Netdev List
 help / color / mirror / Atom feed
* [PATCH 10/12] qlcnic: register dump utility
From: Sony Chacko @ 2012-09-11  1:20 UTC (permalink / raw)
  To: davem; +Cc: netdev, Dept_NX_Linux_NIC_Driver, Sony Chacko
In-Reply-To: <1347326403-1705-1-git-send-email-sony.chacko@qlogic.com>

From: Sony Chacko <sony.chacko@qlogic.com>

Modify 82xx driver to support new adapter - Qlogic 83XX CNA
Common register dump utility for 82xx and 83xx adapters

Signed-off-by: Rajesh Borundia <rajesh.borundia@qlogic.com>
Signed-off-by: Manish chopra <manish.chopra@qlogic.com>
Signed-off-by: Sony Chacko <sony.chacko@qlogic.com>
---
 drivers/net/ethernet/qlogic/qlcnic/Makefile        |    2 +-
 drivers/net/ethernet/qlogic/qlcnic/qlcnic.h        |   63 ++-
 .../net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c  |    7 +
 drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c   |   10 +
 .../net/ethernet/qlogic/qlcnic/qlcnic_minidump.c   |  865 ++++++++++++++++++++
 5 files changed, 938 insertions(+), 9 deletions(-)
 create mode 100644 drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c

diff --git a/drivers/net/ethernet/qlogic/qlcnic/Makefile b/drivers/net/ethernet/qlogic/qlcnic/Makefile
index 8de2dc7..6d60bae 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/Makefile
+++ b/drivers/net/ethernet/qlogic/qlcnic/Makefile
@@ -7,4 +7,4 @@ obj-$(CONFIG_QLCNIC) := qlcnic.o
 qlcnic-y := qlcnic_hw.o qlcnic_main.o qlcnic_init.o \
 	qlcnic_ethtool.o qlcnic_ctx.o qlcnic_io.o \
 	qlcnic_83xx_hw.o qlcnic_83xx_init.o \
-	qlcnic_83xx_vnic.o
+	qlcnic_83xx_vnic.o qlcnic_minidump.o
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
index 5cada0f..de3da22 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
@@ -472,12 +472,14 @@ struct qlcnic_dump_template_hdr {
 	__le32	sys_info[3];
 	__le32	saved_state[16];
 	__le32	cap_sizes[8];
+	__le32  ocm_wnd_reg[16];
 	__le32	rsvd[0];
 };
 
 struct qlcnic_fw_dump {
 	u8	clr;	/* flag to indicate if dump is cleared */
 	u8	enable; /* enable/disable dump */
+	u32     pos;    /* position in the dump buffer */
 	u32	size;	/* total size of the dump */
 	void	*data;	/* dump data area */
 	struct	qlcnic_dump_template_hdr *tmpl_hdr;
@@ -529,7 +531,7 @@ struct qlcnic_hardware_context {
 	u16 max_tx_ques;
 	u16 max_rx_ques;
 	u16 max_mtu;
-	u16 msg_enable;
+	u32 msg_enable;
 	u16 act_pci_func;
 
 	u32 capabilities;
@@ -1408,16 +1410,55 @@ struct __queue {
 	u8	rsvd3[2];
 } __packed;
 
+struct __pollrd {
+	__le32	sel_addr;
+	__le32	read_addr;
+	__le32	sel_val;
+	__le16	sel_val_stride;
+	__le16	no_ops;
+	__le32	poll_wait;
+	__le32	poll_mask;
+	__le32	data_size;
+	u8	rsvd[4];
+} __packed;
+
+struct __mux2 {
+	__le32	sel_addr1;
+	__le32	sel_addr2;
+	__le32	sel_val1;
+	__le32	sel_val2;
+	__le32	no_ops;
+	__le32	sel_val_mask;
+	__le32	read_addr;
+	u8	sel_val_stride;
+	u8	data_size;
+	u8	rsvd[2];
+} __packed;
+
+struct __pollrdmwr {
+	__le32	addr1;
+	__le32	addr2;
+	__le32	val1;
+	__le32	val2;
+	__le32	poll_wait;
+	__le32	poll_mask;
+	__le32	mod_mask;
+	__le32	data_size;
+} __packed;
+
 struct qlcnic_dump_entry {
 	struct qlcnic_common_entry_hdr hdr;
 	union {
-		struct __crb	crb;
-		struct __cache	cache;
-		struct __ocm	ocm;
-		struct __mem	mem;
-		struct __mux	mux;
-		struct __queue	que;
-		struct __ctrl	ctrl;
+		struct __crb		crb;
+		struct __cache		cache;
+		struct __ocm		ocm;
+		struct __mem		mem;
+		struct __mux		mux;
+		struct __queue		que;
+		struct __ctrl		ctrl;
+		struct __pollrdmwr	pollrdmwr;
+		struct __mux2		mux2;
+		struct __pollrd		pollrd;
 	} region;
 } __packed;
 
@@ -1437,6 +1478,9 @@ enum op_codes {
 	QLCNIC_DUMP_L2_ITAG	= 22,
 	QLCNIC_DUMP_L2_DATA	= 23,
 	QLCNIC_DUMP_L2_INST	= 24,
+	QLCNIC_DUMP_POLL_RD	= 35,
+	QLCNIC_READ_MUX2	= 36,
+	QLCNIC_READ_POLLRDMWR	= 37,
 	QLCNIC_DUMP_READ_ROM	= 71,
 	QLCNIC_DUMP_READ_MEM	= 72,
 	QLCNIC_DUMP_READ_CTRL	= 98,
@@ -1480,6 +1524,7 @@ struct qlcnic_cmd_args {
 	struct _cdrp_cmd rsp;
 };
 
+int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter);
 int qlcnic_fw_cmd_set_port(struct qlcnic_adapter *adapter, u32 config);
 int qlcnic_pci_mem_write_2M(struct qlcnic_adapter *, u64 off, u64 data);
 int qlcnic_pci_mem_read_2M(struct qlcnic_adapter *, u64 off, u64 *data);
@@ -1520,6 +1565,7 @@ void qlcnic_pcie_sem_unlock(struct qlcnic_adapter *, int);
 int qlcnic_wol_supported(struct qlcnic_adapter *adapter);
 void qlcnic_prune_lb_filters(struct qlcnic_adapter *adapter);
 void qlcnic_delete_lb_filters(struct qlcnic_adapter *adapter);
+int qlcnic_dump_fw(struct qlcnic_adapter *);
 void qlcnic_get_ocm_win(struct qlcnic_hardware_context *);
 
 /* Functions from qlcnic_init.c */
@@ -1585,6 +1631,7 @@ netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
 int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data);
 int qlcnic_validate_max_rss(struct net_device *netdev, u8, u8);
 
+
 void qlcnic_alloc_lb_filters_mem(struct qlcnic_adapter *adapter);
 
 int qlcnic_poll(struct napi_struct *, int);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
index eadc231..8a18d88 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
@@ -1788,10 +1788,16 @@ qlcnic_83xx_load_fw_image_from_host(struct qlcnic_adapter *adapter)
 
 int qlcnic_83xx_restart_hw(struct qlcnic_adapter *adapter)
 {
+	u32 val;
 	int err = -EIO;
 
 	qlcnic_83xx_stop_hw(adapter);
 
+	/* Collect FW register dump if required */
+	val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
+	if (!(val & QLC_83XX_IDC_GRACEFULL_RESET))
+		qlcnic_dump_fw(adapter);
+
 	qlcnic_83xx_init_hw(adapter);
 	if (qlcnic_83xx_copy_bootloader(adapter))
 		return err;
@@ -1911,6 +1917,7 @@ qlcnic_83xx_init_default_driver(struct qlcnic_adapter *adapter)
 {
 	int err = -EIO;
 
+	qlcnic_83xx_get_minidump_template(adapter);
 	if (qlcnic_83xx_get_port_info(adapter))
 		return err;
 
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index cdebd88..c4f9ff6 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -868,11 +868,15 @@ qlcnic_check_options(struct qlcnic_adapter *adapter)
 		dev_err(&pdev->dev, "Error getting board config info.\n");
 		return;
 	}
+
 	if (ahw->op_mode != QLCNIC_NON_PRIV_FUNC) {
 		if (fw_dump->tmpl_hdr == NULL ||
 				adapter->fw_version > prev_fw_version) {
 			if (fw_dump->tmpl_hdr)
 				vfree(fw_dump->tmpl_hdr);
+			if (!qlcnic_fw_cmd_get_minidump_temp(adapter))
+				dev_info(&pdev->dev,
+					 "Supports FW dump capability\n");
 		}
 	}
 
@@ -2636,6 +2640,12 @@ skip_ack_check:
 
 		qlcnic_api_unlock(adapter);
 
+		rtnl_lock();
+		if (adapter->flags & QLCNIC_FW_RESET_OWNER) {
+			qlcnic_dump_fw(adapter);
+			adapter->flags |= QLCNIC_FW_HANG;
+		}
+		rtnl_unlock();
 
 		adapter->flags &= ~QLCNIC_FW_RESET_OWNER;
 		if (!qlcnic_start_firmware(adapter)) {
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c
new file mode 100644
index 0000000..95689d4
--- /dev/null
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c
@@ -0,0 +1,865 @@
+
+#include "qlcnic.h"
+#include "qlcnic_hdr.h"
+#include "qlcnic_83xx_hw.h"
+#include "qlcnic_hw.h"
+
+#include <net/ip.h>
+
+#define QLC_83XX_MINIDUMP_FLASH			0x520000
+#define QLC_83XX_OCM_INDEX			3
+#define QLC_83XX_PCI_INDEX			0
+
+static const u32 qlcnic_ms_read_data[] = {
+	0x410000A8, 0x410000AC, 0x410000B8, 0x410000BC, };
+
+static u32
+qlcnic_dump_crb(struct qlcnic_adapter *adapter, struct qlcnic_dump_entry *entry,
+		u32 *buffer)
+{
+	int i;
+	u32 addr, data;
+	struct __crb *crb = &entry->region.crb;
+
+	addr = crb->addr;
+
+	for (i = 0; i < crb->no_ops; i++) {
+		data = qlcnic_ind_rd(adapter, addr);
+		*buffer++ = cpu_to_le32(addr);
+		*buffer++ = cpu_to_le32(data);
+		addr += crb->stride;
+	}
+	return crb->no_ops * 2 * sizeof(u32);
+}
+
+static u32
+qlcnic_dump_ctrl(struct qlcnic_adapter *adapter,
+		 struct qlcnic_dump_entry *entry, u32 *buffer)
+{
+	int i, k, timeout = 0;
+	u32 addr, data;
+	u8 opcode, no_ops;
+	struct __ctrl *ctr = &entry->region.ctrl;
+	struct qlcnic_dump_template_hdr *t_hdr = adapter->ahw->fw_dump.tmpl_hdr;
+
+	addr = ctr->addr;
+	no_ops = ctr->no_ops;
+
+	for (i = 0; i < no_ops; i++) {
+		k = 0;
+		opcode = 0;
+		for (k = 0; k < 8; k++) {
+			if (!(ctr->opcode & (1 << k)))
+				continue;
+			switch (1 << k) {
+			case QLCNIC_DUMP_WCRB:
+				qlcnic_ind_wr(adapter, addr, ctr->val1);
+				break;
+			case QLCNIC_DUMP_RWCRB:
+				data = qlcnic_ind_rd(adapter, addr);
+				qlcnic_ind_wr(adapter, addr, data);
+				break;
+			case QLCNIC_DUMP_ANDCRB:
+				data = qlcnic_ind_rd(adapter, addr);
+				qlcnic_ind_wr(adapter, addr,
+					      (data & ctr->val2));
+				break;
+			case QLCNIC_DUMP_ORCRB:
+				data = qlcnic_ind_rd(adapter, addr);
+				qlcnic_ind_wr(adapter, addr,
+					      (data | ctr->val3));
+				break;
+			case QLCNIC_DUMP_POLLCRB:
+				while (timeout <= ctr->timeout) {
+					data = qlcnic_ind_rd(adapter, addr);
+					if ((data & ctr->val2) == ctr->val1)
+						break;
+					usleep_range(1000, 2000);
+					timeout++;
+				}
+				if (timeout > ctr->timeout) {
+					dev_err(&adapter->pdev->dev,
+						"Timeout, aborting poll CRB\n");
+					return 0;
+				}
+				break;
+			case QLCNIC_DUMP_RD_SAVE:
+				if (ctr->index_a)
+					addr = t_hdr->saved_state[ctr->index_a];
+				data = qlcnic_ind_rd(adapter, addr);
+				t_hdr->saved_state[ctr->index_v] = data;
+				break;
+			case QLCNIC_DUMP_WRT_SAVED:
+				if (ctr->index_v)
+					data = t_hdr->saved_state[ctr->index_v];
+				else
+					data = ctr->val1;
+				if (ctr->index_a)
+					addr = t_hdr->saved_state[ctr->index_a];
+				qlcnic_ind_wr(adapter, addr, data);
+				break;
+			case QLCNIC_DUMP_MOD_SAVE_ST:
+				data = t_hdr->saved_state[ctr->index_v];
+				data <<= ctr->shl_val;
+				data >>= ctr->shr_val;
+				if (ctr->val2)
+					data &= ctr->val2;
+				data |= ctr->val3;
+				data += ctr->val1;
+				t_hdr->saved_state[ctr->index_v] = data;
+				break;
+			default:
+				dev_err(&adapter->pdev->dev,
+					"Unknown opcode\n");
+				break;
+			}
+		}
+		addr += ctr->stride;
+	}
+	return 0;
+}
+
+static u32
+qlcnic_dump_mux(struct qlcnic_adapter *adapter, struct qlcnic_dump_entry *entry,
+		u32 *buffer)
+{
+	int loop;
+	u32 val, data = 0;
+	struct __mux *mux = &entry->region.mux;
+
+	val = mux->val;
+	for (loop = 0; loop < mux->no_ops; loop++) {
+		qlcnic_ind_wr(adapter, mux->addr, val);
+		data = qlcnic_ind_rd(adapter, mux->read_addr);
+		*buffer++ = cpu_to_le32(val);
+		*buffer++ = cpu_to_le32(data);
+		val += mux->val_stride;
+	}
+	return 2 * mux->no_ops * sizeof(u32);
+}
+
+static u32
+qlcnic_dump_que(struct qlcnic_adapter *adapter, struct qlcnic_dump_entry *entry,
+		u32 *buffer)
+{
+	int i, loop;
+	u32 cnt, addr, data, que_id = 0;
+	struct __queue *que = &entry->region.que;
+
+	addr = que->read_addr;
+	cnt = que->read_addr_cnt;
+
+	for (loop = 0; loop < que->no_ops; loop++) {
+		qlcnic_ind_wr(adapter, que->sel_addr, que_id);
+		addr = que->read_addr;
+		for (i = 0; i < cnt; i++) {
+			data = qlcnic_ind_rd(adapter, addr);
+			*buffer++ = cpu_to_le32(data);
+			addr += que->read_addr_stride;
+		}
+		que_id += que->stride;
+	}
+	return que->no_ops * cnt * sizeof(u32);
+}
+
+static u32
+qlcnic_dump_ocm(struct qlcnic_adapter *adapter, struct qlcnic_dump_entry *entry,
+		u32 *buffer)
+{
+	int i;
+	u32 data;
+	void __iomem *addr;
+	struct __ocm *ocm = &entry->region.ocm;
+
+	addr = adapter->ahw->pci_base0 + ocm->read_addr;
+	for (i = 0; i < ocm->no_ops; i++) {
+		data = readl(addr);
+		*buffer++ = cpu_to_le32(data);
+		addr += ocm->read_addr_stride;
+	}
+	return ocm->no_ops * sizeof(u32);
+}
+
+static u32
+qlcnic_read_rom(struct qlcnic_adapter *adapter, struct qlcnic_dump_entry *entry,
+		u32 *buffer)
+{
+	int i, count = 0;
+	u32 fl_addr, size, val, lck_val, addr;
+	struct __mem *rom = &entry->region.mem;
+
+	fl_addr = rom->addr;
+	size = rom->size/4;
+lock_try:
+	lck_val = QLCRD(adapter, QLCNIC_FLASH_LOCK);
+	if (!lck_val && count < MAX_CTL_CHECK) {
+		usleep_range(10000, 11000);
+		count++;
+		goto lock_try;
+	}
+	QLCWR(adapter, QLCNIC_FLASH_LOCK_OWNER, adapter->ahw->pci_func);
+	for (i = 0; i < size; i++) {
+		addr = fl_addr & 0xFFFF0000;
+		qlcnic_ind_wr(adapter, FLASH_ROM_WINDOW, addr);
+		addr = LSW(fl_addr) + FLASH_ROM_DATA;
+		val = qlcnic_ind_rd(adapter, addr);
+		fl_addr += 4;
+		*buffer++ = cpu_to_le32(val);
+	}
+	QLCRD(adapter, QLCNIC_FLASH_UNLOCK);
+	return rom->size;
+}
+
+static u32
+qlcnic_dump_l1_cache(struct qlcnic_adapter *adapter,
+		     struct qlcnic_dump_entry *entry, u32 *buffer)
+{
+	int i;
+	u32 cnt, val, data, addr;
+	struct __cache *l1 = &entry->region.cache;
+
+	val = l1->init_tag_val;
+
+	for (i = 0; i < l1->no_ops; i++) {
+		qlcnic_ind_wr(adapter, l1->addr, val);
+		qlcnic_ind_wr(adapter, l1->ctrl_addr, LSW(l1->ctrl_val));
+		addr = l1->read_addr;
+		cnt = l1->read_addr_num;
+		while (cnt) {
+			data = qlcnic_ind_rd(adapter, addr);
+			*buffer++ = cpu_to_le32(data);
+			addr += l1->read_addr_stride;
+			cnt--;
+		}
+		val += l1->stride;
+	}
+	return l1->no_ops * l1->read_addr_num * sizeof(u32);
+}
+
+static u32
+qlcnic_dump_l2_cache(struct qlcnic_adapter *adapter,
+		     struct qlcnic_dump_entry *entry, u32 *buffer)
+{
+	int i;
+	u32 cnt, val, data, addr;
+	u8 poll_mask, poll_to, time_out = 0;
+	struct __cache *l2 = &entry->region.cache;
+
+	val = l2->init_tag_val;
+	poll_mask = LSB(MSW(l2->ctrl_val));
+	poll_to = MSB(MSW(l2->ctrl_val));
+
+	for (i = 0; i < l2->no_ops; i++) {
+		qlcnic_ind_wr(adapter, l2->addr, val);
+		if (LSW(l2->ctrl_val))
+			qlcnic_ind_wr(adapter, l2->ctrl_addr,
+				      LSW(l2->ctrl_val));
+		if (!poll_mask)
+			goto skip_poll;
+		do {
+			data = qlcnic_ind_rd(adapter, l2->ctrl_addr);
+			if (!(data & poll_mask))
+				break;
+			usleep_range(1000, 2000);
+			time_out++;
+		} while (time_out <= poll_to);
+
+		if (time_out > poll_to) {
+			dev_err(&adapter->pdev->dev,
+				"Timeout exceeded in %s, aborting dump\n",
+				__func__);
+			return 0;
+		}
+skip_poll:
+		addr = l2->read_addr;
+		cnt = l2->read_addr_num;
+		while (cnt) {
+			data = qlcnic_ind_rd(adapter, addr);
+			*buffer++ = cpu_to_le32(data);
+			addr += l2->read_addr_stride;
+			cnt--;
+		}
+		val += l2->stride;
+	}
+	return l2->no_ops * l2->read_addr_num * sizeof(u32);
+}
+
+static u32
+qlcnic_read_memory(struct qlcnic_adapter *adapter,
+		   struct qlcnic_dump_entry *entry, u32 *buffer)
+{
+	u32 addr, data, test, ret = 0;
+	int i, reg_read;
+	struct __mem *mem = &entry->region.mem;
+
+	reg_read = mem->size;
+	addr = mem->addr;
+	/* check for data size of multiple of 16 and 16 byte alignment */
+	if ((addr & 0xf) || (reg_read%16)) {
+		dev_err(&adapter->pdev->dev,
+			"Unaligned memory addr:0x%x size:0x%x\n",
+			addr, reg_read);
+		return 0;
+	}
+
+	mutex_lock(&adapter->ahw->mem_lock);
+
+	while (reg_read != 0) {
+		qlcnic_ind_wr(adapter, QLCNIC_MS_ADDR_LO, addr);
+		qlcnic_ind_wr(adapter, QLCNIC_MS_ADDR_HI, 0);
+		qlcnic_ind_wr(adapter, QLCNIC_MS_CTRL, QLC_TA_START_ENABLE);
+
+		for (i = 0; i < MAX_CTL_CHECK; i++) {
+			test = qlcnic_ind_rd(adapter, QLCNIC_MS_CTRL);
+			if (!(test & TA_CTL_BUSY))
+				break;
+		}
+		if (i == MAX_CTL_CHECK) {
+			printk_ratelimited(KERN_WARNING
+					   "failed to read through agent\n");
+			ret = 0;
+			goto out;
+		}
+		for (i = 0; i < 4; i++) {
+			data = qlcnic_ind_rd(adapter, qlcnic_ms_read_data[i]);
+			*buffer++ = cpu_to_le32(data);
+		}
+		addr += 16;
+		reg_read -= 16;
+		ret += 16;
+	}
+out:
+	mutex_unlock(&adapter->ahw->mem_lock);
+	return mem->size;
+}
+
+static u32
+qlcnic_dump_nop(struct qlcnic_adapter *adapter,
+		struct qlcnic_dump_entry *entry, u32 *buffer)
+{
+	entry->hdr.flags |= QLCNIC_DUMP_SKIP;
+	return 0;
+}
+
+static int
+qlcnic_valid_dump_entry(struct device *dev, struct qlcnic_dump_entry *entry,
+			u32 size)
+{
+	int ret = 1;
+	if (size != entry->hdr.cap_size) {
+		dev_err(dev,
+		"Invalid entry, Type:%d\tMask:%d\tSize:%dCap_size:%d\n",
+		entry->hdr.type, entry->hdr.mask, size, entry->hdr.cap_size);
+		ret = 0;
+	}
+	return ret;
+}
+
+static u32
+qlcnic_read_pollrdmwr(struct qlcnic_adapter *adapter,
+		      struct qlcnic_dump_entry *entry, u32 *buffer)
+{
+	struct __pollrdmwr *poll = &entry->region.pollrdmwr;
+	u32 data, wait_count, poll_wait, temp;
+
+	poll_wait = poll->poll_wait;
+
+	qlcnic_ind_wr(adapter, poll->addr1, poll->val1);
+	wait_count = 0;
+
+	while (wait_count < poll_wait) {
+		data = qlcnic_ind_rd(adapter, poll->addr1);
+		if ((data & poll->poll_mask) != 0)
+			break;
+		wait_count++;
+	}
+
+	if (wait_count == poll_wait) {
+		dev_err(&adapter->pdev->dev,
+			"Timeout exceeded in %s, aborting dump\n",
+			__func__);
+		return 0;
+	}
+
+	data = qlcnic_ind_rd(adapter, poll->addr2) & poll->mod_mask;
+	qlcnic_ind_wr(adapter, poll->addr2, data);
+	qlcnic_ind_wr(adapter, poll->addr1, poll->val2);
+	wait_count = 0;
+
+	while (wait_count < poll_wait) {
+		temp = qlcnic_ind_rd(adapter, poll->addr1);
+		if ((temp & poll->poll_mask) != 0)
+			break;
+		wait_count++;
+	}
+
+	*buffer++ = cpu_to_le32(poll->addr2);
+	*buffer++ = cpu_to_le32(data);
+
+	return 2 * sizeof(u32);
+
+}
+
+static u32
+qlcnic_read_pollrd(struct qlcnic_adapter *adapter,
+		   struct qlcnic_dump_entry *entry, u32 *buffer)
+{
+	struct __pollrd *pollrd = &entry->region.pollrd;
+	u32 data, wait_count, poll_wait, sel_val;
+	int i;
+
+	poll_wait = pollrd->poll_wait;
+	sel_val = pollrd->sel_val;
+
+	for (i = 0; i < pollrd->no_ops; i++)  {
+		qlcnic_ind_wr(adapter, pollrd->sel_addr, sel_val);
+		wait_count = 0;
+		while (wait_count < poll_wait) {
+			data = qlcnic_ind_rd(adapter, pollrd->sel_addr);
+			if ((data & pollrd->poll_mask) != 0)
+				break;
+			wait_count++;
+		}
+
+		if (wait_count == poll_wait) {
+			dev_err(&adapter->pdev->dev,
+				"Timeout exceeded in %s, aborting dump\n",
+				__func__);
+			return 0;
+		}
+
+		data = qlcnic_ind_rd(adapter, pollrd->read_addr);
+		*buffer++ = cpu_to_le32(sel_val);
+		*buffer++ = cpu_to_le32(data);
+		sel_val += pollrd->sel_val_stride;
+	}
+	return pollrd->no_ops * (2 * sizeof(u32));
+}
+
+static u32
+qlcnic_read_mux2(struct qlcnic_adapter *adapter,
+		 struct qlcnic_dump_entry *entry, u32 *buffer)
+{
+	struct __mux2 *mux2 = &entry->region.mux2;
+	u32 data;
+	u32 t_sel_val, sel_val1, sel_val2;
+	int i;
+
+	sel_val1 = mux2->sel_val1;
+	sel_val2 = mux2->sel_val2;
+
+	for (i = 0; i < mux2->no_ops; i++)  {
+		qlcnic_ind_wr(adapter, mux2->sel_addr1, sel_val1);
+		t_sel_val = sel_val1 & mux2->sel_val_mask;
+		qlcnic_ind_wr(adapter, mux2->sel_addr2, t_sel_val);
+		data = qlcnic_ind_rd(adapter, mux2->read_addr);
+		*buffer++ = cpu_to_le32(t_sel_val);
+		*buffer++ = cpu_to_le32(data);
+		qlcnic_ind_wr(adapter, mux2->sel_addr1, sel_val2);
+		t_sel_val = sel_val2 & mux2->sel_val_mask;
+		qlcnic_ind_wr(adapter, mux2->sel_addr2, t_sel_val);
+		data = qlcnic_ind_rd(adapter, mux2->read_addr);
+		*buffer++ = cpu_to_le32(t_sel_val);
+		*buffer++ = cpu_to_le32(data);
+		sel_val1 += mux2->sel_val_stride;
+		sel_val2 += mux2->sel_val_stride;
+	}
+
+	return mux2->no_ops * (4 * sizeof(u32));
+}
+
+static u32
+qlcnic_83xx_dump_rom(struct qlcnic_adapter *adapter,
+		     struct qlcnic_dump_entry *entry, u32 *buffer)
+{
+	u32 fl_addr, size;
+	struct __mem *rom = &entry->region.mem;
+
+	fl_addr = rom->addr;
+	size = rom->size/4;
+
+	if (!qlcnic_83xx_lockless_flash_read32(adapter, fl_addr,
+					       (u8 *)buffer, size))
+		return rom->size;
+
+	return 0;
+}
+
+static const struct qlcnic_dump_operations qlcnic_fw_dump_ops[] = {
+	{ QLCNIC_DUMP_NOP, qlcnic_dump_nop },
+	{ QLCNIC_DUMP_READ_CRB, qlcnic_dump_crb },
+	{ QLCNIC_DUMP_READ_MUX, qlcnic_dump_mux },
+	{ QLCNIC_DUMP_QUEUE, qlcnic_dump_que },
+	{ QLCNIC_DUMP_BRD_CONFIG, qlcnic_read_rom },
+	{ QLCNIC_DUMP_READ_OCM, qlcnic_dump_ocm },
+	{ QLCNIC_DUMP_PEG_REG, qlcnic_dump_ctrl },
+	{ QLCNIC_DUMP_L1_DTAG, qlcnic_dump_l1_cache },
+	{ QLCNIC_DUMP_L1_ITAG, qlcnic_dump_l1_cache },
+	{ QLCNIC_DUMP_L1_DATA, qlcnic_dump_l1_cache },
+	{ QLCNIC_DUMP_L1_INST, qlcnic_dump_l1_cache },
+	{ QLCNIC_DUMP_L2_DTAG, qlcnic_dump_l2_cache },
+	{ QLCNIC_DUMP_L2_ITAG, qlcnic_dump_l2_cache },
+	{ QLCNIC_DUMP_L2_DATA, qlcnic_dump_l2_cache },
+	{ QLCNIC_DUMP_L2_INST, qlcnic_dump_l2_cache },
+	{ QLCNIC_DUMP_READ_ROM, qlcnic_read_rom },
+	{ QLCNIC_DUMP_READ_MEM, qlcnic_read_memory },
+	{ QLCNIC_DUMP_READ_CTRL, qlcnic_dump_ctrl },
+	{ QLCNIC_DUMP_TLHDR, qlcnic_dump_nop },
+	{ QLCNIC_DUMP_RDEND, qlcnic_dump_nop },
+};
+
+static const struct qlcnic_dump_operations qlcnic_83xx_fw_dump_ops[] = {
+	{ QLCNIC_DUMP_NOP, qlcnic_dump_nop },
+	{ QLCNIC_DUMP_READ_CRB, qlcnic_dump_crb },
+	{ QLCNIC_DUMP_READ_MUX, qlcnic_dump_mux },
+	{ QLCNIC_DUMP_QUEUE, qlcnic_dump_que },
+	{ QLCNIC_DUMP_BRD_CONFIG, qlcnic_83xx_dump_rom },
+	{ QLCNIC_DUMP_READ_OCM, qlcnic_dump_ocm },
+	{ QLCNIC_DUMP_PEG_REG, qlcnic_dump_ctrl },
+	{ QLCNIC_DUMP_L1_DTAG, qlcnic_dump_l1_cache },
+	{ QLCNIC_DUMP_L1_ITAG, qlcnic_dump_l1_cache },
+	{ QLCNIC_DUMP_L1_DATA, qlcnic_dump_l1_cache },
+	{ QLCNIC_DUMP_L1_INST, qlcnic_dump_l1_cache },
+	{ QLCNIC_DUMP_L2_DTAG, qlcnic_dump_l2_cache },
+	{ QLCNIC_DUMP_L2_ITAG, qlcnic_dump_l2_cache },
+	{ QLCNIC_DUMP_L2_DATA, qlcnic_dump_l2_cache },
+	{ QLCNIC_DUMP_L2_INST, qlcnic_dump_l2_cache },
+	{ QLCNIC_DUMP_POLL_RD, qlcnic_read_pollrd },
+	{ QLCNIC_READ_MUX2, qlcnic_read_mux2 },
+	{ QLCNIC_READ_POLLRDMWR, qlcnic_read_pollrdmwr },
+	{ QLCNIC_DUMP_READ_ROM, qlcnic_83xx_dump_rom },
+	{ QLCNIC_DUMP_READ_MEM, qlcnic_read_memory },
+	{ QLCNIC_DUMP_READ_CTRL, qlcnic_dump_ctrl },
+	{ QLCNIC_DUMP_TLHDR, qlcnic_dump_nop },
+	{ QLCNIC_DUMP_RDEND, qlcnic_dump_nop },
+};
+
+static uint32_t qlcnic_temp_checksum(uint32_t *temp_buffer, u32 temp_size)
+{
+	uint64_t sum = 0;
+	int count = temp_size / sizeof(uint32_t);
+	while (count-- > 0)
+		sum += *temp_buffer++;
+	while (sum >> 32)
+		sum = (sum & 0xFFFFFFFF) + (sum >> 32);
+	return ~sum;
+}
+
+static int
+qlcnic_fw_flash_get_minidump_temp(struct qlcnic_adapter *adapter,
+				  u8 *buffer, u32 size)
+{
+	int ret = 0;
+
+	if (QLCNIC_IS_82XX(adapter))
+		return -EIO;
+
+	if (qlcnic_83xx_lock_flash(adapter))
+		return -EIO;
+
+	ret = qlcnic_83xx_lockless_flash_read32(adapter,
+						QLC_83XX_MINIDUMP_FLASH,
+						buffer, size/sizeof(u32));
+
+	qlcnic_83xx_unlock_flash(adapter);
+
+	return ret;
+}
+
+static int
+qlcnic_fw_flash_get_minidump_temp_size(struct qlcnic_adapter *adapter,
+				       struct qlcnic_cmd_args *cmd)
+{
+	struct qlcnic_dump_template_hdr tmp_hdr;
+	u32 size = sizeof(struct qlcnic_dump_template_hdr) / sizeof(u32);
+	int ret = 0;
+
+	if (QLCNIC_IS_82XX(adapter))
+		return -EIO;
+
+	if (qlcnic_83xx_lock_flash(adapter))
+		return -EIO;
+
+	ret = qlcnic_83xx_lockless_flash_read32(adapter,
+						QLC_83XX_MINIDUMP_FLASH,
+						(u8 *)&tmp_hdr, size);
+
+	qlcnic_83xx_unlock_flash(adapter);
+
+	cmd->rsp.arg[2] = tmp_hdr.size;
+	cmd->rsp.arg[3] = tmp_hdr.version;
+
+	return ret;
+}
+
+static int
+qlcnic_fw_get_minidump_temp_size(struct qlcnic_adapter *adapter,
+				 u32 *version, u32 *temp_size,
+				 u8 *use_flash_temp)
+{
+	int err = 0;
+	struct qlcnic_cmd_args cmd;
+	struct qlcnic_hardware_context *ahw;
+
+	ahw = adapter->ahw;
+	if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_TEMP_SIZE))
+		return -ENOMEM;
+
+	err = qlcnic_issue_cmd(adapter, &cmd);
+	if (err != QLCNIC_RCODE_SUCCESS) {
+		if (qlcnic_fw_flash_get_minidump_temp_size(adapter, &cmd)) {
+			qlcnic_free_mbx_args(&cmd);
+			return -EIO;
+		}
+		*use_flash_temp = 1;
+	}
+
+	*temp_size = cmd.rsp.arg[2];
+	*version = cmd.rsp.arg[3];
+	qlcnic_free_mbx_args(&cmd);
+
+	if (!(*temp_size))
+		return -EIO;
+
+	return 0;
+}
+
+static
+int __qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter,
+				      u32 *buffer, u32 temp_size)
+{
+	int err = 0, i;
+	void *tmp_addr;
+	u32 *tmp_buf;
+	struct qlcnic_cmd_args cmd;
+	dma_addr_t tmp_addr_t = 0;
+
+	tmp_addr = dma_alloc_coherent(&adapter->pdev->dev, temp_size,
+				      &tmp_addr_t, GFP_KERNEL);
+	if (!tmp_addr) {
+		dev_err(&adapter->pdev->dev,
+			"Can't get memory for FW dump template\n");
+		return -ENOMEM;
+	}
+
+	if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_TEMP_HDR)) {
+		err = -ENOMEM;
+		goto free_mem;
+	}
+
+	cmd.req.arg[1] = LSD(tmp_addr_t);
+	cmd.req.arg[2] = MSD(tmp_addr_t);
+	cmd.req.arg[3] = temp_size;
+	err = qlcnic_issue_cmd(adapter, &cmd);
+
+	tmp_buf = tmp_addr;
+	if (err == QLCNIC_RCODE_SUCCESS) {
+		for (i = 0; i < temp_size/sizeof(u32); i++)
+			*buffer++ = __le32_to_cpu(*tmp_buf++);
+	}
+
+	qlcnic_free_mbx_args(&cmd);
+
+free_mem:
+	dma_free_coherent(&adapter->pdev->dev, temp_size, tmp_addr, tmp_addr_t);
+
+	return err;
+}
+
+int
+qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter)
+{
+	int err;
+	u32 temp_size = 0;
+	u32 version, csum, *tmp_buf;
+	struct qlcnic_hardware_context *ahw;
+	struct qlcnic_dump_template_hdr *tmpl_hdr;
+	u8 use_flash_temp = 0;
+
+	ahw = adapter->ahw;
+
+	err = qlcnic_fw_get_minidump_temp_size(adapter, &version,
+					       &temp_size,
+					       &use_flash_temp);
+
+	if (err) {
+		dev_err(&adapter->pdev->dev,
+			"Can't get template size %d\n", err);
+		return -EIO;
+	}
+
+	ahw->fw_dump.tmpl_hdr = vmalloc(temp_size);
+
+	if (!ahw->fw_dump.tmpl_hdr)
+		return -ENOMEM;
+
+	memset(ahw->fw_dump.tmpl_hdr, 0, temp_size);
+	tmp_buf = (u32 *)ahw->fw_dump.tmpl_hdr;
+
+	if (use_flash_temp)
+		goto flash_temp;
+
+	err = __qlcnic_fw_cmd_get_minidump_temp(adapter, tmp_buf, temp_size);
+
+	if (err) {
+flash_temp:
+		err = qlcnic_fw_flash_get_minidump_temp(adapter, (u8 *)tmp_buf,
+							temp_size);
+
+		if (err) {
+			dev_err(&adapter->pdev->dev,
+				"Failed to get minidump template header %d\n",
+				err);
+			vfree(ahw->fw_dump.tmpl_hdr);
+			ahw->fw_dump.tmpl_hdr = NULL;
+			return -EIO;
+		}
+	}
+
+	csum = qlcnic_temp_checksum((uint32_t *) tmp_buf, temp_size);
+
+	if (csum) {
+		dev_err(&adapter->pdev->dev,
+			"Template header checksum validation failed\n");
+		vfree(ahw->fw_dump.tmpl_hdr);
+		ahw->fw_dump.tmpl_hdr = NULL;
+		return -EIO;
+	}
+
+	tmpl_hdr = ahw->fw_dump.tmpl_hdr;
+	tmpl_hdr->drv_cap_mask = QLCNIC_DUMP_MASK_DEF;
+	ahw->fw_dump.enable = 1;
+
+	return 0;
+}
+
+int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
+{
+	u32 *buffer;
+	char mesg[64];
+	char *msg[] = {mesg, NULL};
+	int i, k, ops_cnt, ops_index, dump_size = 0;
+	u32 entry_offset, dump, no_entries, buf_offset = 0;
+	struct qlcnic_dump_entry *entry;
+	struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
+	struct qlcnic_dump_template_hdr *tmpl_hdr = fw_dump->tmpl_hdr;
+	static const struct qlcnic_dump_operations *fw_dump_ops;
+
+	if (!fw_dump->enable) {
+		dev_info(&adapter->pdev->dev,
+			 "Dump not enabled\n");
+		return -EIO;
+	}
+
+	if (fw_dump->clr) {
+		dev_info(&adapter->pdev->dev,
+			 "Previous dump not cleared, not capturing dump\n");
+		return -EIO;
+	}
+
+	netif_info(adapter->ahw, drv, adapter->netdev,
+		   "Take FW dump\n");
+	/* Calculate the size for dump data area only */
+	for (i = 2, k = 1; (i & QLCNIC_DUMP_MASK_MAX); i <<= 1, k++)
+		if (i & tmpl_hdr->drv_cap_mask)
+			dump_size += tmpl_hdr->cap_sizes[k];
+	if (!dump_size)
+		return -EIO;
+
+	fw_dump->data = vmalloc(dump_size);
+	if (!fw_dump->data) {
+		dev_err(&adapter->pdev->dev,
+			"Unable to allocate (%d KB) for fw dump\n",
+			dump_size/1024);
+		return -ENOMEM;
+	}
+	memset(fw_dump->data, 0, dump_size);
+	buffer = fw_dump->data;
+	fw_dump->size = dump_size;
+	no_entries = tmpl_hdr->num_entries;
+	entry_offset = tmpl_hdr->offset;
+	tmpl_hdr->sys_info[0] = QLCNIC_DRIVER_VERSION;
+	tmpl_hdr->sys_info[1] = adapter->fw_version;
+
+	if (QLCNIC_IS_82XX(adapter)) {
+		ops_cnt = ARRAY_SIZE(qlcnic_fw_dump_ops);
+		fw_dump_ops = qlcnic_fw_dump_ops;
+	} else {
+		ops_cnt = ARRAY_SIZE(qlcnic_83xx_fw_dump_ops);
+		fw_dump_ops = qlcnic_83xx_fw_dump_ops;
+		tmpl_hdr->saved_state[QLC_83XX_OCM_INDEX] =
+			tmpl_hdr->ocm_wnd_reg[adapter->ahw->pci_func];
+		tmpl_hdr->saved_state[QLC_83XX_PCI_INDEX] =
+				      adapter->ahw->pci_func;
+	}
+
+	for (i = 0; i < no_entries; i++) {
+		entry = (void *)tmpl_hdr + entry_offset;
+		if (!(entry->hdr.mask & tmpl_hdr->drv_cap_mask)) {
+			entry->hdr.flags |= QLCNIC_DUMP_SKIP;
+			entry_offset += entry->hdr.offset;
+			continue;
+		}
+
+		/* Find the handler for this entry */
+		ops_index = 0;
+		while (ops_index < ops_cnt) {
+			if (entry->hdr.type == fw_dump_ops[ops_index].opcode)
+				break;
+			ops_index++;
+		}
+
+		if (ops_index == ops_cnt) {
+			dev_err(&adapter->pdev->dev,
+				"Invalid entry type %d, exiting dump\n",
+				entry->hdr.type);
+			goto error;
+		}
+
+		/* Collect dump for this entry */
+		dump = fw_dump_ops[ops_index].handler(adapter, entry, buffer);
+		if (!qlcnic_valid_dump_entry(&adapter->pdev->dev, entry, dump))
+			entry->hdr.flags |= QLCNIC_DUMP_SKIP;
+		buf_offset += entry->hdr.cap_size;
+		entry_offset += entry->hdr.offset;
+		buffer = fw_dump->data + buf_offset;
+	}
+	if (dump_size != buf_offset) {
+		dev_err(&adapter->pdev->dev,
+			"Captured(%d) and expected size(%d) do not match\n",
+			buf_offset, dump_size);
+		goto error;
+	} else {
+		fw_dump->clr = 1;
+		snprintf(mesg, sizeof(mesg), "FW_DUMP=%s",
+			adapter->netdev->name);
+		dev_info(&adapter->pdev->dev, "%s: Dump data, %d bytes captured\n",
+			 adapter->netdev->name, fw_dump->size);
+		/* Send a udev event to notify availability of FW dump */
+		kobject_uevent_env(&adapter->pdev->dev.kobj, KOBJ_CHANGE, msg);
+		return 0;
+	}
+error:
+	vfree(fw_dump->data);
+	return -EINVAL;
+}
+
+void
+qlcnic_83xx_get_minidump_template(struct qlcnic_adapter *adapter)
+{
+	u32 prev_version, current_version;
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+	struct qlcnic_fw_dump *fw_dump = &ahw->fw_dump;
+	struct pci_dev *pdev = adapter->pdev;
+
+	prev_version = adapter->fw_version;
+	current_version = qlcnic_83xx_get_fw_version(adapter);
+
+	if (fw_dump->tmpl_hdr == NULL || current_version > prev_version) {
+		if (fw_dump->tmpl_hdr)
+			vfree(fw_dump->tmpl_hdr);
+		if (!qlcnic_fw_cmd_get_minidump_temp(adapter))
+			dev_info(&pdev->dev,
+				 "Supports FW dump capability\n");
+	}
+}
-- 
1.7.1

^ permalink raw reply related

* [PATCH 09/12] qlcnic: enable 83xx virtual NIC mode
From: Sony Chacko @ 2012-09-11  1:20 UTC (permalink / raw)
  To: davem; +Cc: netdev, Dept_NX_Linux_NIC_Driver, Sony Chacko
In-Reply-To: <1347326403-1705-1-git-send-email-sony.chacko@qlogic.com>

From: Sony Chacko <sony.chacko@qlogic.com>

Enable 83xx virtual NIC mode

Signed-off-by: Rajesh Borundia <rajesh.borundia@qlogic.com>
Signed-off-by: Sony Chacko <sony.chacko@qlogic.com>
---
 drivers/net/ethernet/qlogic/qlcnic/Makefile        |    3 +-
 drivers/net/ethernet/qlogic/qlcnic/qlcnic.h        |   11 +-
 .../net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c  |    3 +
 .../net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c  |  261 ++++++++++++++++++++
 4 files changed, 270 insertions(+), 8 deletions(-)
 create mode 100644 drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c

diff --git a/drivers/net/ethernet/qlogic/qlcnic/Makefile b/drivers/net/ethernet/qlogic/qlcnic/Makefile
index 47ae1f8..8de2dc7 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/Makefile
+++ b/drivers/net/ethernet/qlogic/qlcnic/Makefile
@@ -6,4 +6,5 @@ obj-$(CONFIG_QLCNIC) := qlcnic.o
 
 qlcnic-y := qlcnic_hw.o qlcnic_main.o qlcnic_init.o \
 	qlcnic_ethtool.o qlcnic_ctx.o qlcnic_io.o \
-	qlcnic_83xx_hw.o qlcnic_83xx_init.o
+	qlcnic_83xx_hw.o qlcnic_83xx_init.o \
+	qlcnic_83xx_vnic.o
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
index c82042b..5cada0f 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
@@ -400,6 +400,7 @@ extern int qlcnic_use_msi;
 extern int qlcnic_use_msi_x;
 extern int qlcnic_auto_fw_reset;
 extern int qlcnic_load_fw_file;
+extern int qlcnic_config_npars;
 
 /* Number of status descriptors to handle per interrupt */
 #define MAX_STATUS_HANDLE	(64)
@@ -1625,13 +1626,9 @@ int qlcnic_process_cmd_ring(struct qlcnic_adapter *,
 			    struct qlcnic_host_tx_ring *, int);
 void qlcnic_advert_link_change(struct qlcnic_adapter *, int);
 void dump_skb(struct sk_buff *, struct qlcnic_adapter *);
-
-
-extern int qlcnic_config_tso;
-
-/*
- * QLOGIC Board information
- */
+int qlcnic_init_pci_info(struct qlcnic_adapter *);
+int qlcnic_set_default_offload_settings(struct qlcnic_adapter *);
+int qlcnic_reset_npar_config(struct qlcnic_adapter *);
 
 #define QLCNIC_MAX_BOARD_NAME_LEN 100
 struct qlcnic_brdinfo {
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
index bc3ee78..eadc231 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
@@ -822,6 +822,8 @@ qlcnic_83xx_idc_need_reset_state_handler(struct qlcnic_adapter *adapter)
 		qlcnic_83xx_idc_update_audit_reg(adapter, 0, 1);
 		set_bit(__QLCNIC_RESETTING, &adapter->state);
 		clear_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status);
+		if (adapter->ahw->nic_mode == QLC_83XX_VIRTUAL_NIC_MODE)
+			qlcnic_83xx_disable_vnic_mode(adapter, 1);
 
 		qlcnic_83xx_idc_detach_driver(adapter);
 	}
@@ -1873,6 +1875,7 @@ qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter)
 		return -EIO;
 
 	if (ret == QLC_83XX_VIRTUAL_NIC_MODE) {
+		if (qlcnic_83xx_config_vnic_opmode(adapter))
 			return -EIO;
 	} else if (ret == QLC_83XX_DEFAULT_MODE) {
 		if (qlcnic_83xx_config_default_opmode(adapter))
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c
new file mode 100644
index 0000000..5965a54
--- /dev/null
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c
@@ -0,0 +1,261 @@
+#include "qlcnic.h"
+#include "qlcnic_hw.h"
+
+int
+qlcnic_83xx_enable_vnic_mode(struct qlcnic_adapter *adapter, int lock)
+{
+	if (lock) {
+		if (qlcnic_83xx_lock_driver(adapter))
+			return -EBUSY;
+	}
+	QLCWRX(adapter->ahw, QLC_83XX_VNIC_STATE, QLCNIC_DEV_NPAR_OPER);
+	if (lock)
+		qlcnic_83xx_unlock_driver(adapter);
+
+	return 0;
+}
+
+int
+qlcnic_83xx_disable_vnic_mode(struct qlcnic_adapter *adapter, int lock)
+{
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+	if (lock) {
+		if (qlcnic_83xx_lock_driver(adapter))
+			return -EBUSY;
+	}
+
+	QLCWRX(adapter->ahw, QLC_83XX_VNIC_STATE, QLCNIC_DEV_NPAR_NON_OPER);
+	ahw->idc.vnic_state = QLCNIC_DEV_NPAR_NON_OPER;
+
+	if (lock)
+		qlcnic_83xx_unlock_driver(adapter);
+
+	return 0;
+}
+
+/**
+ * qlcnic_83xx_set_vnic_opmode
+ *
+ * @adapter: adapter structure
+ *
+ * Returns:
+ *
+ **/
+static int
+qlcnic_83xx_set_vnic_opmode(struct qlcnic_adapter *adapter)
+{
+	u8 id;
+	int i, ret = -EBUSY;
+	u32 data = QLCNIC_MGMT_FUNC;
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+	if (qlcnic_83xx_lock_driver(adapter))
+		return ret;
+
+	if (qlcnic_config_npars) {
+		for (i = 0; i < ahw->act_pci_func; i++) {
+			id = adapter->npars[i].pci_func;
+			if (id == ahw->pci_func)
+				continue;
+			data |= (qlcnic_config_npars &
+					QLC_83XX_SET_FUNC_OPMODE(0x3, id));
+		}
+	} else {
+		data = QLCRDX(adapter->ahw, QLC_83XX_DRV_OP_MODE);
+		data = (data & ~QLC_83XX_SET_FUNC_OPMODE(0x3, ahw->pci_func)) |
+			(QLC_83XX_SET_FUNC_OPMODE(QLCNIC_MGMT_FUNC,
+			ahw->pci_func));
+	}
+	QLCWRX(adapter->ahw, QLC_83XX_DRV_OP_MODE, data);
+
+	qlcnic_83xx_unlock_driver(adapter);
+
+	return 0;
+}
+
+/**
+ * qlcnic_83xx_config_vnic_buff_descriptors
+ *
+ * @adapter: adapter structure
+ *
+ * Returns:
+ *
+ **/
+static inline void
+qlcnic_83xx_config_vnic_buff_descriptors(struct qlcnic_adapter *adapter)
+{
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+	if (ahw->port_type == QLCNIC_XGBE) {
+		adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_VF;
+		adapter->max_rxd = MAX_RCV_DESCRIPTORS_VF;
+		adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G;
+		adapter->max_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G;
+
+	} else if (ahw->port_type == QLCNIC_GBE) {
+		adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_1G;
+		adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G;
+		adapter->max_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G;
+		adapter->max_rxd = MAX_RCV_DESCRIPTORS_1G;
+	}
+	adapter->num_txd = MAX_CMD_DESCRIPTORS;
+	adapter->max_rds_rings = MAX_RDS_RINGS;
+}
+
+
+/**
+ * qlcnic_83xx_init_mgmt_vnic
+ *
+ * @adapter: adapter structure
+ * Management vNIC sets the operational mode of other vNIC's and
+ * configures embedded switch (ESWITCH).
+ * Returns:
+ *
+ **/
+static int
+qlcnic_83xx_init_mgmt_vnic(struct qlcnic_adapter *adapter)
+{
+	int err = -EIO;
+
+	if (!(adapter->flags & QLCNIC_ADAPTER_INITIALIZED)) {
+		if (qlcnic_init_pci_info(adapter))
+			return err;
+
+		if (qlcnic_83xx_set_vnic_opmode(adapter))
+			return err;
+
+		if (qlcnic_set_default_offload_settings(adapter))
+			return err;
+	} else {
+		if (qlcnic_reset_npar_config(adapter))
+			return err;
+	}
+
+	if (qlcnic_83xx_get_port_info(adapter))
+		return err;
+
+	qlcnic_83xx_config_vnic_buff_descriptors(adapter);
+	adapter->ahw->msix_supported = !!qlcnic_use_msi_x;
+	adapter->flags |= QLCNIC_ADAPTER_INITIALIZED;
+	qlcnic_83xx_enable_vnic_mode(adapter, 1);
+
+	dev_info(&adapter->pdev->dev, "HAL Version: %d, Management function\n",
+		 adapter->ahw->fw_hal_version);
+
+	return 0;
+}
+
+/**
+ * qlcnic_83xx_init_privileged_vnic
+ *
+ * @adapter: adapter structure
+ *
+ * Returns:
+ *
+ **/
+static int
+qlcnic_83xx_init_privileged_vnic(struct qlcnic_adapter *adapter)
+{
+	int err = -EIO;
+
+	if (qlcnic_83xx_get_port_info(adapter))
+		return err;
+
+	qlcnic_83xx_config_vnic_buff_descriptors(adapter);
+	adapter->ahw->msix_supported = !!qlcnic_use_msi_x;
+	adapter->flags |= QLCNIC_ADAPTER_INITIALIZED;
+
+	dev_info(&adapter->pdev->dev,
+		 "HAL Version: %d, Privileged function\n",
+		 adapter->ahw->fw_hal_version);
+	return 0;
+}
+
+/**
+ * qlcnic_83xx_init_non_privileged_vnic
+ *
+ * @adapter: adapter structure
+ *
+ * Returns:
+ *
+ **/
+static int
+qlcnic_83xx_init_non_privileged_vnic(struct qlcnic_adapter *adapter)
+{
+	int err = -EIO;
+
+	qlcnic_83xx_get_fw_version(adapter);
+	if (qlcnic_set_eswitch_port_config(adapter))
+		return err;
+
+	if (qlcnic_83xx_get_port_info(adapter))
+		return err;
+
+	qlcnic_83xx_config_vnic_buff_descriptors(adapter);
+	adapter->ahw->msix_supported = !!qlcnic_use_msi_x;
+	adapter->flags |= QLCNIC_ADAPTER_INITIALIZED;
+
+	dev_info(&adapter->pdev->dev, "HAL Version: %d, Virtual function\n",
+		 adapter->ahw->fw_hal_version);
+
+	return 0;
+}
+
+/**
+ * qlcnic_83xx_vnic_opmode
+ *
+ * @adapter: adapter structure
+ * Identify virtual NIC operational modes.
+ *
+ * Returns:
+ *
+ **/
+int
+qlcnic_83xx_config_vnic_opmode(struct qlcnic_adapter *adapter)
+{
+	u32 op_mode, priv_level;
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+	qlcnic_get_func_no(adapter);
+
+	op_mode = QLCRDX(adapter->ahw, QLC_83XX_DRV_OP_MODE);
+
+	if (op_mode == QLC_83XX_DEFAULT_OPMODE)
+		priv_level = QLCNIC_MGMT_FUNC;
+	else
+		priv_level = QLC_83XX_GET_FUNC_PRIVILEGE_LEVEL(op_mode,
+							       ahw->pci_func);
+
+	if (priv_level == QLCNIC_NON_PRIV_FUNC) {
+		ahw->op_mode = QLCNIC_NON_PRIV_FUNC;
+		adapter->ahw->idc.ready_state_entry_action =
+			qlcnic_83xx_idc_ready_state_entry_action;
+		adapter->nic_ops->init_driver =
+				qlcnic_83xx_init_non_privileged_vnic;
+	} else if (priv_level == QLCNIC_PRIV_FUNC) {
+		ahw->op_mode = QLCNIC_PRIV_FUNC;
+		adapter->ahw->idc.ready_state_entry_action =
+			qlcnic_83xx_idc_vnic_pf_ready_state_entry_action;
+		adapter->nic_ops->init_driver =
+				qlcnic_83xx_init_privileged_vnic;
+	} else if (priv_level == QLCNIC_MGMT_FUNC) {
+		ahw->op_mode = QLCNIC_MGMT_FUNC;
+		adapter->ahw->idc.ready_state_entry_action =
+			qlcnic_83xx_idc_ready_state_entry_action;
+		adapter->nic_ops->init_driver =
+				qlcnic_83xx_init_mgmt_vnic;
+	} else {
+		return -EIO;
+	}
+
+	if (ahw->capabilities & BIT_23)
+		adapter->flags |= QLCNIC_ESWITCH_ENABLED;
+	else
+		adapter->flags &= ~QLCNIC_ESWITCH_ENABLED;
+
+	adapter->ahw->idc.vnic_state = QLCNIC_DEV_NPAR_NON_OPER;
+	adapter->ahw->idc.vnic_wait_limit = QLCNIC_DEV_NPAR_OPER_TIMEO;
+
+	return 0;
+}
-- 
1.7.1

^ permalink raw reply related

* [PATCH 12/12] qlcnic: update driver version - 5.1.30
From: Sony Chacko @ 2012-09-11  1:20 UTC (permalink / raw)
  To: davem; +Cc: netdev, Dept_NX_Linux_NIC_Driver, Sony Chacko
In-Reply-To: <1347326403-1705-1-git-send-email-sony.chacko@qlogic.com>

From: Sony Chacko <sony.chacko@qlogic.com>

Signed-off-by: Sony Chacko <sony.chacko@qlogic.com>
---
 drivers/net/ethernet/qlogic/qlcnic/qlcnic.h |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
index eef0dc3..f115f21 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
@@ -39,8 +39,8 @@
 
 #define _QLCNIC_LINUX_MAJOR 5
 #define _QLCNIC_LINUX_MINOR 1
-#define _QLCNIC_LINUX_SUBVERSION 29
-#define QLCNIC_LINUX_VERSIONID  "5.1.29"
+#define _QLCNIC_LINUX_SUBVERSION 30
+#define QLCNIC_LINUX_VERSIONID  "5.1.30"
 #define QLCNIC_DRV_IDC_VER  0x01
 #define QLCNIC_DRIVER_VERSION  ((_QLCNIC_LINUX_MAJOR << 16) |\
 		 (_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION))
-- 
1.7.1

^ permalink raw reply related

* [PATCH 11/12] qlcnic: 83xx adpater ethtool
From: Sony Chacko @ 2012-09-11  1:20 UTC (permalink / raw)
  To: davem; +Cc: netdev, Dept_NX_Linux_NIC_Driver, Sony Chacko
In-Reply-To: <1347326403-1705-1-git-send-email-sony.chacko@qlogic.com>

From: Sony Chacko <sony.chacko@qlogic.com>

83xx ethtool interface routines

Signed-off-by: Anirban Chakraborty <anirban.chakraborty@qlogic.com>
Signed-off-by: Sucheta Chakraborty <sucheta.chakraborty@qlogic.com>
Signed-off-by: Jitendra Kalsaria <jitendra.kalsaria@qlogic.com>
Signed-off-by: Rajesh Borundia <rajesh.borundia@qlogic.com>
Signed-off-by: Sritej Velaga <sritej.velaga@qlogic.com>
Signed-off-by: Sony Chacko <sony.chacko@qlogic.com>
---
 drivers/net/ethernet/qlogic/qlcnic/qlcnic.h        |    6 +-
 .../net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c    |  467 +++++++++++++-------
 drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c   |   49 ++-
 3 files changed, 348 insertions(+), 174 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
index de3da22..eef0dc3 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
@@ -1006,6 +1006,7 @@ struct qlcnic_ipaddr {
 #define __QLCNIC_AER			5
 #define __QLCNIC_DIAG_RES_ALLOC		6
 #define __QLCNIC_LED_ENABLE		7
+#define __QLCNIC_ELB_INPROGRESS         8
 
 #define QLCNIC_INTERRUPT_TEST		1
 #define QLCNIC_LOOPBACK_TEST		2
@@ -1628,9 +1629,8 @@ int qlcnic_reset_context(struct qlcnic_adapter *);
 void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings);
 int qlcnic_diag_alloc_res(struct net_device *netdev, int test);
 netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
-int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data);
-int qlcnic_validate_max_rss(struct net_device *netdev, u8, u8);
-
+int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data, size_t);
+int qlcnic_validate_max_rss(u8, u8);
 
 void qlcnic_alloc_lb_filters_mem(struct qlcnic_adapter *adapter);
 
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
index 6042395..9f83fbd 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
@@ -23,6 +23,10 @@ struct qlcnic_stats {
 #define QLC_SIZEOF(m) FIELD_SIZEOF(struct qlcnic_adapter, m)
 #define QLC_OFF(m) offsetof(struct qlcnic_adapter, m)
 
+
+static const u32 qlcnic_fw_dump_level[] = {
+	0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff};
+
 static const struct qlcnic_stats qlcnic_gstrings_stats[] = {
 	{"xmit_called",
 		QLC_SIZEOF(stats.xmitcalled), QLC_OFF(stats.xmitcalled)},
@@ -78,7 +82,15 @@ static const char qlcnic_device_gstrings_stats[][ETH_GSTRING_LEN] = {
 	"tx numbytes",
 };
 
-static const char qlcnic_mac_stats_strings [][ETH_GSTRING_LEN] = {
+static const char qlcnic_83xx_tx_stats_strings[][ETH_GSTRING_LEN] = {
+	"ctx_tx_bytes",
+	"ctx_tx_pkts",
+	"ctx_tx_errors",
+	"ctx_tx_dropped_pkts",
+	"ctx_tx_num_buffers",
+};
+
+static const char qlcnic_83xx_mac_stats_strings[][ETH_GSTRING_LEN] = {
 	"mac_tx_frames",
 	"mac_tx_bytes",
 	"mac_tx_mcast_pkts",
@@ -110,21 +122,51 @@ static const char qlcnic_mac_stats_strings [][ETH_GSTRING_LEN] = {
 	"mac_rx_length_large",
 	"mac_rx_jabber",
 	"mac_rx_dropped",
-	"mac_rx_crc_error",
+	"mac_crc_error",
 	"mac_align_error",
 };
 
+static const char qlcnic_83xx_rx_stats_strings[][ETH_GSTRING_LEN] = {
+	"ctx_rx_bytes",
+	"ctx_rx_pkts",
+	"ctx_lro_pkt_cnt",
+	"ctx_ip_csum_error",
+	"ctx_rx_pkts_wo_ctx",
+	"ctx_rx_pkts_dropped_wo_sts",
+	"ctx_rx_osized_pkts",
+	"ctx_rx_pkts_dropped_wo_rds",
+	"ctx_rx_unexpected_mcast_pkts",
+	"ctx_invalid_mac_address",
+	"ctx_rx_rds_ring_prim_attemoted",
+	"ctx_rx_rds_ring_prim_success",
+	"ctx_num_lro_flows_added",
+	"ctx_num_lro_flows_removed",
+	"ctx_num_lro_flows_active",
+	"ctx_pkts_dropped_unknown",
+};
+
+#define QLCNIC_STATS_LEN ARRAY_SIZE(qlcnic_gstrings_stats)
+#define QLC_83XX_STATS (ARRAY_SIZE(qlcnic_83xx_tx_stats_strings)	\
+			+ ARRAY_SIZE(qlcnic_83xx_mac_stats_strings)	\
+			+ ARRAY_SIZE(qlcnic_83xx_rx_stats_strings))
+
+#define QLCNIC_82XX_STATS (QLCNIC_STATS_LEN \
+			+ ARRAY_SIZE(qlcnic_83xx_mac_stats_strings))
+
+#define QLCNIC_DEVICE_STATS_LEN(adapter)	\
+	(QLCNIC_IS_83XX(adapter) ?	\
+	QLC_83XX_STATS :\
+	(ARRAY_SIZE(qlcnic_83xx_mac_stats_strings)	\
+	+ ARRAY_SIZE(qlcnic_device_gstrings_stats)))
+
 #define QLCNIC_STATS_LEN ARRAY_SIZE(qlcnic_gstrings_stats)
-#define QLCNIC_MAC_STATS_LEN ARRAY_SIZE(qlcnic_mac_stats_strings)
-#define QLCNIC_DEVICE_STATS_LEN	ARRAY_SIZE(qlcnic_device_gstrings_stats)
-#define QLCNIC_TOTAL_STATS_LEN QLCNIC_STATS_LEN + QLCNIC_MAC_STATS_LEN
 
 static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = {
 	"Register_Test_on_offline",
 	"Link_Test_on_offline",
 	"Interrupt_Test_offline",
 	"Internal_Loopback_offline",
-	"External_Loopback_offline"
+	"EEPROM_Test_offline"
 };
 
 #define QLCNIC_TEST_LEN	ARRAY_SIZE(qlcnic_gstrings_test)
@@ -146,6 +188,12 @@ static const u32 diag_registers[] = {
 	QLCNIC_PEG_ALIVE_COUNTER,
 	QLCNIC_PEG_HALT_STATUS1,
 	QLCNIC_PEG_HALT_STATUS2,
+	-1
+};
+
+static const u32 ext_diag_registers[] = {
+	CRB_XG_STATE_P3P,
+	ISR_INT_STATE_REG,
 	QLCNIC_CRB_PEG_NET_0+0x3c,
 	QLCNIC_CRB_PEG_NET_1+0x3c,
 	QLCNIC_CRB_PEG_NET_2+0x3c,
@@ -154,12 +202,19 @@ static const u32 diag_registers[] = {
 };
 
 #define QLCNIC_MGMT_API_VERSION	2
-#define QLCNIC_DEV_INFO_SIZE	1
-#define QLCNIC_ETHTOOL_REGS_VER	2
+#define QLCNIC_ETHTOOL_REGS_VER	3
+
 static int qlcnic_get_regs_len(struct net_device *dev)
 {
-	return sizeof(diag_registers) + QLCNIC_RING_REGS_LEN +
-				QLCNIC_DEV_INFO_SIZE + 1;
+	struct qlcnic_adapter *adapter = netdev_priv(dev);
+	u32 len;
+
+	if (QLCNIC_IS_83XX(adapter))
+		len = qlcnic_83xx_get_regs_len(adapter);
+	else
+		len = sizeof(ext_diag_registers) + sizeof(diag_registers);
+
+	return QLCNIC_RING_REGS_LEN + len + QLCNIC_DEV_INFO_SIZE + 1;
 }
 
 static int qlcnic_get_eeprom_len(struct net_device *dev)
@@ -170,15 +225,13 @@ static int qlcnic_get_eeprom_len(struct net_device *dev)
 static void
 qlcnic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
 {
-	int err;
 	struct qlcnic_adapter *adapter = netdev_priv(dev);
 	u32 fw_major, fw_minor, fw_build;
-
-	fw_major = QLCRD32(adapter, QLCNIC_FW_VERSION_MAJOR, &err);
-	fw_minor = QLCRD32(adapter, QLCNIC_FW_VERSION_MINOR, &err);
-	fw_build = QLCRD32(adapter, QLCNIC_FW_VERSION_SUB, &err);
+	fw_major = QLCRD(adapter, QLCNIC_FW_VERSION_MAJOR);
+	fw_minor = QLCRD(adapter, QLCNIC_FW_VERSION_MINOR);
+	fw_build = QLCRD(adapter, QLCNIC_FW_VERSION_SUB);
 	snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
-		"%d.%d.%d", fw_major, fw_minor, fw_build);
+		 "%d.%d.%d", fw_major, fw_minor, fw_build);
 
 	strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
 		sizeof(drvinfo->bus_info));
@@ -190,10 +243,10 @@ qlcnic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
 static int
 qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
 {
-	int err;
 	struct qlcnic_adapter *adapter = netdev_priv(dev);
 	struct qlcnic_hardware_context *ahw = adapter->ahw;
-	int check_sfp_module = 0;
+	int err, check_sfp_module = 0;
+	u16 pcifn = ahw->pci_func;
 
 	/* read which mode */
 	if (ahw->port_type == QLCNIC_GBE) {
@@ -214,9 +267,12 @@ qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
 		ecmd->autoneg = ahw->link_autoneg;
 
 	} else if (ahw->port_type == QLCNIC_XGBE) {
-		u32 val;
-
-		val = QLCRD32(adapter, QLCNIC_PORT_MODE_ADDR, &err);
+		u32 val = 0;
+		if (QLCNIC_IS_83XX(adapter)) {
+			qlcnic_83xx_get_settings(adapter);
+		} else {
+			val = QLCRD32(adapter, QLCNIC_PORT_MODE_ADDR, &err);
+		}
 		if (val == QLCNIC_PORT_MODE_802_3_AP) {
 			ecmd->supported = SUPPORTED_1000baseT_Full;
 			ecmd->advertising = ADVERTISED_1000baseT_Full;
@@ -226,6 +282,10 @@ qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
 		}
 
 		if (netif_running(dev) && ahw->has_link_events) {
+			if (QLCNIC_IS_82XX(adapter))
+				ahw->link_speed =
+					QLCNIC_READ_LINK_SPEED(adapter,
+							       pcifn, &err);
 			ethtool_cmd_speed_set(ecmd, ahw->link_speed);
 			ecmd->autoneg = ahw->link_autoneg;
 			ecmd->duplex = ahw->link_duplex;
@@ -295,6 +355,13 @@ skip:
 			ecmd->port = PORT_TP;
 		}
 		break;
+	case QLCNIC_BRDTYPE_83XX_10G:
+		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) && ahw->has_link_events;
+		break;
 	default:
 		dev_err(&adapter->pdev->dev, "Unsupported board model %d\n",
 			ahw->board_type);
@@ -323,15 +390,10 @@ skip:
 }
 
 static int
-qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+qlcnic_set_port_config(struct qlcnic_adapter *adapter,
+		       struct ethtool_cmd *ecmd)
 {
-	u32 config = 0;
-	u32 ret = 0;
-	struct qlcnic_adapter *adapter = netdev_priv(dev);
-
-	if (adapter->ahw->port_type != QLCNIC_GBE)
-		return -EOPNOTSUPP;
-
+	u32 ret = 0, config = 0;
 	/* read which mode */
 	if (ecmd->duplex)
 		config |= 0x1;
@@ -359,6 +421,25 @@ qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
 		return -EOPNOTSUPP;
 	else if (ret)
 		return -EIO;
+	return ret;
+}
+
+static int
+qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	u32 ret = 0;
+	struct qlcnic_adapter *adapter = netdev_priv(dev);
+
+	if (adapter->ahw->port_type != QLCNIC_GBE)
+		return -EOPNOTSUPP;
+
+	if (QLCNIC_IS_83XX(adapter))
+		ret = qlcnic_83xx_set_settings(adapter, ecmd);
+	else
+		ret = qlcnic_set_port_config(adapter, ecmd);
+
+	if (!ret)
+		return ret;
 
 	adapter->ahw->link_speed = ethtool_cmd_speed(ecmd);
 	adapter->ahw->link_duplex = ecmd->duplex;
@@ -371,26 +452,42 @@ qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
 	return dev->netdev_ops->ndo_open(dev);
 }
 
+static int
+qlcnic_82xx_get_registers(struct qlcnic_adapter *adapter, u32 *regs_buff)
+{
+	int err, i, j = 0;
+
+	for (i = QLCNIC_DEV_INFO_SIZE + 1; diag_registers[j] != -1; j++, i++)
+		regs_buff[i] = QLCRD(adapter, diag_registers[j]);
+	j = 0;
+	while (ext_diag_registers[j] != -1)
+		regs_buff[i++] = QLCRD32(adapter, ext_diag_registers[j++],
+					 &err);
+	return i;
+}
+
 static void
 qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
 {
-	int err;
 	struct qlcnic_adapter *adapter = netdev_priv(dev);
 	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
 	struct qlcnic_host_sds_ring *sds_ring;
 	struct qlcnic_hardware_context *ahw = adapter->ahw;
 	u32 *regs_buff = p;
-	int ring, i = 0, j = 0;
+	int ring, i = 0;
 
 	memset(p, 0, qlcnic_get_regs_len(dev));
+
 	regs->version = (QLCNIC_ETHTOOL_REGS_VER << 24) |
 		(ahw->revision_id << 16) | (adapter->pdev)->device;
 
 	regs_buff[0] = (0xcafe0000 | (QLCNIC_DEV_INFO_SIZE & 0xffff));
 	regs_buff[1] = QLCNIC_MGMT_API_VERSION;
 
-	for (i = QLCNIC_DEV_INFO_SIZE + 1; diag_registers[j] != -1; j++, i++)
-		regs_buff[i] = QLCRD32(adapter, diag_registers[j], &err);
+	if (QLCNIC_IS_82XX(adapter))
+		i = qlcnic_82xx_get_registers(adapter, regs_buff);
+	else
+		i = qlcnic_83xx_get_registers(adapter, regs_buff);
 
 	if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
 		return;
@@ -419,6 +516,10 @@ static u32 qlcnic_test_link(struct net_device *dev)
 	struct qlcnic_adapter *adapter = netdev_priv(dev);
 	u32 val;
 
+	if (QLCNIC_IS_83XX(adapter)) {
+		val = qlcnic_83xx_test_link(adapter);
+		return (val & 1) ? 0 : 1;
+	}
 	val = QLCRD32(adapter, CRB_XG_STATE_P3P, &err);
 	val = XG_LINK_STATE_P3P(adapter->ahw->pci_func, val);
 	return (val == XG_LINK_UP_P3P) ? 0 : 1;
@@ -430,8 +531,10 @@ qlcnic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
 {
 	struct qlcnic_adapter *adapter = netdev_priv(dev);
 	int offset;
-	int ret;
+	int ret = -1;
 
+	if (QLCNIC_IS_83XX(adapter))
+		return 0;
 	if (eeprom->len == 0)
 		return -EINVAL;
 
@@ -439,8 +542,9 @@ qlcnic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
 			((adapter->pdev)->device << 16);
 	offset = eeprom->offset;
 
-	ret = qlcnic_rom_fast_read_words(adapter, offset, bytes,
-						eeprom->len);
+	if (QLCNIC_IS_82XX(adapter))
+		ret = qlcnic_rom_fast_read_words(adapter, offset, bytes,
+						 eeprom->len);
 	if (ret < 0)
 		return ret;
 
@@ -510,12 +614,13 @@ qlcnic_set_ringparam(struct net_device *dev,
 }
 
 static void qlcnic_get_channels(struct net_device *dev,
-		struct ethtool_channels *channel)
+				struct ethtool_channels *channel)
 {
 	struct qlcnic_adapter *adapter = netdev_priv(dev);
 
 	channel->max_rx = rounddown_pow_of_two(min_t(int,
-			adapter->ahw->max_rx_ques, num_online_cpus()));
+					       adapter->ahw->max_rx_ques,
+					       num_online_cpus()));
 	channel->max_tx = adapter->ahw->max_tx_ques;
 
 	channel->rx_count = adapter->max_sds_rings;
@@ -523,7 +628,7 @@ static void qlcnic_get_channels(struct net_device *dev,
 }
 
 static int qlcnic_set_channels(struct net_device *dev,
-		struct ethtool_channels *channel)
+			       struct ethtool_channels *channel)
 {
 	struct qlcnic_adapter *adapter = netdev_priv(dev);
 	int err;
@@ -532,19 +637,19 @@ static int qlcnic_set_channels(struct net_device *dev,
 	    channel->tx_count != channel->max_tx)
 		return -EINVAL;
 
-	err = qlcnic_validate_max_rss(dev, channel->max_rx, channel->rx_count);
+	err = qlcnic_validate_max_rss(channel->max_rx, channel->rx_count);
 	if (err)
 		return err;
 
-	err = qlcnic_set_max_rss(adapter, channel->rx_count);
+	err = qlcnic_set_max_rss(adapter, channel->rx_count, 0);
 	netdev_info(dev, "allocated 0x%x sds rings\n",
-				 adapter->max_sds_rings);
+		    adapter->max_sds_rings);
 	return err;
 }
 
 static void
 qlcnic_get_pauseparam(struct net_device *netdev,
-			  struct ethtool_pauseparam *pause)
+		      struct ethtool_pauseparam *pause)
 {
 	int err;
 	struct qlcnic_adapter *adapter = netdev_priv(netdev);
@@ -552,6 +657,10 @@ qlcnic_get_pauseparam(struct net_device *netdev,
 	int port = adapter->ahw->physical_port;
 	__u32 val;
 
+	if (QLCNIC_IS_83XX(adapter)) {
+		qlcnic_83xx_get_pauseparam(adapter, pause);
+		return;
+	}
 	if (ahw->port_type == QLCNIC_GBE) {
 		if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
 			return;
@@ -591,14 +700,16 @@ qlcnic_get_pauseparam(struct net_device *netdev,
 
 static int
 qlcnic_set_pauseparam(struct net_device *netdev,
-			  struct ethtool_pauseparam *pause)
+		      struct ethtool_pauseparam *pause)
 {
-	int err;
 	struct qlcnic_adapter *adapter = netdev_priv(netdev);
 	struct qlcnic_hardware_context *ahw = adapter->ahw;
-	int port = adapter->ahw->physical_port;
+	int err, port = adapter->ahw->physical_port;
 	__u32 val;
 
+	if (QLCNIC_IS_83XX(adapter))
+		return qlcnic_83xx_set_pauseparam(adapter, pause);
+
 	/* read mode */
 	if (ahw->port_type == QLCNIC_GBE) {
 		if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
@@ -675,6 +786,9 @@ static int qlcnic_reg_test(struct net_device *dev)
 	struct qlcnic_adapter *adapter = netdev_priv(dev);
 	u32 data_read;
 
+	if (QLCNIC_IS_83XX(adapter))
+		return qlcnic_83xx_reg_test(adapter);
+
 	data_read = QLCRD32(adapter, QLCNIC_PCIX_PH_REG(0), &err);
 	if ((data_read & 0xffff) != adapter->pdev->vendor)
 		return 1;
@@ -682,6 +796,16 @@ static int qlcnic_reg_test(struct net_device *dev)
 	return 0;
 }
 
+static int qlcnic_eeprom_test(struct net_device *dev)
+{
+	struct qlcnic_adapter *adapter = netdev_priv(dev);
+
+	if (QLCNIC_IS_82XX(adapter))
+		return 0;
+
+	return qlcnic_83xx_flash_test(adapter);
+}
+
 static int qlcnic_get_sset_count(struct net_device *dev, int sset)
 {
 	struct qlcnic_adapter *adapter = netdev_priv(dev);
@@ -689,9 +813,11 @@ static int qlcnic_get_sset_count(struct net_device *dev, int sset)
 	case ETH_SS_TEST:
 		return QLCNIC_TEST_LEN;
 	case ETH_SS_STATS:
-		if (adapter->flags & QLCNIC_ESWITCH_ENABLED)
-			return QLCNIC_TOTAL_STATS_LEN + QLCNIC_DEVICE_STATS_LEN;
-		return QLCNIC_TOTAL_STATS_LEN;
+		if ((adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
+			QLCNIC_IS_83XX(adapter))
+			return QLCNIC_STATS_LEN +
+				QLCNIC_DEVICE_STATS_LEN(adapter);
+		return QLCNIC_82XX_STATS;
 	default:
 		return -EOPNOTSUPP;
 	}
@@ -714,8 +840,12 @@ static int qlcnic_irq_test(struct net_device *netdev)
 	adapter->ahw->diag_cnt = 0;
 	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_INTRPT_TEST);
 
-	cmd.req.arg[1] = cpu_to_le32(adapter->ahw->pci_func);
-	ret = qlcnic_issue_cmd(adapter, &cmd);
+	if (QLCNIC_IS_83XX(adapter)) {
+		ret = qlcnic_83xx_interrupt_test(adapter, &cmd);
+	} else {
+		cmd.req.arg[1] = cpu_to_le32(adapter->ahw->pci_func);
+		ret = qlcnic_issue_cmd(adapter, &cmd);
+	}
 
 	if (ret)
 		goto done;
@@ -760,15 +890,16 @@ static int qlcnic_do_lb_test(struct qlcnic_adapter *adapter, u8 mode)
 {
 	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
 	struct qlcnic_host_sds_ring *sds_ring = &recv_ctx->sds_rings[0];
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
 	struct sk_buff *skb;
 	int i, loop, cnt = 0;
 
 	for (i = 0; i < QLCNIC_NUM_ILB_PKT; i++) {
-		skb = netdev_alloc_skb(adapter->netdev, QLCNIC_ILB_PKT_SIZE);
+		skb = dev_alloc_skb(QLCNIC_ILB_PKT_SIZE);
 		qlcnic_create_loopback_buff(skb->data, adapter->mac_addr);
 		skb_put(skb, QLCNIC_ILB_PKT_SIZE);
 
-		adapter->ahw->diag_cnt = 0;
+		ahw->diag_cnt = 0;
 		qlcnic_xmit_frame(skb, adapter->netdev);
 
 		loop = 0;
@@ -777,13 +908,14 @@ static int qlcnic_do_lb_test(struct qlcnic_adapter *adapter, u8 mode)
 			qlcnic_process_rcv_ring_diag(sds_ring);
 			if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP)
 				break;
-		} while (!adapter->ahw->diag_cnt);
+		} while (!ahw->diag_cnt);
 
 		dev_kfree_skb_any(skb);
 
-		if (!adapter->ahw->diag_cnt)
-			QLCDB(adapter, DRV,
-			"LB Test: packet #%d was not received\n", i + 1);
+		if (!ahw->diag_cnt)
+			netif_warn(adapter->ahw, pktdata, adapter->netdev,
+				   "LB Test: packet #%d was not received\n",
+				   i + 1);
 		else
 			cnt++;
 	}
@@ -791,8 +923,7 @@ static int qlcnic_do_lb_test(struct qlcnic_adapter *adapter, u8 mode)
 		dev_warn(&adapter->pdev->dev, "LB Test failed\n");
 		if (mode != QLCNIC_ILB_MODE) {
 			dev_warn(&adapter->pdev->dev,
-				"WARNING: Please make sure external"
-				"loopback connector is plugged in\n");
+				 "Check loopback connector\n");
 		}
 		return -1;
 	}
@@ -803,21 +934,25 @@ static int qlcnic_loopback_test(struct net_device *netdev, u8 mode)
 {
 	struct qlcnic_adapter *adapter = netdev_priv(netdev);
 	int max_sds_rings = adapter->max_sds_rings;
-	struct qlcnic_hardware_context *ahw = adapter->ahw;
 	struct qlcnic_host_sds_ring *sds_ring;
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
 	int loop = 0;
 	int ret;
 
+	if (QLCNIC_IS_83XX(adapter))
+		goto skip_cap;
 	if (!(ahw->capabilities & QLCNIC_FW_CAPABILITY_MULTI_LOOPBACK)) {
-		netdev_info(netdev, "Firmware is not loopback test capable\n");
+		netdev_err(netdev,
+			   "Firmware is not loopback test capable\n");
 		return -EOPNOTSUPP;
 	}
-
-	QLCDB(adapter, DRV, "%s loopback test in progress\n",
-		   mode == QLCNIC_ILB_MODE ? "internal" : "external");
+skip_cap:
+	netif_info(adapter->ahw, drv, netdev,
+		   "%s loopback test in progress\n",
+		   mode == QLCNIC_ILB_MODE ? "internal" : "external");
 	if (ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
-		netdev_warn(netdev, "Loopback test not supported for non "
-				"privilege function\n");
+		dev_warn(&adapter->pdev->dev,
+			 "Loopback test invalid for non privileged function\n");
 		return 0;
 	}
 
@@ -829,18 +964,20 @@ static int qlcnic_loopback_test(struct net_device *netdev, u8 mode)
 		goto clear_it;
 
 	sds_ring = &adapter->recv_ctx->sds_rings[0];
-
 	ret = qlcnic_set_lb_mode(adapter, mode);
 	if (ret)
 		goto free_res;
 
+	if (QLCNIC_IS_83XX(adapter))
+		goto skip_fw_msg;
+
 	ahw->diag_cnt = 0;
 	do {
 		msleep(500);
 		qlcnic_process_rcv_ring_diag(sds_ring);
 		if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP) {
-			netdev_info(netdev, "firmware didnt respond to loopback"
-				" configure request\n");
+			netdev_err(netdev,
+				   "No response for loopback request\n");
 			ret = -QLCNIC_FW_NOT_RESPOND;
 			goto free_res;
 		} else if (ahw->diag_cnt) {
@@ -848,7 +985,9 @@ static int qlcnic_loopback_test(struct net_device *netdev, u8 mode)
 			goto free_res;
 		}
 	} while (!QLCNIC_IS_LB_CONFIGURED(ahw->loopback_state));
-
+skip_fw_msg:
+	/* allowing firmware to settle before running traffic */
+	msleep(2000);
 	ret = qlcnic_do_lb_test(adapter, mode);
 
 	qlcnic_clear_lb_mode(adapter, mode);
@@ -884,20 +1023,18 @@ qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
 		data[3] = qlcnic_loopback_test(dev, QLCNIC_ILB_MODE);
 		if (data[3])
 			eth_test->flags |= ETH_TEST_FL_FAILED;
-		if (eth_test->flags & ETH_TEST_FL_EXTERNAL_LB) {
-			data[4] = qlcnic_loopback_test(dev, QLCNIC_ELB_MODE);
-			if (data[4])
-				eth_test->flags |= ETH_TEST_FL_FAILED;
-			eth_test->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE;
-		}
+
+		data[4] = qlcnic_eeprom_test(dev);
+		if (data[4])
+			eth_test->flags |= ETH_TEST_FL_FAILED;
 	}
 }
 
 static void
-qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 * data)
+qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 *data)
 {
 	struct qlcnic_adapter *adapter = netdev_priv(dev);
-	int index, i, j;
+	int index, i, num_stats;
 
 	switch (stringset) {
 	case ETH_SS_TEST:
@@ -910,14 +1047,34 @@ qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 * data)
 			       qlcnic_gstrings_stats[index].stat_string,
 			       ETH_GSTRING_LEN);
 		}
-		for (j = 0; j < QLCNIC_MAC_STATS_LEN; index++, j++) {
-			memcpy(data + index * ETH_GSTRING_LEN,
-			       qlcnic_mac_stats_strings[j],
-			       ETH_GSTRING_LEN);
+		if (QLCNIC_IS_83XX(adapter)) {
+			num_stats = ARRAY_SIZE(qlcnic_83xx_tx_stats_strings);
+			for (i = 0; i < num_stats; i++, index++)
+				memcpy(data + index * ETH_GSTRING_LEN,
+				       qlcnic_83xx_tx_stats_strings[i],
+				       ETH_GSTRING_LEN);
+			num_stats = ARRAY_SIZE(qlcnic_83xx_mac_stats_strings);
+			for (i = 0; i < num_stats; i++, index++)
+				memcpy(data + index * ETH_GSTRING_LEN,
+				       qlcnic_83xx_mac_stats_strings[i],
+				       ETH_GSTRING_LEN);
+			num_stats = ARRAY_SIZE(qlcnic_83xx_rx_stats_strings);
+			for (i = 0; i < num_stats; i++, index++)
+				memcpy(data + index * ETH_GSTRING_LEN,
+				       qlcnic_83xx_rx_stats_strings[i],
+				       ETH_GSTRING_LEN);
+			return;
+		} else {
+			num_stats = ARRAY_SIZE(qlcnic_83xx_mac_stats_strings);
+			for (i = 0; i < num_stats; i++, index++)
+				memcpy(data + index * ETH_GSTRING_LEN,
+				       qlcnic_83xx_mac_stats_strings[i],
+				       ETH_GSTRING_LEN);
 		}
 		if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
 			return;
-		for (i = 0; i < QLCNIC_DEVICE_STATS_LEN; index++, i++) {
+		num_stats = ARRAY_SIZE(qlcnic_device_gstrings_stats);
+		for (i = 0; i < num_stats; index++, i++) {
 			memcpy(data + index * ETH_GSTRING_LEN,
 			       qlcnic_device_gstrings_stats[i],
 			       ETH_GSTRING_LEN);
@@ -926,88 +1083,83 @@ qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 * data)
 }
 
 static void
-qlcnic_fill_stats(int *index, u64 *data, void *stats, int type)
+qlcnic_fill_stats(u64 *data, void *stats, int type)
 {
-	int ind = *index;
-
 	if (type == QLCNIC_MAC_STATS) {
 		struct qlcnic_mac_statistics *mac_stats =
 					(struct qlcnic_mac_statistics *)stats;
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_frames);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_bytes);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_mcast_pkts);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_bcast_pkts);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_pause_cnt);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_ctrl_pkt);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_64b_pkts);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_127b_pkts);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_255b_pkts);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_511b_pkts);
-		data[ind++] =
-			QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_1023b_pkts);
-		data[ind++] =
-			QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_1518b_pkts);
-		data[ind++] =
-			QLCNIC_FILL_STATS(mac_stats->mac_tx_gt_1518b_pkts);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_frames);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_bytes);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_mcast_pkts);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_bcast_pkts);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_pause_cnt);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_ctrl_pkt);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_64b_pkts);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_127b_pkts);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_255b_pkts);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_511b_pkts);
-		data[ind++] =
-			QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_1023b_pkts);
-		data[ind++] =
-			QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_1518b_pkts);
-		data[ind++] =
-			QLCNIC_FILL_STATS(mac_stats->mac_rx_gt_1518b_pkts);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_error);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_small);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_large);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_jabber);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_dropped);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_align_error);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_frames);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_bytes);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_mcast_pkts);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_bcast_pkts);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_pause_cnt);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_ctrl_pkt);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_64b_pkts);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_127b_pkts);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_255b_pkts);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_511b_pkts);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_1023b_pkts);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_1518b_pkts);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_gt_1518b_pkts);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_frames);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_bytes);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_mcast_pkts);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_bcast_pkts);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_pause_cnt);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_ctrl_pkt);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_64b_pkts);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_127b_pkts);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_255b_pkts);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_511b_pkts);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_1023b_pkts);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_1518b_pkts);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_gt_1518b_pkts);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_error);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_small);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_large);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_jabber);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_dropped);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_FCS_error);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_align_error);
 	} else if (type == QLCNIC_ESW_STATS) {
 		struct __qlcnic_esw_statistics *esw_stats =
 				(struct __qlcnic_esw_statistics *)stats;
-		data[ind++] = QLCNIC_FILL_STATS(esw_stats->unicast_frames);
-		data[ind++] = QLCNIC_FILL_STATS(esw_stats->multicast_frames);
-		data[ind++] = QLCNIC_FILL_STATS(esw_stats->broadcast_frames);
-		data[ind++] = QLCNIC_FILL_STATS(esw_stats->dropped_frames);
-		data[ind++] = QLCNIC_FILL_STATS(esw_stats->errors);
-		data[ind++] = QLCNIC_FILL_STATS(esw_stats->local_frames);
-		data[ind++] = QLCNIC_FILL_STATS(esw_stats->numbytes);
+		*data++ = QLCNIC_FILL_STATS(esw_stats->unicast_frames);
+		*data++ = QLCNIC_FILL_STATS(esw_stats->multicast_frames);
+		*data++ = QLCNIC_FILL_STATS(esw_stats->broadcast_frames);
+		*data++ = QLCNIC_FILL_STATS(esw_stats->dropped_frames);
+		*data++ = QLCNIC_FILL_STATS(esw_stats->errors);
+		*data++ = QLCNIC_FILL_STATS(esw_stats->local_frames);
+		*data++ = QLCNIC_FILL_STATS(esw_stats->numbytes);
 	}
-
-	*index = ind;
 }
 
 static void
 qlcnic_get_ethtool_stats(struct net_device *dev,
-			     struct ethtool_stats *stats, u64 * data)
+			 struct ethtool_stats *stats, u64 *data)
 {
 	struct qlcnic_adapter *adapter = netdev_priv(dev);
 	struct qlcnic_esw_statistics port_stats;
 	struct qlcnic_mac_statistics mac_stats;
-	int index, ret;
+	int index, ret, length;
 
-	for (index = 0; index < QLCNIC_STATS_LEN; index++) {
+	length = QLCNIC_STATS_LEN;
+	for (index = 0; index < length; 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);
+		*data++ = (qlcnic_gstrings_stats[index].sizeof_stat ==
+		     sizeof(u64)) ? (*(u64 *)p) : ((*(u32 *)p));
 	}
 
-	/* Retrieve MAC statistics from firmware */
-	memset(&mac_stats, 0, sizeof(struct qlcnic_mac_statistics));
-	qlcnic_get_mac_stats(adapter, &mac_stats);
-	qlcnic_fill_stats(&index, data, &mac_stats, QLCNIC_MAC_STATS);
+	if (QLCNIC_IS_83XX(adapter)) {
+		return qlcnic_83xx_get_stats(adapter, stats, data);
+	} else {
+		/* Retrieve MAC statistics from firmware */
+		memset(&mac_stats, 0, sizeof(struct qlcnic_mac_statistics));
+		qlcnic_get_mac_stats(adapter, &mac_stats);
+		qlcnic_fill_stats(data, &mac_stats, QLCNIC_MAC_STATS);
+	}
 
 	if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
 		return;
@@ -1018,14 +1170,14 @@ qlcnic_get_ethtool_stats(struct net_device *dev,
 	if (ret)
 		return;
 
-	qlcnic_fill_stats(&index, data, &port_stats.rx, QLCNIC_ESW_STATS);
+	qlcnic_fill_stats(data, &port_stats.rx, QLCNIC_ESW_STATS);
 
 	ret = qlcnic_get_port_stats(adapter, adapter->ahw->pci_func,
 			QLCNIC_QUERY_TX_COUNTER, &port_stats.tx);
 	if (ret)
 		return;
 
-	qlcnic_fill_stats(&index, data, &port_stats.tx, QLCNIC_ESW_STATS);
+	qlcnic_fill_stats(data, &port_stats.tx, QLCNIC_ESW_STATS);
 }
 
 static int qlcnic_set_led(struct net_device *dev,
@@ -1035,6 +1187,8 @@ static int qlcnic_set_led(struct net_device *dev,
 	int max_sds_rings = adapter->max_sds_rings;
 	int err = -EIO, active = 1;
 
+	if (QLCNIC_IS_83XX(adapter))
+		return -EOPNOTSUPP;
 	if (adapter->ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
 		netdev_warn(dev, "LED test not supported for non "
 				"privilege function\n");
@@ -1102,6 +1256,8 @@ qlcnic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 	struct qlcnic_adapter *adapter = netdev_priv(dev);
 	u32 wol_cfg;
 
+	if (QLCNIC_IS_83XX(adapter))
+		return;
 	wol->supported = 0;
 	wol->wolopts = 0;
 
@@ -1121,8 +1277,10 @@ 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)
+	if (QLCNIC_IS_83XX(adapter))
 		return -EOPNOTSUPP;
+	if (wol->wolopts & ~WAKE_MAGIC)
+		return -EINVAL;
 
 	wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV, &err);
 	if (!(wol_cfg & (1 << adapter->portnum)))
@@ -1313,7 +1471,7 @@ qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)
 			return 0;
 		}
 		netdev_info(netdev, "Forcing a FW dump\n");
-		qlcnic_dev_request_reset(adapter, 0);
+		qlcnic_dev_request_reset(adapter, val->flag);
 		break;
 	case QLCNIC_DISABLE_FW_DUMP:
 		if (fw_dump->enable && fw_dump->tmpl_hdr) {
@@ -1333,7 +1491,7 @@ qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)
 		return 0;
 	case QLCNIC_FORCE_FW_RESET:
 		netdev_info(netdev, "Forcing a FW reset\n");
-		qlcnic_dev_request_reset(adapter, 0);
+		qlcnic_dev_request_reset(adapter, val->flag);
 		adapter->flags &= ~QLCNIC_FW_RESET_OWNER;
 		return 0;
 	case QLCNIC_SET_QUIESCENT:
@@ -1347,8 +1505,8 @@ qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)
 			netdev_err(netdev, "FW dump not supported\n");
 			return -ENOTSUPP;
 		}
-		for (i = 0; i < ARRAY_SIZE(FW_DUMP_LEVELS); i++) {
-			if (val->flag == FW_DUMP_LEVELS[i]) {
+		for (i = 0; i < ARRAY_SIZE(qlcnic_fw_dump_level); i++) {
+			if (val->flag == qlcnic_fw_dump_level[i]) {
 				fw_dump->tmpl_hdr->drv_cap_mask =
 							val->flag;
 				netdev_info(netdev, "Driver mask changed to: 0x%x\n",
@@ -1356,7 +1514,7 @@ qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)
 				return 0;
 			}
 		}
-		netdev_info(netdev, "Invalid dump level: 0x%x\n", val->flag);
+		netdev_err(netdev, "Invalid dump level: 0x%x\n", val->flag);
 		return -EINVAL;
 	}
 	return 0;
@@ -1392,10 +1550,3 @@ const struct ethtool_ops qlcnic_ethtool_ops = {
 	.get_dump_data = qlcnic_get_dump_data,
 	.set_dump = qlcnic_set_dump,
 };
-
-const struct ethtool_ops qlcnic_ethtool_failed_ops = {
-	.get_settings = qlcnic_get_settings,
-	.get_drvinfo = qlcnic_get_drvinfo,
-	.set_msglevel = qlcnic_set_msglevel,
-	.get_msglevel = qlcnic_get_msglevel,
-};
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index c4f9ff6..1d8a878 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -3238,39 +3238,61 @@ static struct device_attribute dev_attr_diag_mode = {
 	.store = qlcnic_store_diag_mode,
 };
 
-int qlcnic_validate_max_rss(struct net_device *netdev, u8 max_hw, u8 val)
+int qlcnic_validate_max_rss(u8 max_hw, u8 val)
 {
-	if (!qlcnic_use_msi_x && !qlcnic_use_msi) {
-		netdev_info(netdev, "no msix or msi support, hence no rss\n");
-		return -EINVAL;
+	u32 max_allowed;
+
+	if (max_hw > MAX_SDS_RINGS) {
+		max_hw = MAX_SDS_RINGS;
+		pr_info("max rss reset to %d\n", MAX_SDS_RINGS);
 	}
 
-	if ((val > max_hw) || (val <  2) || !is_power_of_2(val)) {
-		netdev_info(netdev, "rss_ring valid range [2 - %x] in "
-			" powers of 2\n", max_hw);
+	max_allowed = rounddown_pow_of_two(min_t(int, max_hw,
+					   num_online_cpus()));
+
+	if ((val > max_allowed) || (val <  2) || !is_power_of_2(val)) {
+		pr_info("rss_ring valid range [2 - %x] in powers of 2\n",
+			max_allowed);
 		return -EINVAL;
 	}
 	return 0;
-
 }
 
-int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data)
+int
+qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data, size_t len)
 {
+	int err;
 	struct net_device *netdev = adapter->netdev;
-	int err = 0;
 
-	if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+	if (test_bit(__QLCNIC_RESETTING, &adapter->state))
 		return -EBUSY;
 
 	netif_device_detach(netdev);
 	if (netif_running(netdev))
 		__qlcnic_down(adapter, netdev);
+
+	if (QLCNIC_IS_83XX(adapter)) {
+		if (adapter->flags & QLCNIC_MSIX_ENABLED)
+			qlcnic_83xx_config_intrpt(adapter, 0);
+		qlcnic_83xx_free_mbx_intr(adapter);
+	}
+
 	qlcnic_detach(adapter);
 	qlcnic_teardown_intr(adapter);
 
 	err = qlcnic_setup_intr(adapter, data);
 	if (err)
-		netdev_info(netdev, "failed setting max_rss; rss disabled\n");
+		dev_err(&adapter->pdev->dev,
+			"failed setting max_rss; rss disabled\n");
+
+	if (QLCNIC_IS_83XX(adapter)) {
+		err = qlcnic_83xx_setup_mbx_intr(adapter);
+		if (err) {
+			dev_err(&adapter->pdev->dev,
+				"failed to setup mbx interrupt\n");
+			goto done;
+		}
+	}
 
 	if (netif_running(netdev)) {
 		err = qlcnic_attach(adapter);
@@ -3281,10 +3303,11 @@ int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data)
 			goto done;
 		qlcnic_restore_indev_addr(netdev, NETDEV_UP);
 	}
+	err = len;
  done:
 	netif_device_attach(netdev);
-	clear_bit(__QLCNIC_RESETTING, &adapter->state);
 	return err;
+
 }
 
 static int
-- 
1.7.1

^ permalink raw reply related

* Re: [RFC PATCH 0/5] Reorganize libfcoe control interfaces
From: Love, Robert W @ 2012-09-11  1:41 UTC (permalink / raw)
  To: Bhanu Prakash Gollapudi
  Cc: netdev@vger.kernel.org, gregkh@linuxfoundation.org,
	linux-scsi@vger.kernel.org, devel@open-fcoe.org
In-Reply-To: <504E8040.70403@broadcom.com>

On Mon 10 Sep 2012 05:05:20 PM PDT, Bhanu Prakash Gollapudi wrote:
> On 9/10/2012 3:59 PM, Robert Love wrote:
>> The following series implements a move from using module parameters
>> as control interfaces to /sys/bus/fcoe based interfaces. A sysfs
>> infrastructure
>> was added to the kernel a few cycles ago, this series builds on that
>> work.
>>
>> It moves the create, vn2vn_create, destroy, enable and disable
>> interfaces
>> from /sys/module/libfcoe/parameters/ to various places under
>> /sys/bus/fcoe/.
>> These interfaces simply are not module configurations- they are control
>> interfaces.
>>
>> A second goal of this series is to change the initialization sequence
>> for
>> a FCoE device. The result of this series is that interfaces created
>> using
>> libfcoe.ko interfaces (i.e. fcoe.ko or bnx2fc.ko) will have the
>> following
>> starting steps-
>>
>> 1) Create/alloc the port
>>     - Allocate kernel memory and create per-instance sysfs devices
>>     - No discovery or login
>>
>> 2) Configure the port
>>     - Change mode, set ddp_min, etc...
>>
>> 3) Start the port
>>     - Begins discovery and/or login (depending on mode)
>>
>> 4) Destroy the port
>>     - Logout and free all memory
>
> Robert, Can you please let me now what is the motivation for this
> change and what problem are we solving with this approach? Is this
> primarily to allow user to set the mode?
>

The main problem is that our control interfaces shouldn't be module 
parameters. I think of module parameters as things that globally alter 
the module.

I also think that moving to a create/configure/start model gives us 
more flexibility going forward. We don't have too many FC/FCoE knobs to 
tune right now, but if we wanted to add more we don't have a good way 
to do it without starting the whole discovery/login process and then 
making changes during the discovery/login.

I think the module parameter problem is the justification, but I'm 
trying to be comprehensive in coming up with a flexible interface that 
will allow us to evolve as well.

> I'm concerned that we will be breaking user space compatibility with
> this change, as there should be a corresponding fcoemon/fipvlan change
> along with this, and existing utilities will not work.  Also the way
> we start fcoe will be completely different and the user may need to do
> the scripting changes, if any.

See the last statement from my initial posting (it's below). I have 
patches to modify fcoemon to use these new interfaces. I'd be happy to 
share them, I just didn't want to spam this broad of a audience.

>
> Thanks,
> Bhanu
>
>>
>> I'm looking for feedback on using sysfs files as control interfaces that
>> the user (application) would write interface names to. I modeled this
>> series off of the bonding sysfs interface, but it was suggested to me
>> that
>> it might not be a good example. I belive bonding uses two values
>> per-file
>> a '+' or a '-" to add or delete and then the ifname apended. I am simply
>> writing the ifname to the ctlr_create or ctlr_destroy.
>>
>> Series compiled and tested against v3.5. libfcoe.ko compile warning
>> fixed
>> upstream after v3.5, anyone who compiles this can ignore section
>> mismatch
>> warning. Also note that a modified fcoemon is needed to use the fcoe
>> system
>> service against this kernel modification. I'd be happy to provide that
>> fcoemon code on request.


^ permalink raw reply

* Re: [PATCH 2/3] ipv6, route: remove BACKTRACK() macro
From: David Miller @ 2012-09-11  1:42 UTC (permalink / raw)
  To: amwang; +Cc: netdev
In-Reply-To: <1347326362.30731.9.camel@cr0>

From: Cong Wang <amwang@redhat.com>
Date: Tue, 11 Sep 2012 09:19:22 +0800

> On Mon, 2012-09-10 at 16:32 -0400, David Miller wrote:
>> From: Cong Wang <amwang@redhat.com>
>> Date: Mon, 10 Sep 2012 20:48:45 +0800
>> 
>> > It doesn't save any code, nor it helps readability.
>> > 
>> > Signed-off-by: Cong Wang <amwang@redhat.com>
>> 
>> I'm not applying this.
>> 
>> Having two copies of the same exact logic means we will accumulate
>> bugs in the future if someone fixes the problem only in one
>> copy.
> 
> Makes sense, but BACKTRACK() is not well written, as it jumps out of its
> definition. :(

Anyone who has worked with longest-matching-prefix TRIE traversal
functions will have a pretty good idea what is going on here.

Yes, I know this conflicts with cases like how we killed all of
the netlink macros with embedded gotos.

But this patch made things worse and added code duplication.  Fix
it without the code duplication side effect and it'll be fine.

^ permalink raw reply

* Re: RFC: mac802154 Packet Queueing and Slave Devices
From: Alan Ott @ 2012-09-11  3:00 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-zigbee-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
In-Reply-To: <1347257547.1234.1110.camel@edumazet-glaptop>

On 09/10/2012 02:12 AM, Eric Dumazet wrote:
> On Sun, 2012-09-09 at 20:43 -0400, Alan Ott wrote:
>> Tony and I were recently talking about packet queueing on 802.15.4.
>>
>> The problem with this is that it defeats the netif flow control.
> And qdisc ability to better control bufferbloat...
>
> By the way, mac802154_tx() looks buggy :
>
> Also mac802154_wpan_xmit() returns NETDEV_TX_OK without kfree_skb(skb)
>

Hi Eric,

Thanks for the review. I'll get this patched up.

Alan.


------------------------------------------------------------------------------
Live Security Virtual Conference
Exclusive live event will cover all the ways today's security and 
threat landscape has changed and how IT managers can respond. Discussions 
will include endpoint security, mobile security and the latest in malware 
threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/

^ permalink raw reply

* Re: [PATCH 1/1] [PATCH] net: qmi_wwan: fix Gobi device probing for un2430
From: Bjørn Mork @ 2012-09-11  4:59 UTC (permalink / raw)
  To: David Miller, pierre.sauter; +Cc: gregkh, netdev
In-Reply-To: <20120910.164314.1674016370550788813.davem@davemloft.net>

David Miller <davem@davemloft.net> wrote:

>From: pierre.sauter@gmail.com
>Date: Mon, 10 Sep 2012 19:02:59 +0200
>
>> From: Pierre Sauter <pierre.sauter@gmail.com>
>> 
>> HP un2430 is a Gobi 3000 device. It was mistakenly treated as Gobi
>1000
>> in patch b9f90eb2740203ff2592efe640409ad48335d1c2.
>> 
>> I own this device and qmi_wwan works again with this fix.
>> 
>> Signed-off-by: Pierre Sauter <pierre.sauter@gmail.com>
>
>Bjorn, ACK/NACK?

Acked-by: Bjørn Mork <bjorn@mork.no>

Thanks for fixing this, Pierre. I wonder how I managed to get this wrong. Better look it all over again, I guess...


Bjørn

^ permalink raw reply

* Re: [PATCH 1/1] [PATCH] net: qmi_wwan: fix Gobi device probing for un2430
From: David Miller @ 2012-09-11  5:10 UTC (permalink / raw)
  To: bjorn; +Cc: pierre.sauter, gregkh, netdev
In-Reply-To: <22bf77fd-e0de-4a07-acf2-cd816a543ee9@email.android.com>

From: Bjørn Mork <bjorn@mork.no>
Date: Tue, 11 Sep 2012 06:59:57 +0200

> David Miller <davem@davemloft.net> wrote:
> 
>>From: pierre.sauter@gmail.com
>>Date: Mon, 10 Sep 2012 19:02:59 +0200
>>
>>> From: Pierre Sauter <pierre.sauter@gmail.com>
>>> 
>>> HP un2430 is a Gobi 3000 device. It was mistakenly treated as Gobi
>>1000
>>> in patch b9f90eb2740203ff2592efe640409ad48335d1c2.
>>> 
>>> I own this device and qmi_wwan works again with this fix.
>>> 
>>> Signed-off-by: Pierre Sauter <pierre.sauter@gmail.com>
>>
>>Bjorn, ACK/NACK?
> 
> Acked-by: Bjørn Mork <bjorn@mork.no>
> 
> Thanks for fixing this, Pierre. I wonder how I managed to get this
> wrong. Better look it all over again, I guess...

Applied, thanks everyone.

^ permalink raw reply

* [PATCH 2/2] ipv6: Compare addresses only bits up to the prefix length (RFC6724).
From: YOSHIFUJI Hideaki @ 2012-09-11  4:41 UTC (permalink / raw)
  To: davem, netdev; +Cc: yoshfuji

Compare bits up to the source address's prefix length only to
allows DNS load balancing to continue to be used as a tie breaker.

Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
---
 net/ipv6/addrconf.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 1237d5d..5fd8ec8 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -1070,8 +1070,10 @@ static int ipv6_get_saddr_eval(struct net *net,
 		break;
 	case IPV6_SADDR_RULE_PREFIX:
 		/* Rule 8: Use longest matching prefix */
-		score->matchlen = ret = ipv6_addr_diff(&score->ifa->addr,
-						       dst->addr);
+		ret = ipv6_addr_diff(&score->ifa->addr, dst->addr);
+		if (ret > score->ifa->prefix_len)
+			ret = score->ifa->prefix_len;
+		score->matchlen = ret;
 		break;
 	default:
 		ret = 0;
-- 
1.7.5.4

^ permalink raw reply related

* [PATCH 1/2] ipv6: Add labels for site-local and 6bone testing addresses (RFC6724)
From: YOSHIFUJI Hideaki @ 2012-09-11  4:16 UTC (permalink / raw)
  To: davem, netdev; +Cc: yoshfuji

Added labels for site-local addresses (fec0::/10) and 6bone testing
addresses (3ffe::/16) in order to depreference them.

Note that the RFC introduced new rows for Teredo, ULA and 6to4 addresses
in the default policy table.  Some of them have different labels from ours.
For backward compatibility, we do not change the "default" labels.

Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
---
 net/ipv6/addrlabel.c |   14 +++++++++++++-
 1 files changed, 13 insertions(+), 1 deletions(-)

diff --git a/net/ipv6/addrlabel.c b/net/ipv6/addrlabel.c
index 0b01715..4be23da 100644
--- a/net/ipv6/addrlabel.c
+++ b/net/ipv6/addrlabel.c
@@ -57,7 +57,7 @@ struct net *ip6addrlbl_net(const struct ip6addrlbl_entry *lbl)
 }
 
 /*
- * Default policy table (RFC3484 + extensions)
+ * Default policy table (RFC6724 + extensions)
  *
  * prefix		addr_type	label
  * -------------------------------------------------------------------------
@@ -69,8 +69,12 @@ struct net *ip6addrlbl_net(const struct ip6addrlbl_entry *lbl)
  * fc00::/7		N/A		5		ULA (RFC 4193)
  * 2001::/32		N/A		6		Teredo (RFC 4380)
  * 2001:10::/28		N/A		7		ORCHID (RFC 4843)
+ * fec0::/10		N/A		11		Site-local
+ *							(deprecated by RFC3879)
+ * 3ffe::/16		N/A		12		6bone
  *
  * Note: 0xffffffff is used if we do not have any policies.
+ * Note: Labels for ULA and 6to4 are different from labels listed in RFC6724.
  */
 
 #define IPV6_ADDR_LABEL_DEFAULT	0xffffffffUL
@@ -88,10 +92,18 @@ static const __net_initdata struct ip6addrlbl_init_table
 		.prefix = &(struct in6_addr){{{ 0xfc }}},
 		.prefixlen = 7,
 		.label = 5,
+	},{	/* fec0::/10 */
+		.prefix = &(struct in6_addr){{{ 0xfe, 0xc0 }}},
+		.prefixlen = 10,
+		.label = 11,
 	},{	/* 2002::/16 */
 		.prefix = &(struct in6_addr){{{ 0x20, 0x02 }}},
 		.prefixlen = 16,
 		.label = 2,
+	},{	/* 3ffe::/16 */
+		.prefix = &(struct in6_addr){{{ 0x3f, 0xfe }}},
+		.prefixlen = 16,
+		.label = 12,
 	},{	/* 2001::/32 */
 		.prefix = &(struct in6_addr){{{ 0x20, 0x01 }}},
 		.prefixlen = 32,
-- 
1.7.5.4

^ permalink raw reply related

* Re: [RFC PATCH 0/5] Reorganize libfcoe control interfaces
From: Bhanu Prakash Gollapudi @ 2012-09-11  5:46 UTC (permalink / raw)
  To: Love, Robert W
  Cc: netdev@vger.kernel.org, gregkh@linuxfoundation.org,
	linux-scsi@vger.kernel.org, devel@open-fcoe.org
In-Reply-To: <504E96DA.1080406@intel.com>

On 9/10/2012 6:41 PM, Love, Robert W wrote:
> On Mon 10 Sep 2012 05:05:20 PM PDT, Bhanu Prakash Gollapudi wrote:
>> On 9/10/2012 3:59 PM, Robert Love wrote:
>>> The following series implements a move from using module parameters
>>> as control interfaces to /sys/bus/fcoe based interfaces. A sysfs
>>> infrastructure
>>> was added to the kernel a few cycles ago, this series builds on that
>>> work.
>>>
>>> It moves the create, vn2vn_create, destroy, enable and disable
>>> interfaces
>>> from /sys/module/libfcoe/parameters/ to various places under
>>> /sys/bus/fcoe/.
>>> These interfaces simply are not module configurations- they are control
>>> interfaces.
>>>
>>> A second goal of this series is to change the initialization sequence
>>> for
>>> a FCoE device. The result of this series is that interfaces created
>>> using
>>> libfcoe.ko interfaces (i.e. fcoe.ko or bnx2fc.ko) will have the
>>> following
>>> starting steps-
>>>
>>> 1) Create/alloc the port
>>>      - Allocate kernel memory and create per-instance sysfs devices
>>>      - No discovery or login
>>>
>>> 2) Configure the port
>>>      - Change mode, set ddp_min, etc...
>>>
>>> 3) Start the port
>>>      - Begins discovery and/or login (depending on mode)
>>>
>>> 4) Destroy the port
>>>      - Logout and free all memory
>>
>> Robert, Can you please let me now what is the motivation for this
>> change and what problem are we solving with this approach? Is this
>> primarily to allow user to set the mode?
>>
>
> The main problem is that our control interfaces shouldn't be module
> parameters. I think of module parameters as things that globally alter
> the module.
>
> I also think that moving to a create/configure/start model gives us
> more flexibility going forward. We don't have too many FC/FCoE knobs to
> tune right now, but if we wanted to add more we don't have a good way
> to do it without starting the whole discovery/login process and then
> making changes during the discovery/login.
>
> I think the module parameter problem is the justification, but I'm
> trying to be comprehensive in coming up with a flexible interface that
> will allow us to evolve as well.
>
>> I'm concerned that we will be breaking user space compatibility with
>> this change, as there should be a corresponding fcoemon/fipvlan change
>> along with this, and existing utilities will not work.  Also the way
>> we start fcoe will be completely different and the user may need to do
>> the scripting changes, if any.
>
> See the last statement from my initial posting (it's below). I have
> patches to modify fcoemon to use these new interfaces. I'd be happy to
> share them, I just didn't want to spam this broad of a audience.
>
Thanks Robert for the explanation. Appreciate if you could share the 
fcoeutils patches also.

^ permalink raw reply

* RE: [net PATCH 3/7] bnx2x: prevent timeouts when using PFC
From: Yaniv Rosner @ 2012-09-11  5:49 UTC (permalink / raw)
  To: Yuval Mintz, davem@davemloft.net, netdev@vger.kernel.org
  Cc: Eilon Greenstein, Yuval Mintz
In-Reply-To: <1347292135-30250-4-git-send-email-yuvalmin@broadcom.com>

Ack

-----Original Message-----
From: Yuval Mintz [mailto:yuvalmin@broadcom.com] 
Sent: Monday, September 10, 2012 6:49 PM
To: davem@davemloft.net; netdev@vger.kernel.org
Cc: Eilon Greenstein; Yaniv Rosner; Yuval Mintz
Subject: [net PATCH 3/7] bnx2x: prevent timeouts when using PFC

From: Yaniv Rosner <yaniv.rosner@broadcom.com>

Prevent updating the xmac PFC configuration when using a link speed
slower than 10G -the umac block is responsible for 1G or slower connections,
therefore it is possible the xmac block is reset when connection is slower.

Signed-off-by: Yaniv Rosner <yaniv.rosner@broadcom.com>
Signed-off-by: Yuval Mintz <yuvalmin@broadcom.com>
Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
---
 drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c |    8 +++++---
 1 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
index f4beb46..40a7b8d 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
@@ -2667,9 +2667,11 @@ int bnx2x_update_pfc(struct link_params *params,
 		return bnx2x_status;
 
 	DP(NETIF_MSG_LINK, "About to update PFC in BMAC\n");
-	if (CHIP_IS_E3(bp))
-		bnx2x_update_pfc_xmac(params, vars, 0);
-	else {
+
+	if (CHIP_IS_E3(bp)) {
+		if (vars->mac_type == MAC_TYPE_XMAC)
+			bnx2x_update_pfc_xmac(params, vars, 0);
+	} else {
 		val = REG_RD(bp, MISC_REG_RESET_REG_2);
 		if ((val &
 		     (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << params->port))
-- 
1.7.9.rc2

^ permalink raw reply related

* Recall: [net PATCH 3/7] bnx2x: prevent timeouts when using PFC
From: Yaniv Rosner @ 2012-09-11  5:50 UTC (permalink / raw)
  To: Yuval Mintz, davem@davemloft.net, netdev@vger.kernel.org
  Cc: Eilon Greenstein, Yuval Mintz

Yaniv Rosner would like to recall the message, "[net PATCH 3/7] bnx2x: prevent timeouts when using PFC".

^ permalink raw reply

* Re: [RFC PATCH 1/5] libfcoe, fcoe: Allow user to set a ctlr's mode
From: Bart Van Assche @ 2012-09-11  5:51 UTC (permalink / raw)
  To: Robert Love; +Cc: netdev, gregkh, linux-scsi, bprakash, devel
In-Reply-To: <20120910225914.13140.22190.stgit@fritz>

On 09/11/12 00:59, Robert Love wrote:
> +static enum fip_conn_type fcoe_parse_mode(const char *buf,
> +				  const struct fcoe_ctlr_mode_table *tbl)
> +{
> +	int modeint = -1, i, rv;
> +	char *p, modestr[FCOE_MAX_MODENAME_LEN + 1] = { 0, };
> +
> +	for (p = (char *)buf; *p; p++)
> +		if (!(isdigit(*p) || isspace(*p)))
> +			break;

If you change the declaration of p from "char *p" into "const char *p"
you won't need a cast in the above for loop.

[ ... ]

> -static FCOE_DEVICE_ATTR(ctlr, mode, S_IRUGO,
> -			show_ctlr_mode, NULL);
> +
> +static ssize_t store_ctlr_mode(struct device *dev,
> +			       struct device_attribute *attr,
> +			       const char *buf, size_t count)
> +{
> +	struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev);
> +
> +	if (!ctlr->f->set_fcoe_ctlr_mode)
> +		return -EINVAL;
> +
> +	ctlr->mode = fcoe_parse_mode(buf, ctlr_mode_tbl);

As far as I know sysfs doesn't terminate buf with a '\0' before calling
a store method. Does that mean that you are passing a string that is not
'\0'-terminated to a function that expects a '\0'-terminated string ?

Bart.

^ permalink raw reply

* Re: Recall: [net PATCH 3/7] bnx2x: prevent timeouts when using PFC
From: David Miller @ 2012-09-11  5:57 UTC (permalink / raw)
  To: yaniv.rosner; +Cc: yuvalmin, netdev, eilong
In-Reply-To: <A6AA2EF896BED345B0F23520D832A4B10B73BF@SJEXCHMB05.corp.ad.broadcom.com>

From: "Yaniv Rosner" <yaniv.rosner@broadcom.com>
Date: Tue, 11 Sep 2012 05:50:04 +0000

> Yaniv Rosner would like to recall the message, "[net PATCH 3/7]
> bnx2x: prevent timeouts when using PFC".

What in the world are you doing?

^ permalink raw reply

* Re: [PATCH v3 0/7] mv643xx.c: Add basic device tree support.
From: Benjamin Herrenschmidt @ 2012-09-11  6:03 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	andrew-g2DYL2Zd6BY, netdev-u79uwXL29TY76Z2rM5mHXA,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ,
	ben.dooks-4yDnlxn2s6sWdaTGBSpHTA, dale-1viX+2+OPRFcxvNqPlePQg,
	Ian Molton, David Miller,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <201209101422.13875.arnd-r2nGTMty4D4@public.gmane.org>

On Mon, 2012-09-10 at 14:22 +0000, Arnd Bergmann wrote:
> Following up on the old discussion, I talked briefly about this
> issue with BenH at the kernel summit. The outcome basically is that
> it's a bit sad to have incompatible bindings, but it's not the end
> of the world,and it's more important to do it right this time.
> 
> Just make sure that you use different values for the 'compatible'
> strings and then do what you need to get the ARM hardware working.
> 
> Ideally, the new binding should be written in a way that powerpc
> machines can use the same one, but the existing ones all use
> an version of Open Firmware that is not going to get updated
> and it's also not too likely that we are going to see new
> powerpc machines based on this chip.

Right, mostly these machines where the Pegasos. Those came with a fairly
busted variant of Open Firmware which generated a pretty gross
device-tree.

For some reason, the manufacturer of those things was never willing to
fix anything in their firmware (despite the distributor providing
patches etc...), seemingly on the assumption that whatever they were
doing was perfect and operating system people like us didn't matter one
little bit :-)

So I don't care much about it. It would be nice to keep them working
since people in the community still have them but if it goes through
some "compat" code that detects old/broken device-trees and eventually
disappears when we finally drop support, then so be it.

Cheers,
Ben.

^ permalink raw reply

* Re: [PATCH 0/12] qlcnic: patches for new adapter - Qlogic 83XX CNA
From: Francois Romieu @ 2012-09-11  6:01 UTC (permalink / raw)
  To: Sony Chacko; +Cc: davem, netdev, Dept_NX_Linux_NIC_Driver
In-Reply-To: <1347326403-1705-1-git-send-email-sony.chacko@qlogic.com>

Sony Chacko <sony.chacko@qlogic.com> :
[...]
> We have updated the patches.
> Please apply the updated 12 patch series to net-next.

Please consider including a submission count in the subject. A formal
changelog in message #0 will be welcome too.

<my life>
Spliting the patches further would help review.
</my life>

-- 
Ueimor

^ permalink raw reply

* Re: [PATCH 01/12] qlcnic: Refactoring - template based hardware interface
From: Francois Romieu @ 2012-09-11  6:01 UTC (permalink / raw)
  To: Sony Chacko; +Cc: davem, netdev, Dept_NX_Linux_NIC_Driver, Anirban Chakraborty
In-Reply-To: <1347326403-1705-2-git-send-email-sony.chacko@qlogic.com>

Sony Chacko <sony.chacko@qlogic.com> :
> Modify 82xx driver to support new adapter - Qlogic 83XX CNA
> Separate adapter specific hardware accesses routines
> Create template based hardware interface
> 
> Signed-off-by: Anirban Chakraborty <anirban.chakraborty@qlogic.com>
> Signed-off-by: Sony Chacko <sony.chacko@qlogic.com>
> ---
>  drivers/net/ethernet/qlogic/qlcnic/qlcnic.h        |   67 ++++-
>  drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c    |    4 +-
>  .../net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c    |   32 ++-
>  drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h    |   55 +---
>  drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c     |  125 ++++++--
>  drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h     |   36 +++
>  drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c   |    1 +
>  drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c   |  309 +++++++++-----------
>  8 files changed, 359 insertions(+), 270 deletions(-)
>  create mode 100644 drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
> 
> diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
> index eaa1db9..a4ae965 100644
> --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
> +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
> @@ -439,6 +439,8 @@ struct qlcnic_fw_dump {
>  	struct	qlcnic_dump_template_hdr *tmpl_hdr;
>  };
>  
> +struct qlcnic_hardware_ops;
> +

qlcnic_hardware_ops is defined in this same file and it only uses
pointers to yet unknown types. You can define it here.

[...]
> @@ -552,8 +556,9 @@ struct qlcnic_recv_context {
>  /* 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_SIGNATURE_MAKE(ahw)					\
> +	(((ahw->pci_func) & 0xff) | (((ahw->fw_hal_version) &		\
> +	0xff) << 8) | (0xcafe << 16))

It could be a proper function and it could belong to the (only) file where
it is actually used (once).

[...]
> +static inline void
> +qlcnic_read_crb(struct qlcnic_adapter *adapter, char *buf,
> +		loff_t offset, size_t size)

?

static inline void qlcnic_read_crb(struct qlcnic_adapter *adapter, char *buf,
				   loff_t offset, size_t size)

[...]
> diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
> index 9e9e78a..c81fcf8 100644
> --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
> +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
[...]
> @@ -603,8 +608,7 @@ qlcnic_set_pauseparam(struct net_device *netdev,
>  		else
>  			qlcnic_gb_unset_rx_flowctl(val);
>  
> -		QLCWR32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port),
> -				val);
> +		QLCWR32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port), val);

This change does not fit the patch description.

[...]
> diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h
> index 28a6b28..0bee9f7 100644
> --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h
> +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h
[...]

Most of the changes in this file does not fit the patch description.

You could as well make a separate patch dedicated to removing unused stuff.

5...]
> diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
> index b528e52..ee4cd43 100644
> --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
> +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
[...]
> @@ -880,7 +889,7 @@ qlcnic_pci_get_crb_addr_2M(struct qlcnic_adapter *adapter,
>  	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 +
> +		*addr = ahw->pci_base0 + m->start_2M +
>  			(off - m->start_128M);

		*addr = ahw->pci_base0 + m->start_2M + off - m->start_128M;

[...]
> @@ -1105,7 +1116,7 @@ correct:
>  	i = 0;
>  	writel(TA_CTL_ENABLE, (mem_crb + TEST_AGT_CTRL));
>  	writel((TA_CTL_START | TA_CTL_ENABLE),
> -			(mem_crb + TEST_AGT_CTRL));
> +	       (mem_crb + TEST_AGT_CTRL));

  	writel(TA_CTL_START | TA_CTL_ENABLE, mem_crb + TEST_AGT_CTRL);

The topic of the patch does not ask for a change here and these lines
don't even appear in the context diff of such changes. It could be
isolated in a separate patch (where you would probably be suggested to
remove the useless parenthesis in "(TA_CTL_START | TA_CTL_ENABLE)" as well).

[...]
> @@ -1786,3 +1800,54 @@ error:
>  	vfree(fw_dump->data);
>  	return -EINVAL;
>  }
> +
> +void qlcnic_get_func_no(struct qlcnic_adapter *adapter)
> +{
> +	void __iomem *msix_base_addr;
> +	u32 func;
> +	u32 msix_base;
> +
> +	pci_read_config_dword(adapter->pdev, QLCNIC_MSIX_TABLE_OFFSET, &func);
> +	msix_base_addr = adapter->ahw->pci_base0 + QLCNIC_MSIX_BASE;
> +	msix_base = readl(msix_base_addr);
> +	func = (func - msix_base)/QLCNIC_MSIX_TBL_PGSIZE;
> +	adapter->ahw->pci_func = func;
> +}

It is not used in this patch. #2 adds a declaration for it in qlcnic.h, a
function pointer for it in qlcnic_hardware_ops, then uses it. #5 renames
it to qlcnic_82xx_get_func_no.

Reviewers won't complain if you keep the patchset at the smallest size
for a given set of changes, especially as the qlcnic_82xx_ prefix is
used a few lines below.

> +
> +void qlcnic_get_ocm_win(struct qlcnic_hardware_context *ahw)
> +{
> +	u32 addr;
> +
> +	addr = QLCNIC_PCIX_PS_REG(PCIX_OCM_WINDOW_REG(ahw->pci_func));
> +	ahw->ocm_win_crb = qlcnic_get_ioaddr(ahw, addr);
> +}

Either it's hidden behind some clever macro or it isn't used at all in
the whole patchset.

> +
> +void qlcnic_82xx_read_crb(struct qlcnic_adapter *adapter, char *buf,
> +			   loff_t offset, size_t size)
> +{
> +	u32 data;
> +	u64 qmdata;
> +
> +	if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM, QLCNIC_PCI_CAMQM_END)) {
> +		qlcnic_pci_camqm_read_2M(adapter, offset, &qmdata);
> +		memcpy(buf, &qmdata, size);
> +	} else {
> +		data = QLCRD32(adapter, offset);
> +		memcpy(buf, &data, size);
> +	}
> +}

Nit: reduce the scope of data and qmdata.

[...]
> diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
> new file mode 100644
> index 0000000..7dab9e2
> --- /dev/null
> +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
> @@ -0,0 +1,36 @@
> +#ifndef __QLCNIC_HW_H
> +#define __QLCNIC_HW_H
> +
> +#include "qlcnic.h"
> +
> +/* List of PCI device IDs */
> +#define PCI_DEVICE_ID_QLOGIC_QLE824X  0x8020
> +#define QLCNIC_P3P_BAR0_LENGTH		0x00200000UL
> +
> +#define QLCNIC_BAR_LENGTH(dev_id, bar)			\
> +do {							\
> +	if (dev_id == PCI_DEVICE_ID_QLOGIC_QLE824X)\
> +		*bar = QLCNIC_P3P_BAR0_LENGTH;		\
> +	else						\
> +		*bar = 0;				\
> +} while (0)

It is used only once in the whole patchset.

> diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
> index 0bcda9c..350bf79 100644
> --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
> +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
[...]
> @@ -343,9 +312,9 @@ static const struct net_device_ops qlcnic_netdev_failed_ops = {
>  };
>  
>  static struct qlcnic_nic_template qlcnic_ops = {
> -	.config_bridged_mode = qlcnic_config_bridged_mode,
> -	.config_led = qlcnic_config_led,
> -	.start_firmware = qlcnic_start_firmware
> +	.config_bridged_mode = qlcnic_82xx_config_bridged_mode,
> +	.config_led = qlcnic_82xx_config_led,
> +	.start_firmware = qlcnic_82xx_start_firmware
>  };

You should really consider aligning as:

static struct qlcnic_nic_template qlcnic_ops = {
	.config_bridged_mode	= qlcnic_82xx_config_bridged_mode,
	.config_led		= qlcnic_82xx_config_led,
	.start_firmware		= qlcnic_82xx_start_firmware
};


(off to work)

-- 
Ueimor

^ permalink raw reply

* [net-next.git 0/8 (V4)] stmmac: remove dead code for STMMAC_TIMER and add new mitigation schema
From: Giuseppe CAVALLARO @ 2012-09-11  6:55 UTC (permalink / raw)
  To: netdev; +Cc: bhutchings, davem, Giuseppe Cavallaro

These patch series remove the STMMAC_TIMER option no longer updated
and never used and add a new mitigation schema.
Having removed the Timer opt, this has made the driver slim.
On top of this work, it has been easier to introduce the new
mitigation schema based on HW RX-watchdog (available in new cores).
In fact, 3.50 and newer cores have an HW RX-Watchdog that can be used for 
mitigating the Rx-interrupts and first results look promising.

Running n-u-t-t-c-p with the following parameters:

 Throughput: 500Mbps
 UDP Buffer size: 1328bytes
 TCP Buffer size: 65536bytes

for example, I got on ST box (arm-based) these improvements:

--------------------------------------------------------------------
      Original                   |     With New Mitigation patch
--------------------------------------------------------------------
 Test        CPU usage  pkt/loss |        CPU usage     pkt/loss
 Type  Mbps        %         %   |Mbps      %              %
--------------------------------------------------------------------
UDP-RX 395.5065 95       20.89   |499.9552  23        0.00
UDP-TX 499.5578 100     0.08915  |500.0152  100       0.00
TCP-RX 499.9221 77               |499.9217  27
TCP-TX 389.5719 99               |499.9171  80
--------------------------------------------------------------------

 ... no regression on ST boxes (SH based) I always test.

This is a brief explanation of the new mitigation schema although there
is a patch that updates the driver's documentation.

o On Rx-side I have:
  New GMACs will use the RX-watchdog timer; old ones will continue to
  use NAPI to mitigate the RX DMA interrupts.
  For the RX-watchdog, there is a parameter that is the RI Watchdog 
  Timer count. It indicates the number of system clock cycles and can be
  set via *ethtool*.

o On Tx-side, the mitigation schema is based on a SW timer
  that calls the tx function (stmmac_tx) to reclaim the resource after
  transmitting the frames.
  Also there is another parameter (a threshold) used to program
  the descriptors avoiding to set the interrupt on completion bit in
  when the frame is sent (xmit). This means that the stmmac_tx can be
  called by the ISR too. Also this parameter can be tuned via ethtool.

V2: these patches add the ethtool support to get/set coalesce parameters
and totally remove the sysFS support added in the first patches.

V3: added several fixes: for example NAPI and RX-watchdog work together
while in the previous implementation the HW  RX-watchdog disabled NAPI.
On the tx side, erroneously the tx coalesce frame parameter was limited
to the ring size and the driver didn't take care of the segment numbers
when enable/disable the IC bit in the TDES.

V4: reject not supported coalesce settings in ethtool.

Giuseppe Cavallaro (8):
  stmmac: remove dead code for TIMER
  stmmac: manage tx clean out of rx_poll
  stmmac: add the initial tx coalesce schema
  stmmac: add Rx watchdog support to mitigate the DMA irqs
  stmmac: get/set coalesce parameters via ethtool
  stmmac: fix and review the rx irq path after adding new mitigation
  stmmac: update the doc with new IRQ mitigation
  stmmac: update the driver version to Sept_2012

 Documentation/networking/stmmac.txt                |   28 ++-
 drivers/net/ethernet/stmicro/stmmac/Kconfig        |   25 --
 drivers/net/ethernet/stmicro/stmmac/Makefile       |    1 -
 drivers/net/ethernet/stmicro/stmmac/common.h       |   42 +++-
 drivers/net/ethernet/stmicro/stmmac/dwmac1000.h    |    3 -
 .../net/ethernet/stmicro/stmmac/dwmac1000_dma.c    |   10 +-
 drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c |    4 +-
 drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h    |    7 +-
 drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c    |   28 ++-
 drivers/net/ethernet/stmicro/stmmac/stmmac.h       |   14 +-
 .../net/ethernet/stmicro/stmmac/stmmac_ethtool.c   |  103 ++++++++-
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c  |  240 ++++++++------------
 drivers/net/ethernet/stmicro/stmmac/stmmac_timer.c |  134 -----------
 drivers/net/ethernet/stmicro/stmmac/stmmac_timer.h |   46 ----
 include/linux/stmmac.h                             |    1 +
 15 files changed, 280 insertions(+), 406 deletions(-)
 delete mode 100644 drivers/net/ethernet/stmicro/stmmac/stmmac_timer.c
 delete mode 100644 drivers/net/ethernet/stmicro/stmmac/stmmac_timer.h

-- 
1.7.4.4

^ permalink raw reply

* [net-next.git 1/8] stmmac: remove dead code for TIMER
From: Giuseppe CAVALLARO @ 2012-09-11  6:55 UTC (permalink / raw)
  To: netdev; +Cc: bhutchings, davem, Giuseppe Cavallaro
In-Reply-To: <1347346514-23411-1-git-send-email-peppe.cavallaro@st.com>

TIMER option is not longer supported and this
code can be considered dead for this driver in
the new kernel series.
In fact, It was not updated at all and never used.

Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
---
 drivers/net/ethernet/stmicro/stmmac/Kconfig        |   25 ----
 drivers/net/ethernet/stmicro/stmmac/Makefile       |    1 -
 drivers/net/ethernet/stmicro/stmmac/stmmac.h       |    6 -
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c  |  101 +--------------
 drivers/net/ethernet/stmicro/stmmac/stmmac_timer.c |  134 --------------------
 drivers/net/ethernet/stmicro/stmmac/stmmac_timer.h |   46 -------
 6 files changed, 3 insertions(+), 310 deletions(-)
 delete mode 100644 drivers/net/ethernet/stmicro/stmmac/stmmac_timer.c
 delete mode 100644 drivers/net/ethernet/stmicro/stmmac/stmmac_timer.h

diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
index 9f44827..1164930 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
@@ -54,31 +54,6 @@ config STMMAC_DA
 	  By default, the DMA arbitration scheme is based on Round-robin
 	  (rx:tx priority is 1:1).
 
-config STMMAC_TIMER
-	bool "STMMAC Timer optimisation"
-	default n
-	depends on RTC_HCTOSYS_DEVICE
-	---help---
-	  Use an external timer for mitigating the number of network
-	  interrupts. Currently, for SH architectures, it is possible
-	  to use the TMU channel 2 and the SH-RTC device.
-
-choice
-        prompt "Select Timer device"
-        depends on STMMAC_TIMER
-
-config STMMAC_TMU_TIMER
-        bool "TMU channel 2"
-        depends on CPU_SH4
-	---help---
-
-config STMMAC_RTC_TIMER
-        bool "Real time clock"
-        depends on RTC_CLASS
-	---help---
-
-endchoice
-
 choice
 	prompt "Select the DMA TX/RX descriptor operating modes"
 	depends on STMMAC_ETH
diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
index bc965ac..c8e8ea6 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -1,5 +1,4 @@
 obj-$(CONFIG_STMMAC_ETH) += stmmac.o
-stmmac-$(CONFIG_STMMAC_TIMER) += stmmac_timer.o
 stmmac-$(CONFIG_STMMAC_RING) += ring_mode.o
 stmmac-$(CONFIG_STMMAC_CHAINED) += chain_mode.o
 stmmac-$(CONFIG_STMMAC_PLATFORM) += stmmac_platform.o
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index e872e1d..9f35769 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -31,9 +31,6 @@
 #include <linux/phy.h>
 #include <linux/pci.h>
 #include "common.h"
-#ifdef CONFIG_STMMAC_TIMER
-#include "stmmac_timer.h"
-#endif
 
 struct stmmac_priv {
 	/* Frequently used values are kept adjacent for cache effect */
@@ -78,9 +75,6 @@ struct stmmac_priv {
 	spinlock_t tx_lock;
 	int wolopts;
 	int wol_irq;
-#ifdef CONFIG_STMMAC_TIMER
-	struct stmmac_timer *tm;
-#endif
 	struct plat_stmmacenet_data *plat;
 	struct stmmac_counters mmc;
 	struct dma_features dma_cap;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index c136162..c8985f3 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -115,16 +115,6 @@ static int tc = TC_DEFAULT;
 module_param(tc, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(tc, "DMA threshold control value");
 
-/* Pay attention to tune this parameter; take care of both
- * hardware capability and network stabitily/performance impact.
- * Many tests showed that ~4ms latency seems to be good enough. */
-#ifdef CONFIG_STMMAC_TIMER
-#define DEFAULT_PERIODIC_RATE	256
-static int tmrate = DEFAULT_PERIODIC_RATE;
-module_param(tmrate, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(tmrate, "External timer freq. (default: 256Hz)");
-#endif
-
 #define DMA_BUFFER_SIZE	BUF_SIZE_2KiB
 static int buf_sz = DMA_BUFFER_SIZE;
 module_param(buf_sz, int, S_IRUGO | S_IWUSR);
@@ -536,12 +526,6 @@ static void init_dma_desc_rings(struct net_device *dev)
 	else
 		bfsize = stmmac_set_bfsize(dev->mtu, priv->dma_buf_sz);
 
-#ifdef CONFIG_STMMAC_TIMER
-	/* Disable interrupts on completion for the reception if timer is on */
-	if (likely(priv->tm->enable))
-		dis_ic = 1;
-#endif
-
 	DBG(probe, INFO, "stmmac: txsize %d, rxsize %d, bfsize %d\n",
 	    txsize, rxsize, bfsize);
 
@@ -786,22 +770,12 @@ static void stmmac_tx(struct stmmac_priv *priv)
 
 static inline void stmmac_enable_irq(struct stmmac_priv *priv)
 {
-#ifdef CONFIG_STMMAC_TIMER
-	if (likely(priv->tm->enable))
-		priv->tm->timer_start(tmrate);
-	else
-#endif
-		priv->hw->dma->enable_dma_irq(priv->ioaddr);
+	priv->hw->dma->enable_dma_irq(priv->ioaddr);
 }
 
 static inline void stmmac_disable_irq(struct stmmac_priv *priv)
 {
-#ifdef CONFIG_STMMAC_TIMER
-	if (likely(priv->tm->enable))
-		priv->tm->timer_stop();
-	else
-#endif
-		priv->hw->dma->disable_dma_irq(priv->ioaddr);
+	priv->hw->dma->disable_dma_irq(priv->ioaddr);
 }
 
 static int stmmac_has_work(struct stmmac_priv *priv)
@@ -829,25 +803,6 @@ static inline void _stmmac_schedule(struct stmmac_priv *priv)
 	}
 }
 
-#ifdef CONFIG_STMMAC_TIMER
-void stmmac_schedule(struct net_device *dev)
-{
-	struct stmmac_priv *priv = netdev_priv(dev);
-
-	priv->xstats.sched_timer_n++;
-
-	_stmmac_schedule(priv);
-}
-
-static void stmmac_no_timer_started(unsigned int x)
-{;
-};
-
-static void stmmac_no_timer_stopped(void)
-{;
-};
-#endif
-
 /**
  * stmmac_tx_err:
  * @priv: pointer to the private device structure
@@ -1049,23 +1004,6 @@ static int stmmac_open(struct net_device *dev)
 	struct stmmac_priv *priv = netdev_priv(dev);
 	int ret;
 
-#ifdef CONFIG_STMMAC_TIMER
-	priv->tm = kzalloc(sizeof(struct stmmac_timer *), GFP_KERNEL);
-	if (unlikely(priv->tm == NULL))
-		return -ENOMEM;
-
-	priv->tm->freq = tmrate;
-
-	/* Test if the external timer can be actually used.
-	 * In case of failure continue without timer. */
-	if (unlikely((stmmac_open_ext_timer(dev, priv->tm)) < 0)) {
-		pr_warning("stmmaceth: cannot attach the external timer.\n");
-		priv->tm->freq = 0;
-		priv->tm->timer_start = stmmac_no_timer_started;
-		priv->tm->timer_stop = stmmac_no_timer_stopped;
-	} else
-		priv->tm->enable = 1;
-#endif
 	clk_enable(priv->stmmac_clk);
 
 	stmmac_check_ether_addr(priv);
@@ -1152,10 +1090,6 @@ static int stmmac_open(struct net_device *dev)
 	priv->hw->dma->start_tx(priv->ioaddr);
 	priv->hw->dma->start_rx(priv->ioaddr);
 
-#ifdef CONFIG_STMMAC_TIMER
-	priv->tm->timer_start(tmrate);
-#endif
-
 	/* Dump DMA/MAC registers */
 	if (netif_msg_hw(priv)) {
 		priv->hw->mac->dump_regs(priv->ioaddr);
@@ -1182,9 +1116,6 @@ open_error_wolirq:
 	free_irq(dev->irq, dev);
 
 open_error:
-#ifdef CONFIG_STMMAC_TIMER
-	kfree(priv->tm);
-#endif
 	if (priv->phydev)
 		phy_disconnect(priv->phydev);
 
@@ -1215,12 +1146,6 @@ static int stmmac_release(struct net_device *dev)
 
 	netif_stop_queue(dev);
 
-#ifdef CONFIG_STMMAC_TIMER
-	/* Stop and release the timer */
-	stmmac_close_ext_timer();
-	if (priv->tm != NULL)
-		kfree(priv->tm);
-#endif
 	napi_disable(&priv->napi);
 	skb_queue_purge(&priv->rx_recycle);
 
@@ -1336,12 +1261,6 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
 	/* Interrupt on completition only for the latest segment */
 	priv->hw->desc->close_tx_desc(desc);
 
-#ifdef CONFIG_STMMAC_TIMER
-	/* Clean IC while using timer */
-	if (likely(priv->tm->enable))
-		priv->hw->desc->clear_tx_ic(desc);
-#endif
-
 	wmb();
 
 	/* To avoid raise condition */
@@ -1539,7 +1458,7 @@ static int stmmac_poll(struct napi_struct *napi, int budget)
  *  stmmac_tx_timeout
  *  @dev : Pointer to net device structure
  *  Description: this function is called when a packet transmission fails to
- *   complete within a reasonable tmrate. The driver will mark the error in the
+ *   complete within a reasonable time. The driver will mark the error in the
  *   netdev structure and arrange for the device to be reset to a sane state
  *   in order to transmit a new packet.
  */
@@ -2157,11 +2076,6 @@ int stmmac_suspend(struct net_device *ndev)
 	netif_device_detach(ndev);
 	netif_stop_queue(ndev);
 
-#ifdef CONFIG_STMMAC_TIMER
-	priv->tm->timer_stop();
-	if (likely(priv->tm->enable))
-		dis_ic = 1;
-#endif
 	napi_disable(&priv->napi);
 
 	/* Stop TX/RX DMA */
@@ -2212,10 +2126,6 @@ int stmmac_resume(struct net_device *ndev)
 	priv->hw->dma->start_tx(priv->ioaddr);
 	priv->hw->dma->start_rx(priv->ioaddr);
 
-#ifdef CONFIG_STMMAC_TIMER
-	if (likely(priv->tm->enable))
-		priv->tm->timer_start(tmrate);
-#endif
 	napi_enable(&priv->napi);
 
 	netif_start_queue(ndev);
@@ -2311,11 +2221,6 @@ static int __init stmmac_cmdline_opt(char *str)
 		} else if (!strncmp(opt, "eee_timer:", 6)) {
 			if (kstrtoint(opt + 10, 0, &eee_timer))
 				goto err;
-#ifdef CONFIG_STMMAC_TIMER
-		} else if (!strncmp(opt, "tmrate:", 7)) {
-			if (kstrtoint(opt + 7, 0, &tmrate))
-				goto err;
-#endif
 		}
 	}
 	return 0;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_timer.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_timer.c
deleted file mode 100644
index 2a0e1ab..0000000
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_timer.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/*******************************************************************************
-  STMMAC external timer support.
-
-  Copyright (C) 2007-2009  STMicroelectronics Ltd
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
-*******************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/etherdevice.h>
-#include "stmmac_timer.h"
-
-static void stmmac_timer_handler(void *data)
-{
-	struct net_device *dev = (struct net_device *)data;
-
-	stmmac_schedule(dev);
-}
-
-#define STMMAC_TIMER_MSG(timer, freq) \
-printk(KERN_INFO "stmmac_timer: %s Timer ON (freq %dHz)\n", timer, freq);
-
-#if defined(CONFIG_STMMAC_RTC_TIMER)
-#include <linux/rtc.h>
-static struct rtc_device *stmmac_rtc;
-static rtc_task_t stmmac_task;
-
-static void stmmac_rtc_start(unsigned int new_freq)
-{
-	rtc_irq_set_freq(stmmac_rtc, &stmmac_task, new_freq);
-	rtc_irq_set_state(stmmac_rtc, &stmmac_task, 1);
-}
-
-static void stmmac_rtc_stop(void)
-{
-	rtc_irq_set_state(stmmac_rtc, &stmmac_task, 0);
-}
-
-int stmmac_open_ext_timer(struct net_device *dev, struct stmmac_timer *tm)
-{
-	stmmac_task.private_data = dev;
-	stmmac_task.func = stmmac_timer_handler;
-
-	stmmac_rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
-	if (stmmac_rtc == NULL) {
-		pr_err("open rtc device failed\n");
-		return -ENODEV;
-	}
-
-	rtc_irq_register(stmmac_rtc, &stmmac_task);
-
-	/* Periodic mode is not supported */
-	if ((rtc_irq_set_freq(stmmac_rtc, &stmmac_task, tm->freq) < 0)) {
-		pr_err("set periodic failed\n");
-		rtc_irq_unregister(stmmac_rtc, &stmmac_task);
-		rtc_class_close(stmmac_rtc);
-		return -1;
-	}
-
-	STMMAC_TIMER_MSG(CONFIG_RTC_HCTOSYS_DEVICE, tm->freq);
-
-	tm->timer_start = stmmac_rtc_start;
-	tm->timer_stop = stmmac_rtc_stop;
-
-	return 0;
-}
-
-int stmmac_close_ext_timer(void)
-{
-	rtc_irq_set_state(stmmac_rtc, &stmmac_task, 0);
-	rtc_irq_unregister(stmmac_rtc, &stmmac_task);
-	rtc_class_close(stmmac_rtc);
-	return 0;
-}
-
-#elif defined(CONFIG_STMMAC_TMU_TIMER)
-#include <linux/clk.h>
-#define TMU_CHANNEL "tmu2_clk"
-static struct clk *timer_clock;
-
-static void stmmac_tmu_start(unsigned int new_freq)
-{
-	clk_set_rate(timer_clock, new_freq);
-	clk_enable(timer_clock);
-}
-
-static void stmmac_tmu_stop(void)
-{
-	clk_disable(timer_clock);
-}
-
-int stmmac_open_ext_timer(struct net_device *dev, struct stmmac_timer *tm)
-{
-	timer_clock = clk_get(NULL, TMU_CHANNEL);
-
-	if (timer_clock == NULL)
-		return -1;
-
-	if (tmu2_register_user(stmmac_timer_handler, (void *)dev) < 0) {
-		timer_clock = NULL;
-		return -1;
-	}
-
-	STMMAC_TIMER_MSG("TMU2", tm->freq);
-	tm->timer_start = stmmac_tmu_start;
-	tm->timer_stop = stmmac_tmu_stop;
-
-	return 0;
-}
-
-int stmmac_close_ext_timer(void)
-{
-	clk_disable(timer_clock);
-	tmu2_unregister_user();
-	clk_put(timer_clock);
-	return 0;
-}
-#endif
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_timer.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_timer.h
deleted file mode 100644
index aea9b14..0000000
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_timer.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*******************************************************************************
-  STMMAC external timer Header File.
-
-  Copyright (C) 2007-2009  STMicroelectronics Ltd
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
-*******************************************************************************/
-#ifndef __STMMAC_TIMER_H__
-#define __STMMAC_TIMER_H__
-
-struct stmmac_timer {
-	void (*timer_start) (unsigned int new_freq);
-	void (*timer_stop) (void);
-	unsigned int freq;
-	unsigned int enable;
-};
-
-/* Open the HW timer device and return 0 in case of success */
-int stmmac_open_ext_timer(struct net_device *dev, struct stmmac_timer *tm);
-/* Stop the timer and release it */
-int stmmac_close_ext_timer(void);
-/* Function used for scheduling task within the stmmac */
-void stmmac_schedule(struct net_device *dev);
-
-#if defined(CONFIG_STMMAC_TMU_TIMER)
-extern int tmu2_register_user(void *fnt, void *data);
-extern void tmu2_unregister_user(void);
-#endif
-
-#endif /* __STMMAC_TIMER_H__ */
-- 
1.7.4.4

^ permalink raw reply related

* [net-next.git 2/8 (V2)] stmmac: manage tx clean out of rx_poll
From: Giuseppe CAVALLARO @ 2012-09-11  6:55 UTC (permalink / raw)
  To: netdev; +Cc: bhutchings, davem, Giuseppe Cavallaro
In-Reply-To: <1347346514-23411-1-git-send-email-peppe.cavallaro@st.com>

This patch is to invoke the stmmac_tx (tx handler)
out of the NAPI poll method.
This will make easier the next step to add the new
mitigation schema.
Also the patch enhances the ethtool to report some
stats for normal TX and RX IRQs.

V2: use status & handle_rx/tx

Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
---
 drivers/net/ethernet/stmicro/stmmac/common.h       |   13 +++++++----
 drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c    |    7 +++--
 .../net/ethernet/stmicro/stmmac/stmmac_ethtool.c   |    4 ++-
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c  |   22 ++++++++++++++-----
 4 files changed, 31 insertions(+), 15 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index 719be39..bd32fe6 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -95,7 +95,9 @@ struct stmmac_extra_stats {
 	unsigned long threshold;
 	unsigned long tx_pkt_n;
 	unsigned long rx_pkt_n;
-	unsigned long poll_n;
+	unsigned long rx_napi_poll;
+	unsigned long rx_normal_irq_n;
+	unsigned long tx_normal_irq_n;
 	unsigned long sched_timer_n;
 	unsigned long normal_irq_n;
 	unsigned long mmc_tx_irq_n;
@@ -169,10 +171,11 @@ enum rx_frame_status { /* IPC status */
 	llc_snap = 4,
 };
 
-enum tx_dma_irq_status {
-	tx_hard_error = 1,
-	tx_hard_error_bump_tc = 2,
-	handle_tx_rx = 3,
+enum dma_irq_status {
+	tx_hard_error = 0x1,
+	tx_hard_error_bump_tc = 0x2,
+	handle_rx = 0x4,
+	handle_tx = 0x8,
 };
 
 enum core_specific_irq_mask {
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
index 4e0e18a..73766e6 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
@@ -206,9 +206,10 @@ int dwmac_dma_interrupt(void __iomem *ioaddr,
 	/* TX/RX NORMAL interrupts */
 	if (intr_status & DMA_STATUS_NIS) {
 		x->normal_irq_n++;
-		if (likely((intr_status & DMA_STATUS_RI) ||
-			 (intr_status & (DMA_STATUS_TI))))
-				ret = handle_tx_rx;
+		if (likely(intr_status & DMA_STATUS_RI))
+			ret |= handle_rx;
+		if (intr_status & (DMA_STATUS_TI))
+			ret |= handle_tx;
 	}
 	/* Optional hardware blocks, interrupts should be disabled */
 	if (unlikely(intr_status &
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index 76fd61a..505fe71 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -90,7 +90,9 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = {
 	STMMAC_STAT(threshold),
 	STMMAC_STAT(tx_pkt_n),
 	STMMAC_STAT(rx_pkt_n),
-	STMMAC_STAT(poll_n),
+	STMMAC_STAT(rx_napi_poll),
+	STMMAC_STAT(rx_normal_irq_n),
+	STMMAC_STAT(tx_normal_irq_n),
 	STMMAC_STAT(sched_timer_n),
 	STMMAC_STAT(normal_irq_n),
 	STMMAC_STAT(normal_irq_n),
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index c8985f3..8e1e53e 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -824,16 +824,27 @@ static void stmmac_tx_err(struct stmmac_priv *priv)
 	netif_wake_queue(priv->dev);
 }
 
+static inline void stmmac_rx_schedule(struct stmmac_priv *priv)
+{
+	if (likely(napi_schedule_prep(&priv->napi))) {
+		stmmac_disable_irq(priv);
+		__napi_schedule(&priv->napi);
+	}
+}
 
 static void stmmac_dma_interrupt(struct stmmac_priv *priv)
 {
 	int status;
 
 	status = priv->hw->dma->dma_interrupt(priv->ioaddr, &priv->xstats);
-	if (likely(status == handle_tx_rx))
-		_stmmac_schedule(priv);
-
-	else if (unlikely(status == tx_hard_error_bump_tc)) {
+	if (likely(status & handle_rx)) {
+		priv->xstats.rx_normal_irq_n++;
+		stmmac_rx_schedule(priv);
+	}
+	if (likely(status & handle_tx)) {
+		priv->xstats.tx_normal_irq_n++;
+		stmmac_tx(priv);
+	} else if (unlikely(status & tx_hard_error_bump_tc)) {
 		/* Try to bump up the dma threshold on this failure */
 		if (unlikely(tc != SF_DMA_MODE) && (tc <= 256)) {
 			tc += 64;
@@ -1443,8 +1454,7 @@ static int stmmac_poll(struct napi_struct *napi, int budget)
 	struct stmmac_priv *priv = container_of(napi, struct stmmac_priv, napi);
 	int work_done = 0;
 
-	priv->xstats.poll_n++;
-	stmmac_tx(priv);
+	priv->xstats.rx_napi_poll++;
 	work_done = stmmac_rx(priv, budget);
 
 	if (work_done < budget) {
-- 
1.7.4.4

^ permalink raw reply related

* [net-next.git 3/8 (V2)] stmmac: add the initial tx coalesce schema
From: Giuseppe CAVALLARO @ 2012-09-11  6:55 UTC (permalink / raw)
  To: netdev; +Cc: bhutchings, davem, Giuseppe Cavallaro
In-Reply-To: <1347346514-23411-1-git-send-email-peppe.cavallaro@st.com>

This patch adds a new schema used for mitigating the
number of transmit interrupts.
It is based on a sw timer and a threshold value.
The timer is used to periodically call the stmmac_tx
function that can be invoked by the ISR but only for
the descriptors where the interrupt on completion
field has been set. This is tuned by a threshold.

Next step is to add the ability to tune these coalesce
values by ethtool.

Till now I have put a default that showed a real gain
on all the platforms ARM/SH4 where I performed benchmarks.

V2: review the logic to manage the IC bit in the TDESC
that was bugged because it didn't take care about the
fragments. Also fix the tx_count_frames that has not to be
limited to TX DMA ring. Thanks to Ben Hutchings.

Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
---
 drivers/net/ethernet/stmicro/stmmac/common.h       |    8 +-
 drivers/net/ethernet/stmicro/stmmac/stmmac.h       |    4 +
 .../net/ethernet/stmicro/stmmac/stmmac_ethtool.c   |    9 +-
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c  |   92 ++++++++++++--------
 4 files changed, 69 insertions(+), 44 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index bd32fe6..1d6bd3e 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -95,11 +95,13 @@ struct stmmac_extra_stats {
 	unsigned long threshold;
 	unsigned long tx_pkt_n;
 	unsigned long rx_pkt_n;
-	unsigned long rx_napi_poll;
+	unsigned long normal_irq_n;
 	unsigned long rx_normal_irq_n;
+	unsigned long rx_napi_poll;
 	unsigned long tx_normal_irq_n;
-	unsigned long sched_timer_n;
-	unsigned long normal_irq_n;
+	unsigned long txtimer;
+	unsigned long tx_clean;
+	unsigned long tx_reset_ic_bit;
 	unsigned long mmc_tx_irq_n;
 	unsigned long mmc_rx_irq_n;
 	unsigned long mmc_rx_csum_offload_irq_n;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index 9f35769..0f5ab28 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -88,6 +88,10 @@ struct stmmac_priv {
 	int eee_enabled;
 	int eee_active;
 	int tx_lpi_timer;
+	struct timer_list txtimer;
+	u32 tx_count_frames;
+	u32 tx_coal_frames;
+	u32 tx_coal_timer;
 };
 
 extern int phyaddr;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index 505fe71..48ad0bc 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -90,12 +90,13 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = {
 	STMMAC_STAT(threshold),
 	STMMAC_STAT(tx_pkt_n),
 	STMMAC_STAT(rx_pkt_n),
-	STMMAC_STAT(rx_napi_poll),
+	STMMAC_STAT(normal_irq_n),
 	STMMAC_STAT(rx_normal_irq_n),
+	STMMAC_STAT(rx_napi_poll),
 	STMMAC_STAT(tx_normal_irq_n),
-	STMMAC_STAT(sched_timer_n),
-	STMMAC_STAT(normal_irq_n),
-	STMMAC_STAT(normal_irq_n),
+	STMMAC_STAT(txtimer),
+	STMMAC_STAT(tx_clean),
+	STMMAC_STAT(tx_reset_ic_bit),
 	STMMAC_STAT(mmc_tx_irq_n),
 	STMMAC_STAT(mmc_rx_irq_n),
 	STMMAC_STAT(mmc_rx_csum_offload_irq_n),
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 8e1e53e..3df3c3b 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -77,6 +77,8 @@
 
 #define STMMAC_ALIGN(x)	L1_CACHE_ALIGN(x)
 #define JUMBO_LEN	9000
+#define	STMMAC_TX_TM	40000
+#define STMMAC_TX_MAX_FRAMES	32	/* Max coalesced frame */
 
 /* Module parameters */
 #define TX_TIMEO 5000 /* default 5 seconds */
@@ -695,8 +697,11 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
 static void stmmac_tx(struct stmmac_priv *priv)
 {
 	unsigned int txsize = priv->dma_tx_size;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->tx_lock, flags);
 
-	spin_lock(&priv->tx_lock);
+	priv->xstats.tx_clean++;
 
 	while (priv->dirty_tx != priv->cur_tx) {
 		int last;
@@ -741,7 +746,7 @@ static void stmmac_tx(struct stmmac_priv *priv)
 				skb_recycle_check(skb, priv->dma_buf_sz))
 				__skb_queue_head(&priv->rx_recycle, skb);
 			else
-				dev_kfree_skb(skb);
+				dev_kfree_skb_any(skb);
 
 			priv->tx_skbuff[entry] = NULL;
 		}
@@ -765,7 +770,7 @@ static void stmmac_tx(struct stmmac_priv *priv)
 		stmmac_enable_eee_mode(priv);
 		mod_timer(&priv->eee_ctrl_timer, STMMAC_LPI_TIMER(eee_timer));
 	}
-	spin_unlock(&priv->tx_lock);
+	spin_unlock_irqrestore(&priv->tx_lock, flags);
 }
 
 static inline void stmmac_enable_irq(struct stmmac_priv *priv)
@@ -778,29 +783,12 @@ static inline void stmmac_disable_irq(struct stmmac_priv *priv)
 	priv->hw->dma->disable_dma_irq(priv->ioaddr);
 }
 
-static int stmmac_has_work(struct stmmac_priv *priv)
+static void stmmac_txtimer(unsigned long data)
 {
-	unsigned int has_work = 0;
-	int rxret, tx_work = 0;
-
-	rxret = priv->hw->desc->get_rx_owner(priv->dma_rx +
-		(priv->cur_rx % priv->dma_rx_size));
-
-	if (priv->dirty_tx != priv->cur_tx)
-		tx_work = 1;
-
-	if (likely(!rxret || tx_work))
-		has_work = 1;
+	struct stmmac_priv *priv = (struct stmmac_priv *)data;
 
-	return has_work;
-}
-
-static inline void _stmmac_schedule(struct stmmac_priv *priv)
-{
-	if (likely(stmmac_has_work(priv))) {
-		stmmac_disable_irq(priv);
-		napi_schedule(&priv->napi);
-	}
+	priv->xstats.txtimer++;
+	stmmac_tx(priv);
 }
 
 /**
@@ -824,7 +812,7 @@ static void stmmac_tx_err(struct stmmac_priv *priv)
 	netif_wake_queue(priv->dev);
 }
 
-static inline void stmmac_rx_schedule(struct stmmac_priv *priv)
+static void stmmac_rx_schedule(struct stmmac_priv *priv)
 {
 	if (likely(napi_schedule_prep(&priv->napi))) {
 		stmmac_disable_irq(priv);
@@ -1001,6 +989,18 @@ static int stmmac_init_dma_engine(struct stmmac_priv *priv)
 				   priv->dma_rx_phy);
 }
 
+static void stmmac_init_tx_coalesce(struct stmmac_priv *priv)
+{
+	/* Set Tx coalesce parameters and timers */
+	priv->tx_coal_frames = STMMAC_TX_MAX_FRAMES;
+	priv->tx_coal_timer = jiffies + usecs_to_jiffies(STMMAC_TX_TM);
+	init_timer(&priv->txtimer);
+	priv->txtimer.expires = priv->tx_coal_timer;
+	priv->txtimer.data = (unsigned long)priv;
+	priv->txtimer.function = stmmac_txtimer;
+	add_timer(&priv->txtimer);
+}
+
 /**
  *  stmmac_open - open entry point of the driver
  *  @dev : pointer to the device structure.
@@ -1113,6 +1113,8 @@ static int stmmac_open(struct net_device *dev)
 	priv->tx_lpi_timer = STMMAC_DEFAULT_TWT_LS_TIMER;
 	priv->eee_enabled = stmmac_eee_init(priv);
 
+	stmmac_init_tx_coalesce(priv);
+
 	napi_enable(&priv->napi);
 	skb_queue_head_init(&priv->rx_recycle);
 	netif_start_queue(dev);
@@ -1160,6 +1162,8 @@ static int stmmac_release(struct net_device *dev)
 	napi_disable(&priv->napi);
 	skb_queue_purge(&priv->rx_recycle);
 
+	del_timer_sync(&priv->txtimer);
+
 	/* Free the IRQ lines */
 	free_irq(dev->irq, dev);
 	if (priv->wol_irq != dev->irq)
@@ -1202,6 +1206,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
 	int nfrags = skb_shinfo(skb)->nr_frags;
 	struct dma_desc *desc, *first;
 	unsigned int nopaged_len = skb_headlen(skb);
+	unsigned long flags;
 
 	if (unlikely(stmmac_tx_avail(priv) < nfrags + 1)) {
 		if (!netif_queue_stopped(dev)) {
@@ -1213,7 +1218,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
 		return NETDEV_TX_BUSY;
 	}
 
-	spin_lock(&priv->tx_lock);
+	spin_lock_irqsave(&priv->tx_lock, flags);
 
 	if (priv->tx_path_in_lpi_mode)
 		stmmac_disable_eee_mode(priv);
@@ -1222,11 +1227,13 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
 
 #ifdef STMMAC_XMIT_DEBUG
 	if ((skb->len > ETH_FRAME_LEN) || nfrags)
-		pr_info("stmmac xmit:\n"
-		       "\tskb addr %p - len: %d - nopaged_len: %d\n"
-		       "\tn_frags: %d - ip_summed: %d - %s gso\n",
-		       skb, skb->len, nopaged_len, nfrags, skb->ip_summed,
-		       !skb_is_gso(skb) ? "isn't" : "is");
+		pr_debug("stmmac xmit: [entry %d]\n"
+			 "\tskb addr %p - len: %d - nopaged_len: %d\n"
+			 "\tn_frags: %d - ip_summed: %d - %s gso\n"
+			 "\ttx_count_frames %d\n", entry,
+			 skb, skb->len, nopaged_len, nfrags, skb->ip_summed,
+			 !skb_is_gso(skb) ? "isn't" : "is",
+			 priv->tx_count_frames);
 #endif
 
 	csum_insertion = (skb->ip_summed == CHECKSUM_PARTIAL);
@@ -1236,9 +1243,9 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
 
 #ifdef STMMAC_XMIT_DEBUG
 	if ((nfrags > 0) || (skb->len > ETH_FRAME_LEN))
-		pr_debug("stmmac xmit: skb len: %d, nopaged_len: %d,\n"
-		       "\t\tn_frags: %d, ip_summed: %d\n",
-		       skb->len, nopaged_len, nfrags, skb->ip_summed);
+		pr_debug("\tskb len: %d, nopaged_len: %d,\n"
+			 "\t\tn_frags: %d, ip_summed: %d\n",
+			 skb->len, nopaged_len, nfrags, skb->ip_summed);
 #endif
 	priv->tx_skbuff[entry] = skb;
 
@@ -1269,10 +1276,22 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
 		wmb();
 	}
 
-	/* Interrupt on completition only for the latest segment */
+	/* Finalize the latest segment. */
 	priv->hw->desc->close_tx_desc(desc);
 
 	wmb();
+	/* According to the coalesce parameter the IC bit for the latest
+	 * segment could be reset and the timer re-started to invoke the
+	 * stmmac_tx function. This approach takes care about the fragments. */
+	priv->tx_count_frames += nfrags + 1;
+	if (priv->tx_coal_frames > priv->tx_count_frames) {
+		priv->hw->desc->clear_tx_ic(desc);
+		priv->xstats.tx_reset_ic_bit++;
+		TX_DBG("\t[entry %d]: tx_count_frames %d\n", entry,
+		       priv->tx_count_frames);
+		mod_timer(&priv->txtimer, priv->tx_coal_timer);
+	} else
+		priv->tx_count_frames = 0;
 
 	/* To avoid raise condition */
 	priv->hw->desc->set_tx_owner(first);
@@ -1302,7 +1321,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
 
 	priv->hw->dma->enable_dma_transmission(priv->ioaddr);
 
-	spin_unlock(&priv->tx_lock);
+	spin_unlock_irqrestore(&priv->tx_lock, flags);
 
 	return NETDEV_TX_OK;
 }
@@ -1447,7 +1466,6 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
  *	      all interfaces.
  *  Description :
  *   This function implements the the reception process.
- *   Also it runs the TX completion thread
  */
 static int stmmac_poll(struct napi_struct *napi, int budget)
 {
-- 
1.7.4.4

^ permalink raw reply related

* [net-next.git 4/8 (V3)] stmmac: add Rx watchdog support to mitigate the DMA irqs
From: Giuseppe CAVALLARO @ 2012-09-11  6:55 UTC (permalink / raw)
  To: netdev; +Cc: bhutchings, davem, Giuseppe Cavallaro
In-Reply-To: <1347346514-23411-1-git-send-email-peppe.cavallaro@st.com>

GMAC devices newer than databook 3.40 has an embedded timer
that can be used for mitigating the number of interrupts.
So this patch adds this optimizations.
At any rate, the Rx watchdog can be disable (on bugged HW) by
passing from the platform the riwt_off field.

In this implementation the rx timer stored in the Reg9 is fixed
to the max value. Next step will be to tune it via ethtool.

V2: added a platform parameter to force to disable the rx-watchdog
for example on new core where it is bugged.

V3: do not disable NAPI when Rx watchdog is used.

Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
---
 drivers/net/ethernet/stmicro/stmmac/common.h       |    7 ++++
 drivers/net/ethernet/stmicro/stmmac/dwmac1000.h    |    3 --
 .../net/ethernet/stmicro/stmmac/dwmac1000_dma.c    |    6 +++
 drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h    |    3 +-
 drivers/net/ethernet/stmicro/stmmac/stmmac.h       |    1 +
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c  |   36 +++++++++++++++----
 include/linux/stmmac.h                             |    1 +
 7 files changed, 45 insertions(+), 12 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index 1d6bd3e..02eb2da 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -48,6 +48,10 @@
 #define CHIP_DBG(fmt, args...)  do { } while (0)
 #endif
 
+/* Synopsys Core versions */
+#define	DWMAC_CORE_3_40	0x34
+#define	DWMAC_CORE_3_50	0x35
+
 #undef FRAME_FILTER_DEBUG
 /* #define FRAME_FILTER_DEBUG */
 
@@ -165,6 +169,7 @@ struct stmmac_extra_stats {
 #define DMA_HW_FEAT_SAVLANINS	0x08000000 /* Source Addr or VLAN Insertion */
 #define DMA_HW_FEAT_ACTPHYIF	0x70000000 /* Active/selected PHY interface */
 #define DEFAULT_DMA_PBL		8
+#define DEFAULT_DMA_RIWT	0xff	/* Max RI Watchdog Timer count */
 
 enum rx_frame_status { /* IPC status */
 	good_frame = 0,
@@ -301,6 +306,8 @@ struct stmmac_dma_ops {
 			      struct stmmac_extra_stats *x);
 	/* If supported then get the optional core features */
 	unsigned int (*get_hw_feature) (void __iomem *ioaddr);
+	/* Program the HW RX Watchdog */
+	void (*rx_watchdog) (void __iomem *ioaddr, u32 riwt);
 };
 
 struct stmmac_ops {
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
index 0e4cace..7ad56af 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
@@ -230,8 +230,5 @@ enum rtc_control {
 #define GMAC_MMC_TX_INTR   0x108
 #define GMAC_MMC_RX_CSUM_OFFLOAD   0x208
 
-/* Synopsys Core versions */
-#define	DWMAC_CORE_3_40	0x34
-
 extern const struct stmmac_dma_ops dwmac1000_dma_ops;
 #endif /* __DWMAC1000_H__ */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
index 0335000..bf83c03 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
@@ -174,6 +174,11 @@ static unsigned int dwmac1000_get_hw_feature(void __iomem *ioaddr)
 	return readl(ioaddr + DMA_HW_FEATURE);
 }
 
+static void dwmac1000_rx_watchdog(void __iomem *ioaddr, u32 riwt)
+{
+	writel(riwt, ioaddr + DMA_RX_WATCHDOG);
+}
+
 const struct stmmac_dma_ops dwmac1000_dma_ops = {
 	.init = dwmac1000_dma_init,
 	.dump_regs = dwmac1000_dump_dma_regs,
@@ -187,4 +192,5 @@ const struct stmmac_dma_ops dwmac1000_dma_ops = {
 	.stop_rx = dwmac_dma_stop_rx,
 	.dma_interrupt = dwmac_dma_interrupt,
 	.get_hw_feature = dwmac1000_get_hw_feature,
+	.rx_watchdog = dwmac1000_rx_watchdog,
 };
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h b/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
index e49c9a0..4eeff5d 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
@@ -35,7 +35,8 @@
 #define DMA_CONTROL		0x00001018	/* Ctrl (Operational Mode) */
 #define DMA_INTR_ENA		0x0000101c	/* Interrupt Enable */
 #define DMA_MISSED_FRAME_CTR	0x00001020	/* Missed Frame Counter */
-#define DMA_AXI_BUS_MODE       0x00001028      /* AXI Bus Mode */
+#define DMA_RX_WATCHDOG		0x00001024	/* Receive Int Watchdog Timer */
+#define DMA_AXI_BUS_MODE	0x00001028      /* AXI Bus Mode */
 #define DMA_CUR_TX_BUF_ADDR	0x00001050	/* Current Host Tx Buffer */
 #define DMA_CUR_RX_BUF_ADDR	0x00001054	/* Current Host Rx Buffer */
 #define DMA_HW_FEATURE		0x00001058	/* HW Feature Register */
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index 0f5ab28..6901e3c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -89,6 +89,7 @@ struct stmmac_priv {
 	int eee_active;
 	int tx_lpi_timer;
 	struct timer_list txtimer;
+	int use_riwt;
 	u32 tx_count_frames;
 	u32 tx_coal_frames;
 	u32 tx_coal_timer;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 3df3c3b..8e610a1 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -133,6 +133,7 @@ MODULE_PARM_DESC(eee_timer, "LPI tx expiration time in msec");
 #define STMMAC_LPI_TIMER(x) (jiffies + msecs_to_jiffies(x))
 
 static irqreturn_t stmmac_interrupt(int irq, void *dev_id);
+static int stmmac_rx(struct stmmac_priv *priv, int limit);
 
 #ifdef CONFIG_STMMAC_DEBUG_FS
 static int stmmac_init_fs(struct net_device *dev);
@@ -603,6 +604,8 @@ static void init_dma_desc_rings(struct net_device *dev)
 	priv->dirty_tx = 0;
 	priv->cur_tx = 0;
 
+	if (priv->use_riwt)
+		dis_ic = 1;
 	/* Clear the Rx/Tx descriptors */
 	priv->hw->desc->init_rx_desc(priv->dma_rx, rxsize, dis_ic);
 	priv->hw->desc->init_tx_desc(priv->dma_tx, txsize);
@@ -812,7 +815,7 @@ static void stmmac_tx_err(struct stmmac_priv *priv)
 	netif_wake_queue(priv->dev);
 }
 
-static void stmmac_rx_schedule(struct stmmac_priv *priv)
+static void stmmac_rx_work(struct stmmac_priv *priv)
 {
 	if (likely(napi_schedule_prep(&priv->napi))) {
 		stmmac_disable_irq(priv);
@@ -827,7 +830,7 @@ static void stmmac_dma_interrupt(struct stmmac_priv *priv)
 	status = priv->hw->dma->dma_interrupt(priv->ioaddr, &priv->xstats);
 	if (likely(status & handle_rx)) {
 		priv->xstats.rx_normal_irq_n++;
-		stmmac_rx_schedule(priv);
+		stmmac_rx_work(priv);
 	}
 	if (likely(status & handle_tx)) {
 		priv->xstats.tx_normal_irq_n++;
@@ -1115,7 +1118,14 @@ static int stmmac_open(struct net_device *dev)
 
 	stmmac_init_tx_coalesce(priv);
 
+	if ((priv->use_riwt) && (priv->hw->dma->rx_watchdog))
+		/* Program RX Watchdog register to the default values
+		 * FIXME: provide user value for RIWT
+		 */
+		priv->hw->dma->rx_watchdog(priv->ioaddr, DEFAULT_DMA_RIWT);
+
 	napi_enable(&priv->napi);
+
 	skb_queue_head_init(&priv->rx_recycle);
 	netif_start_queue(dev);
 
@@ -1436,14 +1446,12 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
 #endif
 			skb->protocol = eth_type_trans(skb, priv->dev);
 
-			if (unlikely(!priv->plat->rx_coe)) {
-				/* No RX COE for old mac10/100 devices */
+			if (unlikely(!priv->plat->rx_coe))
 				skb_checksum_none_assert(skb);
-				netif_receive_skb(skb);
-			} else {
+			else
 				skb->ip_summed = CHECKSUM_UNNECESSARY;
-				napi_gro_receive(&priv->napi, skb);
-			}
+
+			napi_gro_receive(&priv->napi, skb);
 
 			priv->dev->stats.rx_packets++;
 			priv->dev->stats.rx_bytes += frame_len;
@@ -2013,6 +2021,15 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,
 	if (flow_ctrl)
 		priv->flow_ctrl = FLOW_AUTO;	/* RX/TX pause on */
 
+	/* Rx Watchdog is available in the COREs newer than the 3.40.
+	 * In some case, for example on bugged HW this feature
+	 * has to be disable and this can be done by passing the
+	 * riwt_off field from the platform. */
+	if ((priv->synopsys_id >= DWMAC_CORE_3_50) && (!priv->plat->riwt_off)) {
+		priv->use_riwt = 1;
+		pr_info(" Enable RX Mitigation via HW Watchdog Timer\n");
+	}
+
 	netif_napi_add(ndev, &priv->napi, stmmac_poll, 64);
 
 	spin_lock_init(&priv->lock);
@@ -2104,6 +2121,9 @@ int stmmac_suspend(struct net_device *ndev)
 	netif_device_detach(ndev);
 	netif_stop_queue(ndev);
 
+	if (priv->use_riwt)
+		dis_ic = 1;
+
 	napi_disable(&priv->napi);
 
 	/* Stop TX/RX DMA */
diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h
index a1547ea..de5b2f8 100644
--- a/include/linux/stmmac.h
+++ b/include/linux/stmmac.h
@@ -104,6 +104,7 @@ struct plat_stmmacenet_data {
 	int bugged_jumbo;
 	int pmt;
 	int force_sf_dma_mode;
+	int riwt_off;
 	void (*fix_mac_speed)(void *priv, unsigned int speed);
 	void (*bus_setup)(void __iomem *ioaddr);
 	int (*init)(struct platform_device *pdev);
-- 
1.7.4.4

^ permalink raw reply related

* [net-next.git 6/8] stmmac: fix and review the rx irq path after adding new mitigation
From: Giuseppe CAVALLARO @ 2012-09-11  6:55 UTC (permalink / raw)
  To: netdev; +Cc: bhutchings, davem, Giuseppe Cavallaro
In-Reply-To: <1347346514-23411-1-git-send-email-peppe.cavallaro@st.com>

After adopting the new mitigation approach I have
found a couple of problems in the rx irq path.
The enable/disable_dma_irq functions now are used for
handling the DMA_INTR_ENA_RIE bit in the DMA register 7.
So this patch masks the specific bit in this register.
Also these function names have been changed (to make clear
their meaning).
A new extra statistic field has been added to show the early
receive status in the interrupt handler as well. This has been
useful on debugging stage, indeed.
In the end, this patch also adds an extra check to avoid to call
napi_schedule when the DMA_INTR_ENA_RIE bit is disabled in the
Interrupt Mask register.

Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
---
 drivers/net/ethernet/stmicro/stmmac/common.h       |   12 +++++---
 .../net/ethernet/stmicro/stmmac/dwmac1000_dma.c    |    4 +-
 drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c |    4 +-
 drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h    |    4 +-
 drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c    |   27 ++++++++++++++-----
 .../net/ethernet/stmicro/stmmac/stmmac_ethtool.c   |    9 ++++--
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c  |   17 ++++--------
 7 files changed, 45 insertions(+), 32 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index b9033cc..9daa9df 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -85,7 +85,7 @@ struct stmmac_extra_stats {
 	unsigned long rx_missed_cntr;
 	unsigned long rx_overflow_cntr;
 	unsigned long rx_vlan;
-	/* Tx/Rx IRQ errors */
+	/* Tx/Rx IRQ error info */
 	unsigned long tx_undeflow_irq;
 	unsigned long tx_process_stopped_irq;
 	unsigned long tx_jabber_irq;
@@ -95,7 +95,8 @@ struct stmmac_extra_stats {
 	unsigned long rx_watchdog_irq;
 	unsigned long tx_early_irq;
 	unsigned long fatal_bus_error_irq;
-	/* Extra info */
+	/* Tx/Rx IRQ Events */
+	unsigned long rx_early_irq;
 	unsigned long threshold;
 	unsigned long tx_pkt_n;
 	unsigned long rx_pkt_n;
@@ -106,11 +107,12 @@ struct stmmac_extra_stats {
 	unsigned long txtimer;
 	unsigned long tx_clean;
 	unsigned long tx_reset_ic_bit;
+	unsigned long irq_receive_pmt_irq_n;
+	/* MMC info */
 	unsigned long mmc_tx_irq_n;
 	unsigned long mmc_rx_irq_n;
 	unsigned long mmc_rx_csum_offload_irq_n;
 	/* EEE */
-	unsigned long irq_receive_pmt_irq_n;
 	unsigned long irq_tx_path_in_lpi_mode_n;
 	unsigned long irq_tx_path_exit_lpi_mode_n;
 	unsigned long irq_rx_path_in_lpi_mode_n;
@@ -302,8 +304,8 @@ struct stmmac_dma_ops {
 	void (*dma_diagnostic_fr) (void *data, struct stmmac_extra_stats *x,
 				   void __iomem *ioaddr);
 	void (*enable_dma_transmission) (void __iomem *ioaddr);
-	void (*enable_dma_irq) (void __iomem *ioaddr);
-	void (*disable_dma_irq) (void __iomem *ioaddr);
+	void (*enable_rx_dma_irq) (void __iomem *ioaddr);
+	void (*disable_rx_dma_irq) (void __iomem *ioaddr);
 	void (*start_tx) (void __iomem *ioaddr);
 	void (*stop_tx) (void __iomem *ioaddr);
 	void (*start_rx) (void __iomem *ioaddr);
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
index bf83c03..9804e82 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
@@ -184,8 +184,8 @@ const struct stmmac_dma_ops dwmac1000_dma_ops = {
 	.dump_regs = dwmac1000_dump_dma_regs,
 	.dma_mode = dwmac1000_dma_operation_mode,
 	.enable_dma_transmission = dwmac_enable_dma_transmission,
-	.enable_dma_irq = dwmac_enable_dma_irq,
-	.disable_dma_irq = dwmac_disable_dma_irq,
+	.enable_rx_dma_irq = dwmac_enable_rx_dma_irq,
+	.disable_rx_dma_irq = dwmac_disable_rx_dma_irq,
 	.start_tx = dwmac_dma_start_tx,
 	.stop_tx = dwmac_dma_stop_tx,
 	.start_rx = dwmac_dma_start_rx,
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
index c2b4d55..81630c3 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
@@ -134,8 +134,8 @@ const struct stmmac_dma_ops dwmac100_dma_ops = {
 	.dma_mode = dwmac100_dma_operation_mode,
 	.dma_diagnostic_fr = dwmac100_dma_diagnostic_fr,
 	.enable_dma_transmission = dwmac_enable_dma_transmission,
-	.enable_dma_irq = dwmac_enable_dma_irq,
-	.disable_dma_irq = dwmac_disable_dma_irq,
+	.enable_rx_dma_irq = dwmac_enable_rx_dma_irq,
+	.disable_rx_dma_irq = dwmac_disable_rx_dma_irq,
 	.start_tx = dwmac_dma_start_tx,
 	.stop_tx = dwmac_dma_stop_tx,
 	.start_rx = dwmac_dma_start_rx,
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h b/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
index 4eeff5d..b91c8cf 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
@@ -105,8 +105,8 @@
 #define DMA_CONTROL_FTF		0x00100000 /* Flush transmit FIFO */
 
 extern void dwmac_enable_dma_transmission(void __iomem *ioaddr);
-extern void dwmac_enable_dma_irq(void __iomem *ioaddr);
-extern void dwmac_disable_dma_irq(void __iomem *ioaddr);
+extern void dwmac_enable_rx_dma_irq(void __iomem *ioaddr);
+extern void dwmac_disable_rx_dma_irq(void __iomem *ioaddr);
 extern void dwmac_dma_start_tx(void __iomem *ioaddr);
 extern void dwmac_dma_stop_tx(void __iomem *ioaddr);
 extern void dwmac_dma_start_rx(void __iomem *ioaddr);
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
index 73766e6..a650019 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
@@ -39,14 +39,20 @@ void dwmac_enable_dma_transmission(void __iomem *ioaddr)
 	writel(1, ioaddr + DMA_XMT_POLL_DEMAND);
 }
 
-void dwmac_enable_dma_irq(void __iomem *ioaddr)
+void dwmac_enable_rx_dma_irq(void __iomem *ioaddr)
 {
-	writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
+	u32 value = readl(ioaddr + DMA_INTR_ENA);
+
+	value |= DMA_INTR_ENA_RIE;
+	writel(value, ioaddr + DMA_INTR_ENA);
 }
 
-void dwmac_disable_dma_irq(void __iomem *ioaddr)
+void dwmac_disable_rx_dma_irq(void __iomem *ioaddr)
 {
-	writel(0, ioaddr + DMA_INTR_ENA);
+	u32 value = readl(ioaddr + DMA_INTR_ENA);
+
+	value &= ~DMA_INTR_ENA_RIE;
+	writel(value, ioaddr + DMA_INTR_ENA);
 }
 
 void dwmac_dma_start_tx(void __iomem *ioaddr)
@@ -206,15 +212,22 @@ int dwmac_dma_interrupt(void __iomem *ioaddr,
 	/* TX/RX NORMAL interrupts */
 	if (intr_status & DMA_STATUS_NIS) {
 		x->normal_irq_n++;
-		if (likely(intr_status & DMA_STATUS_RI))
-			ret |= handle_rx;
-		if (intr_status & (DMA_STATUS_TI))
+		if (likely(intr_status & DMA_STATUS_RI)) {
+			u32 value = readl(ioaddr + DMA_INTR_ENA);
+			/* to schedule NAPI on real RIE event. */
+			if (likely(value & DMA_INTR_ENA_RIE))
+				ret |= handle_rx;
+		}
+		if (intr_status & DMA_STATUS_TI)
 			ret |= handle_tx;
+		if (intr_status & DMA_STATUS_ERI)
+			x->rx_early_irq++;
 	}
 	/* Optional hardware blocks, interrupts should be disabled */
 	if (unlikely(intr_status &
 		     (DMA_STATUS_GPI | DMA_STATUS_GMI | DMA_STATUS_GLI)))
 		pr_info("%s: unexpected status %08x\n", __func__, intr_status);
+
 	/* Clear the interrupt by writing a logic 1 to the CSR5[15-0] */
 	writel((intr_status & 0x1ffff), ioaddr + DMA_STATUS);
 
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index d27cc18..1ea5520 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -76,7 +76,7 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = {
 	STMMAC_STAT(rx_missed_cntr),
 	STMMAC_STAT(rx_overflow_cntr),
 	STMMAC_STAT(rx_vlan),
-	/* Tx/Rx IRQ errors */
+	/* Tx/Rx IRQ error info */
 	STMMAC_STAT(tx_undeflow_irq),
 	STMMAC_STAT(tx_process_stopped_irq),
 	STMMAC_STAT(tx_jabber_irq),
@@ -86,7 +86,8 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = {
 	STMMAC_STAT(rx_watchdog_irq),
 	STMMAC_STAT(tx_early_irq),
 	STMMAC_STAT(fatal_bus_error_irq),
-	/* Extra info */
+	/* Tx/Rx IRQ Events */
+	STMMAC_STAT(rx_early_irq),
 	STMMAC_STAT(threshold),
 	STMMAC_STAT(tx_pkt_n),
 	STMMAC_STAT(rx_pkt_n),
@@ -97,10 +98,12 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = {
 	STMMAC_STAT(txtimer),
 	STMMAC_STAT(tx_clean),
 	STMMAC_STAT(tx_reset_ic_bit),
+	STMMAC_STAT(irq_receive_pmt_irq_n),
+	/* MMC info */
 	STMMAC_STAT(mmc_tx_irq_n),
 	STMMAC_STAT(mmc_rx_irq_n),
 	STMMAC_STAT(mmc_rx_csum_offload_irq_n),
-	STMMAC_STAT(irq_receive_pmt_irq_n),
+	/* EEE */
 	STMMAC_STAT(irq_tx_path_in_lpi_mode_n),
 	STMMAC_STAT(irq_tx_path_exit_lpi_mode_n),
 	STMMAC_STAT(irq_rx_path_in_lpi_mode_n),
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index b0731e6..0b37c6d 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -778,12 +778,12 @@ static void stmmac_tx(struct stmmac_priv *priv)
 
 static inline void stmmac_enable_irq(struct stmmac_priv *priv)
 {
-	priv->hw->dma->enable_dma_irq(priv->ioaddr);
+	priv->hw->dma->enable_rx_dma_irq(priv->ioaddr);
 }
 
 static inline void stmmac_disable_irq(struct stmmac_priv *priv)
 {
-	priv->hw->dma->disable_dma_irq(priv->ioaddr);
+	priv->hw->dma->disable_rx_dma_irq(priv->ioaddr);
 }
 
 static void stmmac_txtimer(unsigned long data)
@@ -815,14 +815,6 @@ static void stmmac_tx_err(struct stmmac_priv *priv)
 	netif_wake_queue(priv->dev);
 }
 
-static void stmmac_rx_work(struct stmmac_priv *priv)
-{
-	if (likely(napi_schedule_prep(&priv->napi))) {
-		stmmac_disable_irq(priv);
-		__napi_schedule(&priv->napi);
-	}
-}
-
 static void stmmac_dma_interrupt(struct stmmac_priv *priv)
 {
 	int status;
@@ -830,7 +822,10 @@ static void stmmac_dma_interrupt(struct stmmac_priv *priv)
 	status = priv->hw->dma->dma_interrupt(priv->ioaddr, &priv->xstats);
 	if (likely(status & handle_rx)) {
 		priv->xstats.rx_normal_irq_n++;
-		stmmac_rx_work(priv);
+		if (likely(napi_schedule_prep(&priv->napi))) {
+			stmmac_disable_irq(priv);
+			__napi_schedule(&priv->napi);
+		}
 	}
 	if (likely(status & handle_tx)) {
 		priv->xstats.tx_normal_irq_n++;
-- 
1.7.4.4

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox