[kernel] r16248 - in dists/sid/linux-2.6/debian: . patches/features/all patches/series

Dann Frazier dannf at alioth.debian.org
Wed Sep 8 21:39:19 UTC 2010


Author: dannf
Date: Wed Sep  8 21:39:07 2010
New Revision: 16248

Log:
netxen_nic: add support for loading unified firmware images

Added:
   dists/sid/linux-2.6/debian/patches/features/all/netxen-unified-fw-image.patch
Modified:
   dists/sid/linux-2.6/debian/changelog
   dists/sid/linux-2.6/debian/patches/series/22

Modified: dists/sid/linux-2.6/debian/changelog
==============================================================================
--- dists/sid/linux-2.6/debian/changelog	Tue Sep  7 01:17:59 2010	(r16247)
+++ dists/sid/linux-2.6/debian/changelog	Wed Sep  8 21:39:07 2010	(r16248)
@@ -52,6 +52,9 @@
     - kirkwood: Unbreak PCIe I/O port
     - Kirkwood: support for Seagate DockStar
 
+  [ dann frazier ]
+  * netxen_nic: add support for loading unified firmware images
+
  -- Ben Hutchings <ben at decadent.org.uk>  Fri, 27 Aug 2010 08:38:26 +0100
 
 linux-2.6 (2.6.32-21) unstable; urgency=high

Added: dists/sid/linux-2.6/debian/patches/features/all/netxen-unified-fw-image.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux-2.6/debian/patches/features/all/netxen-unified-fw-image.patch	Wed Sep  8 21:39:07 2010	(r16248)
@@ -0,0 +1,1566 @@
+commit 5fe4d5c338291bbd504b8ebbd4d3931adfa61772
+Author: Amit Kumar Salecha <amit.salecha at qlogic.com>
+Date:   Mon Mar 29 02:43:44 2010 +0000
+
+    netxen: fix fw load from file
+    
+    Rarely: Fw file size can be unaligned to 8.
+    
+    Signed-off-by: Amit Kumar Salecha <amit.salecha at qlogic.com>
+    Signed-off-by: David S. Miller <davem at davemloft.net>
+
+commit 3111bf7ed99902687728eeec2ad068c2a7f8e5f0
+Author: Rajesh K Borundia <rajesh.borundia at qlogic.com>
+Date:   Mon Mar 29 02:43:43 2010 +0000
+
+    netxen: validate unified romimage
+    
+    Signed-off-by: Rajesh K Borundia <rajesh.borundia at qlogic.com>
+    Signed-off-by: Amit Kumar Salecha <amit.salecha at qlogic.com>
+    
+    Validate all sections of unified romimage, before accessing them,
+      to avoid seg fault.
+    
+    Signed-off-by: Amit Kumar Salecha <amit.salecha at qlogic.com>
+    Signed-off-by: David S. Miller <davem at davemloft.net>
+
+commit e9c75051c380aa07e237fd271a191f71cc5b79ef
+Author: Amit Kumar Salecha <amit.salecha at qlogic.com>
+Date:   Fri Mar 26 00:30:07 2010 +0000
+
+    netxen: fix bios version calculation
+    
+    Bios sub version from unified fw image is calculated incorrect.
+    
+    Signed-off-by: Amit Kumar Salecha <amit.salecha at qlogic.com>
+    Signed-off-by: David S. Miller <davem at davemloft.net>
+
+commit 31ae5cfdfd99db77ef6f213d4c35422320356d3b
+Author: Amit Kumar Salecha <amit.salecha at qlogic.com>
+Date:   Tue Dec 8 20:40:57 2009 +0000
+
+    netxen: fix unified fw size check
+    
+    o Unified firmware image size can be < 1 MB
+    
+    Signed-off-by: Amit Kumar Salecha <amit.salecha at qlogic.com>
+    Signed-off-by: David S. Miller <davem at davemloft.net>
+
+commit fd1ae25890ba3e63c62f4ba53519ec21bcc7181b
+Author: Dhananjay Phadke <dhananjay at netxen.com>
+Date:   Sat Dec 5 12:23:56 2009 +0000
+
+    netxen: fix firmware type check
+    
+    Unified firmware image may not contain MN type of firmware.
+    Driver should fall back to NOMN firmware type instead
+    of going to flash.
+    
+    Signed-off-by: Dhananjay Phadke <dhananjay at netxen.com>
+    Signed-off-by: Amit Kumar Salecha <amit.salecha at qlogic.com>
+    Signed-off-by: David S. Miller <davem at davemloft.net>
+
+commit 629073465ea87a2f5792225dc4647b9f965ee2d3
+Author: Amit Kumar Salecha <amit at netxen.com>
+Date:   Sat Oct 24 16:03:58 2009 +0000
+
+    netxen: support for new firmware file format
+    
+    Add support for extracting firmware from a unified
+    file format which embeds firmware images for all chip
+    revisions. Fallback to orginal file formats if new
+    image is not found.
+    
+    Signed-off-by: Amit Kumar Salecha <amit at netxen.com>
+    Signed-off-by: Dhananjay Phadke <dhananjay at netxen.com>
+    Signed-off-by: David S. Miller <davem at davemloft.net>
+
+commit 57cf596bef5692dc543b846cd1c05ea075270741
+Author: Dhananjay Phadke <dhananjay at netxen.com>
+Date:   Fri Oct 16 15:50:10 2009 +0000
+
+    netxen: fix error codes in for tools access
+    
+    [Backported to Debian's 2.6.26 by dann frazier <dannf at debian.org>]
+    
+    Use -EIO or -EINVAL as error codes, these can get passed up
+    to applications (tools).
+    
+    Signed-off-by: Dhananjay Phadke <dhananjay at netxen.com>
+    Signed-off-by: David S. Miller <davem at davemloft.net>
+
+commit 1648870d11e31d16b0c44d9a104ec68ebb5d9b58
+Author: Amit Kumar Salecha <amit at qlogic.com>
+Date:   Fri Oct 16 15:50:06 2009 +0000
+
+    netxen: defines for next revision
+    
+    Signed-off-by: Amit Kumar Salecha <amit at netxen.com>
+    Signed-off-by: Dhananjay Phadke <dhananjay at netxen.com>
+    Signed-off-by: David S. Miller <davem at davemloft.net>
+
+commit 43afdee1baceca4bdeccde45f98f5983302e80c2
+Author: Amit Kumar Salecha <amit at netxen.com>
+Date:   Tue Oct 13 05:31:41 2009 +0000
+
+    netxen: remove sub 64-bit mem accesses
+    
+    Sub 64-bit / unaligned access to oncard memory was only used
+    by old diagnostic tools, causes some intermittent issues when
+    memory controller agent is used.  The new access method was
+    added by commit ea6828b8aa3a8ebae8d7740f32f212ba1d2f0742
+    ("netxen: improve pci memory access").  Firmware init anyway
+    uses 8-byte strides.
+    
+    This also fixes address/offset calculation for NX2031 context
+    memory (SIU). For NX3031, SIU uses same register offsets
+    as packet memory (MIU).
+    
+    Signed-off-by: Amit Kumar Salecha <amit at netxen.com>
+    Signed-off-by: Dhananjay Phadke <dhananjay at netxen.com>
+    Signed-off-by: David S. Miller <davem at davemloft.net>
+diff -urpN a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h
+--- a/drivers/net/netxen/netxen_nic.h	2010-08-30 19:40:21.000000000 -0600
++++ b/drivers/net/netxen/netxen_nic.h	2010-08-30 19:42:40.000000000 -0600
+@@ -117,9 +117,11 @@
+ #define NX_P3_B0		0x40
+ #define NX_P3_B1		0x41
+ #define NX_P3_B2		0x42
++#define NX_P3P_A0		0x50
+ 
+ #define NX_IS_REVISION_P2(REVISION)     (REVISION <= NX_P2_C1)
+ #define NX_IS_REVISION_P3(REVISION)     (REVISION >= NX_P3_A0)
++#define NX_IS_REVISION_P3P(REVISION)     (REVISION >= NX_P3P_A0)
+ 
+ #define FIRST_PAGE_GROUP_START	0
+ #define FIRST_PAGE_GROUP_END	0x100000
+@@ -419,6 +421,33 @@ struct status_desc {
+ 	__le64 status_desc_data[2];
+ } __attribute__ ((aligned(16)));
+ 
++/* UNIFIED ROMIMAGE *************************/
++#define NX_UNI_DIR_SECT_PRODUCT_TBL	0x0
++#define NX_UNI_DIR_SECT_BOOTLD		0x6
++#define NX_UNI_DIR_SECT_FW		0x7
++
++/*Offsets */
++#define NX_UNI_CHIP_REV_OFF		10
++#define NX_UNI_FLAGS_OFF		11
++#define NX_UNI_BIOS_VERSION_OFF 	12
++#define NX_UNI_BOOTLD_IDX_OFF		27
++#define NX_UNI_FIRMWARE_IDX_OFF 	29
++
++struct uni_table_desc{
++	uint32_t	findex;
++	uint32_t	num_entries;
++	uint32_t	entry_size;
++	uint32_t	reserved[5];
++};
++
++struct uni_data_desc{
++	uint32_t	findex;
++	uint32_t	size;
++	uint32_t	reserved[5];
++};
++
++/* UNIFIED ROMIMAGE *************************/
++
+ /* The version of the main data structure */
+ #define	NETXEN_BDINFO_VERSION 1
+ 
+@@ -485,11 +514,14 @@ struct status_desc {
+ #define NX_P2_MN_ROMIMAGE	0
+ #define NX_P3_CT_ROMIMAGE	1
+ #define NX_P3_MN_ROMIMAGE	2
+-#define NX_FLASH_ROMIMAGE	3
++#define NX_UNIFIED_ROMIMAGE	3
++#define NX_FLASH_ROMIMAGE	4
++#define NX_UNKNOWN_ROMIMAGE	0xff
+ 
+ #define NX_P2_MN_ROMIMAGE_NAME		"nxromimg.bin"
+ #define NX_P3_CT_ROMIMAGE_NAME		"nx3fwct.bin"
+ #define NX_P3_MN_ROMIMAGE_NAME		"nx3fwmn.bin"
++#define NX_UNIFIED_ROMIMAGE_NAME	"phanfw.bin"
+ #define NX_FLASH_ROMIMAGE_NAME		"flash"
+ 
+ extern char netxen_nic_driver_name[];
+@@ -1187,8 +1219,8 @@ struct netxen_adapter {
+ 	u32 (*crb_read)(struct netxen_adapter *, ulong);
+ 	int (*crb_write)(struct netxen_adapter *, ulong, u32);
+ 
+-	int (*pci_mem_read)(struct netxen_adapter *, u64, void *, int);
+-	int (*pci_mem_write)(struct netxen_adapter *, u64, void *, int);
++	int (*pci_mem_read)(struct netxen_adapter *, u64, u64 *);
++	int (*pci_mem_write)(struct netxen_adapter *, u64, u64);
+ 
+ 	unsigned long (*pci_set_window)(struct netxen_adapter *,
+ 			unsigned long long);
+@@ -1215,7 +1247,7 @@ struct netxen_adapter {
+ 	nx_nic_intr_coalesce_t coal;
+ 
+ 	unsigned long state;
+-	u32 resv5;
++	__le32 file_prd_off;	/*File fw product offset*/
+ 	u32 fw_version;
+ 	const struct firmware *fw;
+ };
+diff -urpN a/drivers/net/netxen/netxen_nic_hdr.h b/drivers/net/netxen/netxen_nic_hdr.h
+--- a/drivers/net/netxen/netxen_nic_hdr.h	2009-12-02 20:51:21.000000000 -0700
++++ b/drivers/net/netxen/netxen_nic_hdr.h	2010-08-30 19:42:40.000000000 -0600
+@@ -664,40 +664,47 @@ enum {
+ #define NETXEN_NIU_AP_STATION_ADDR_0(I)    (NETXEN_CRB_NIU+0xa0040+(I)*0x10000)
+ #define NETXEN_NIU_AP_STATION_ADDR_1(I)    (NETXEN_CRB_NIU+0xa0044+(I)*0x10000)
+ 
++
++#define TEST_AGT_CTRL	(0x00)
++
++#define TA_CTL_START	1
++#define TA_CTL_ENABLE	2
++#define TA_CTL_WRITE	4
++#define TA_CTL_BUSY	8
++
+ /*
+  *   Register offsets for MN
+  */
+-#define	MIU_CONTROL	       (0x000)
+-#define MIU_TEST_AGT_CTRL      (0x090)
+-#define MIU_TEST_AGT_ADDR_LO   (0x094)
+-#define MIU_TEST_AGT_ADDR_HI   (0x098)
+-#define MIU_TEST_AGT_WRDATA_LO (0x0a0)
+-#define MIU_TEST_AGT_WRDATA_HI (0x0a4)
+-#define MIU_TEST_AGT_WRDATA(i) (0x0a0+(4*(i)))
+-#define MIU_TEST_AGT_RDDATA_LO (0x0a8)
+-#define MIU_TEST_AGT_RDDATA_HI (0x0ac)
+-#define MIU_TEST_AGT_RDDATA(i) (0x0a8+(4*(i)))
+-#define MIU_TEST_AGT_ADDR_MASK 0xfffffff8
+-#define MIU_TEST_AGT_UPPER_ADDR(off) (0)
+-
+-/* MIU_TEST_AGT_CTRL flags. work for SIU as well */
+-#define MIU_TA_CTL_START        1
+-#define MIU_TA_CTL_ENABLE       2
+-#define MIU_TA_CTL_WRITE        4
+-#define MIU_TA_CTL_BUSY         8
+-
+-#define SIU_TEST_AGT_CTRL      (0x060)
+-#define SIU_TEST_AGT_ADDR_LO   (0x064)
+-#define SIU_TEST_AGT_ADDR_HI   (0x078)
+-#define SIU_TEST_AGT_WRDATA_LO (0x068)
+-#define SIU_TEST_AGT_WRDATA_HI (0x06c)
+-#define SIU_TEST_AGT_WRDATA(i) (0x068+(4*(i)))
+-#define SIU_TEST_AGT_RDDATA_LO (0x070)
+-#define SIU_TEST_AGT_RDDATA_HI (0x074)
+-#define SIU_TEST_AGT_RDDATA(i) (0x070+(4*(i)))
++#define MIU_TEST_AGT_BASE		(0x90)
++
++#define MIU_TEST_AGT_ADDR_LO		(0x04)
++#define MIU_TEST_AGT_ADDR_HI		(0x08)
++#define MIU_TEST_AGT_WRDATA_LO		(0x10)
++#define MIU_TEST_AGT_WRDATA_HI		(0x14)
++#define MIU_TEST_AGT_WRDATA(i)		(0x10+(4*(i)))
++#define MIU_TEST_AGT_RDDATA_LO		(0x18)
++#define MIU_TEST_AGT_RDDATA_HI		(0x1c)
++#define MIU_TEST_AGT_RDDATA(i)		(0x18+(4*(i)))
++
++#define MIU_TEST_AGT_ADDR_MASK		0xfffffff8
++#define MIU_TEST_AGT_UPPER_ADDR(off)	(0)
++
++/*
++ *   Register offsets for MS
++ */
++#define SIU_TEST_AGT_BASE		(0x60)
++
++#define SIU_TEST_AGT_ADDR_LO		(0x04)
++#define SIU_TEST_AGT_ADDR_HI		(0x18)
++#define SIU_TEST_AGT_WRDATA_LO		(0x08)
++#define SIU_TEST_AGT_WRDATA_HI		(0x0c)
++#define SIU_TEST_AGT_WRDATA(i)		(0x08+(4*(i)))
++#define SIU_TEST_AGT_RDDATA_LO		(0x10)
++#define SIU_TEST_AGT_RDDATA_HI		(0x14)
++#define SIU_TEST_AGT_RDDATA(i)		(0x10+(4*(i)))
+ 
+-#define SIU_TEST_AGT_ADDR_MASK 0x3ffff8
+-#define SIU_TEST_AGT_UPPER_ADDR(off) ((off)>>22)
++#define SIU_TEST_AGT_ADDR_MASK		0x3ffff8
++#define SIU_TEST_AGT_UPPER_ADDR(off)	((off)>>22)
+ 
+ /* XG Link status */
+ #define XG_LINK_UP	0x10
+diff -urpN a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c
+--- a/drivers/net/netxen/netxen_nic_hw.c	2009-12-02 20:51:21.000000000 -0700
++++ b/drivers/net/netxen/netxen_nic_hw.c	2010-08-30 19:42:40.000000000 -0600
+@@ -326,7 +326,7 @@ netxen_pcie_sem_lock(struct netxen_adapt
+ 		if (done == 1)
+ 			break;
+ 		if (++timeout >= NETXEN_PCIE_SEM_TIMEOUT)
+-			return -1;
++			return -EIO;
+ 		msleep(1);
+ 	}
+ 
+@@ -1116,7 +1116,7 @@ netxen_nic_pci_change_crbwindow_128M(str
+ }
+ 
+ /*
+- * Return -1 if off is not valid,
++ * Returns < 0 if off is not valid,
+  *	 1 if window access is needed. 'off' is set to offset from
+  *	   CRB space in 128M pci map
+  *	 0 if no window access is needed. 'off' is set to 2M addr
+@@ -1129,7 +1129,7 @@ netxen_nic_pci_get_crb_addr_2M(struct ne
+ 
+ 
+ 	if (*off >= NETXEN_CRB_MAX)
+-		return -1;
++		return -EINVAL;
+ 
+ 	if (*off >= NETXEN_PCI_CAMQM && (*off < NETXEN_PCI_CAMQM_2M_END)) {
+ 		*off = (*off - NETXEN_PCI_CAMQM) + NETXEN_PCI_CAMQM_2M_BASE +
+@@ -1138,7 +1138,7 @@ netxen_nic_pci_get_crb_addr_2M(struct ne
+ 	}
+ 
+ 	if (*off < NETXEN_PCI_CRBSPACE)
+-		return -1;
++		return -EINVAL;
+ 
+ 	*off -= NETXEN_PCI_CRBSPACE;
+ 
+@@ -1251,25 +1251,26 @@ netxen_nic_hw_write_wx_2M(struct netxen_
+ 
+ 	rv = netxen_nic_pci_get_crb_addr_2M(adapter, &off);
+ 
+-	if (rv == -1) {
+-		printk(KERN_ERR "%s: invalid offset: 0x%016lx\n",
+-				__func__, off);
+-		dump_stack();
+-		return -1;
++	if (rv == 0) {
++		writel(data, (void __iomem *)off);
++		return 0;
+ 	}
+ 
+-	if (rv == 1) {
++	if (rv > 0) {
++		/* indirect access */
+ 		write_lock_irqsave(&adapter->adapter_lock, flags);
+ 		crb_win_lock(adapter);
+ 		netxen_nic_pci_set_crbwindow_2M(adapter, &off);
+ 		writel(data, (void __iomem *)off);
+ 		crb_win_unlock(adapter);
+ 		write_unlock_irqrestore(&adapter->adapter_lock, flags);
+-	} else
+-		writel(data, (void __iomem *)off);
+-
++		return 0;
++	}
+ 
+-	return 0;
++	dev_err(&adapter->pdev->dev,
++			"%s: invalid offset: 0x%016lx\n", __func__, off);
++	dump_stack();
++	return -EIO;
+ }
+ 
+ static u32
+@@ -1281,24 +1282,24 @@ netxen_nic_hw_read_wx_2M(struct netxen_a
+ 
+ 	rv = netxen_nic_pci_get_crb_addr_2M(adapter, &off);
+ 
+-	if (rv == -1) {
+-		printk(KERN_ERR "%s: invalid offset: 0x%016lx\n",
+-				__func__, off);
+-		dump_stack();
+-		return -1;
+-	}
++	if (rv == 0)
++		return readl((void __iomem *)off);
+ 
+-	if (rv == 1) {
++	if (rv > 0) {
++		/* indirect access */
+ 		write_lock_irqsave(&adapter->adapter_lock, flags);
+ 		crb_win_lock(adapter);
+ 		netxen_nic_pci_set_crbwindow_2M(adapter, &off);
+ 		data = readl((void __iomem *)off);
+ 		crb_win_unlock(adapter);
+ 		write_unlock_irqrestore(&adapter->adapter_lock, flags);
+-	} else
+-		data = readl((void __iomem *)off);
++		return data;
++	}
+ 
+-	return data;
++	dev_err(&adapter->pdev->dev,
++			"%s: invalid offset: 0x%016lx\n", __func__, off);
++	dump_stack();
++	return -1;
+ }
+ 
+ static int netxen_pci_set_window_warning_count;
+@@ -1485,101 +1486,69 @@ netxen_nic_pci_set_window_2M(struct netx
+ 
+ static int
+ netxen_nic_pci_mem_write_128M(struct netxen_adapter *adapter,
+-		u64 off, void *data, int size)
++		u64 off, u64 data)
+ {
+ 	unsigned long   flags;
+-	int	     i, j, ret = 0, loop, sz[2], off0;
+-	uint32_t      temp;
+-	uint64_t      off8, tmpw, word[2] = {0, 0};
++	int j, ret;
++	u32 temp, off_lo, off_hi, addr_hi, data_hi, data_lo;
+ 	void __iomem *mem_crb;
+ 
+-	if (size != 8)
++	/* Only 64-bit aligned access */
++	if (off & 7)
+ 		return -EIO;
+ 
++	/* P2 has different SIU and MIU test agent base addr */
+ 	if (ADDR_IN_RANGE(off, NETXEN_ADDR_QDR_NET,
+ 				NETXEN_ADDR_QDR_NET_MAX_P2)) {
+-		mem_crb = pci_base_offset(adapter, NETXEN_CRB_QDR_NET);
++		mem_crb = pci_base_offset(adapter,
++				NETXEN_CRB_QDR_NET+SIU_TEST_AGT_BASE);
++		addr_hi = SIU_TEST_AGT_ADDR_HI;
++		data_lo = SIU_TEST_AGT_WRDATA_LO;
++		data_hi = SIU_TEST_AGT_WRDATA_HI;
++		off_lo = off & SIU_TEST_AGT_ADDR_MASK;
++		off_hi = SIU_TEST_AGT_UPPER_ADDR(off);
+ 		goto correct;
+ 	}
+ 
+ 	if (ADDR_IN_RANGE(off, NETXEN_ADDR_DDR_NET, NETXEN_ADDR_DDR_NET_MAX)) {
+-		mem_crb = pci_base_offset(adapter, NETXEN_CRB_DDR_NET);
++		mem_crb = pci_base_offset(adapter,
++				NETXEN_CRB_DDR_NET+MIU_TEST_AGT_BASE);
++		addr_hi = MIU_TEST_AGT_ADDR_HI;
++		data_lo = MIU_TEST_AGT_WRDATA_LO;
++		data_hi = MIU_TEST_AGT_WRDATA_HI;
++		off_lo = off & MIU_TEST_AGT_ADDR_MASK;
++		off_hi = 0;
+ 		goto correct;
+ 	}
+ 
+ 	return -EIO;
+ 
+ correct:
+-	off8 = off & 0xfffffff8;
+-	off0 = off & 0x7;
+-	sz[0] = (size < (8 - off0)) ? size : (8 - off0);
+-	sz[1] = size - sz[0];
+-	loop = ((off0 + size - 1) >> 3) + 1;
+-
+-	if ((size != 8) || (off0 != 0))  {
+-		for (i = 0; i < loop; i++) {
+-			if (adapter->pci_mem_read(adapter,
+-				off8 + (i << 3), &word[i], 8))
+-				return -1;
+-		}
+-	}
+-
+-	switch (size) {
+-	case 1:
+-		tmpw = *((uint8_t *)data);
+-		break;
+-	case 2:
+-		tmpw = *((uint16_t *)data);
+-		break;
+-	case 4:
+-		tmpw = *((uint32_t *)data);
+-		break;
+-	case 8:
+-	default:
+-		tmpw = *((uint64_t *)data);
+-		break;
+-	}
+-	word[0] &= ~((~(~0ULL << (sz[0] * 8))) << (off0 * 8));
+-	word[0] |= tmpw << (off0 * 8);
+-
+-	if (loop == 2) {
+-		word[1] &= ~(~0ULL << (sz[1] * 8));
+-		word[1] |= tmpw >> (sz[0] * 8);
+-	}
+-
+ 	write_lock_irqsave(&adapter->adapter_lock, flags);
+ 	netxen_nic_pci_change_crbwindow_128M(adapter, 0);
+ 
+-	for (i = 0; i < loop; i++) {
+-		writel((uint32_t)(off8 + (i << 3)),
+-			(mem_crb+MIU_TEST_AGT_ADDR_LO));
+-		writel(0,
+-			(mem_crb+MIU_TEST_AGT_ADDR_HI));
+-		writel(word[i] & 0xffffffff,
+-			(mem_crb+MIU_TEST_AGT_WRDATA_LO));
+-		writel((word[i] >> 32) & 0xffffffff,
+-			(mem_crb+MIU_TEST_AGT_WRDATA_HI));
+-		writel(MIU_TA_CTL_ENABLE|MIU_TA_CTL_WRITE,
+-			(mem_crb+MIU_TEST_AGT_CTRL));
+-		writel(MIU_TA_CTL_START|MIU_TA_CTL_ENABLE|MIU_TA_CTL_WRITE,
+-			(mem_crb+MIU_TEST_AGT_CTRL));
+-
+-		for (j = 0; j < MAX_CTL_CHECK; j++) {
+-			temp = readl(
+-			     (mem_crb+MIU_TEST_AGT_CTRL));
+-			if ((temp & MIU_TA_CTL_BUSY) == 0)
+-				break;
+-		}
+-
+-		if (j >= MAX_CTL_CHECK) {
+-			if (printk_ratelimit())
+-				dev_err(&adapter->pdev->dev,
+-					"failed to write through agent\n");
+-			ret = -1;
++	writel(off_lo, (mem_crb + MIU_TEST_AGT_ADDR_LO));
++	writel(off_hi, (mem_crb + addr_hi));
++	writel(data & 0xffffffff, (mem_crb + data_lo));
++	writel((data >> 32) & 0xffffffff, (mem_crb + data_hi));
++	writel((TA_CTL_ENABLE | TA_CTL_WRITE), (mem_crb + TEST_AGT_CTRL));
++	writel((TA_CTL_START | TA_CTL_ENABLE | TA_CTL_WRITE),
++			(mem_crb + TEST_AGT_CTRL));
++
++	for (j = 0; j < MAX_CTL_CHECK; j++) {
++		temp = readl((mem_crb + TEST_AGT_CTRL));
++		if ((temp & TA_CTL_BUSY) == 0)
+ 			break;
+-		}
+ 	}
+ 
++	if (j >= MAX_CTL_CHECK) {
++		if (printk_ratelimit())
++			dev_err(&adapter->pdev->dev,
++					"failed to write through agent\n");
++		ret = -EIO;
++	} else
++		ret = 0;
++
+ 	netxen_nic_pci_change_crbwindow_128M(adapter, 1);
+ 	write_unlock_irqrestore(&adapter->adapter_lock, flags);
+ 	return ret;
+@@ -1587,304 +1556,202 @@ correct:
+ 
+ static int
+ netxen_nic_pci_mem_read_128M(struct netxen_adapter *adapter,
+-		u64 off, void *data, int size)
++		u64 off, u64 *data)
+ {
+ 	unsigned long   flags;
+-	int	     i, j = 0, k, start, end, loop, sz[2], off0[2];
+-	uint32_t      temp;
+-	uint64_t      off8, val, word[2] = {0, 0};
++	int j, ret;
++	u32 temp, off_lo, off_hi, addr_hi, data_hi, data_lo;
++	u64 val;
+ 	void __iomem *mem_crb;
+ 
+-	if (size != 8)
++	/* Only 64-bit aligned access */
++	if (off & 7)
+ 		return -EIO;
+ 
++	/* P2 has different SIU and MIU test agent base addr */
+ 	if (ADDR_IN_RANGE(off, NETXEN_ADDR_QDR_NET,
+ 				NETXEN_ADDR_QDR_NET_MAX_P2)) {
+-		mem_crb = pci_base_offset(adapter, NETXEN_CRB_QDR_NET);
++		mem_crb = pci_base_offset(adapter,
++				NETXEN_CRB_QDR_NET+SIU_TEST_AGT_BASE);
++		addr_hi = SIU_TEST_AGT_ADDR_HI;
++		data_lo = SIU_TEST_AGT_RDDATA_LO;
++		data_hi = SIU_TEST_AGT_RDDATA_HI;
++		off_lo = off & SIU_TEST_AGT_ADDR_MASK;
++		off_hi = SIU_TEST_AGT_UPPER_ADDR(off);
+ 		goto correct;
+ 	}
+ 
+ 	if (ADDR_IN_RANGE(off, NETXEN_ADDR_DDR_NET, NETXEN_ADDR_DDR_NET_MAX)) {
+-		mem_crb = pci_base_offset(adapter, NETXEN_CRB_DDR_NET);
++		mem_crb = pci_base_offset(adapter,
++				NETXEN_CRB_DDR_NET+MIU_TEST_AGT_BASE);
++		addr_hi = MIU_TEST_AGT_ADDR_HI;
++		data_lo = MIU_TEST_AGT_RDDATA_LO;
++		data_hi = MIU_TEST_AGT_RDDATA_HI;
++		off_lo = off & MIU_TEST_AGT_ADDR_MASK;
++		off_hi = 0;
+ 		goto correct;
+ 	}
+ 
+ 	return -EIO;
+ 
+ correct:
+-	off8 = off & 0xfffffff8;
+-	off0[0] = off & 0x7;
+-	off0[1] = 0;
+-	sz[0] = (size < (8 - off0[0])) ? size : (8 - off0[0]);
+-	sz[1] = size - sz[0];
+-	loop = ((off0[0] + size - 1) >> 3) + 1;
+-
+ 	write_lock_irqsave(&adapter->adapter_lock, flags);
+ 	netxen_nic_pci_change_crbwindow_128M(adapter, 0);
+ 
+-	for (i = 0; i < loop; i++) {
+-		writel((uint32_t)(off8 + (i << 3)),
+-			(mem_crb+MIU_TEST_AGT_ADDR_LO));
+-		writel(0,
+-			(mem_crb+MIU_TEST_AGT_ADDR_HI));
+-		writel(MIU_TA_CTL_ENABLE,
+-			(mem_crb+MIU_TEST_AGT_CTRL));
+-		writel(MIU_TA_CTL_START|MIU_TA_CTL_ENABLE,
+-			(mem_crb+MIU_TEST_AGT_CTRL));
+-
+-		for (j = 0; j < MAX_CTL_CHECK; j++) {
+-			temp = readl(
+-			      (mem_crb+MIU_TEST_AGT_CTRL));
+-			if ((temp & MIU_TA_CTL_BUSY) == 0)
+-				break;
+-		}
++	writel(off_lo, (mem_crb + MIU_TEST_AGT_ADDR_LO));
++	writel(off_hi, (mem_crb + addr_hi));
++	writel(TA_CTL_ENABLE, (mem_crb + TEST_AGT_CTRL));
++	writel((TA_CTL_START|TA_CTL_ENABLE), (mem_crb + TEST_AGT_CTRL));
++
++	for (j = 0; j < MAX_CTL_CHECK; j++) {
++		temp = readl(mem_crb + TEST_AGT_CTRL);
++		if ((temp & TA_CTL_BUSY) == 0)
++			break;
++	}
+ 
+-		if (j >= MAX_CTL_CHECK) {
+-			if (printk_ratelimit())
+-				dev_err(&adapter->pdev->dev,
++	if (j >= MAX_CTL_CHECK) {
++		if (printk_ratelimit())
++			dev_err(&adapter->pdev->dev,
+ 					"failed to read through agent\n");
+-			break;
+-		}
++		ret = -EIO;
++	} else {
+ 
+-		start = off0[i] >> 2;
+-		end   = (off0[i] + sz[i] - 1) >> 2;
+-		for (k = start; k <= end; k++) {
+-			word[i] |= ((uint64_t) readl(
+-				    (mem_crb +
+-				    MIU_TEST_AGT_RDDATA(k))) << (32*k));
+-		}
++		temp = readl(mem_crb + data_hi);
++		val = ((u64)temp << 32);
++		val |= readl(mem_crb + data_lo);
++		*data = val;
++		ret = 0;
+ 	}
+ 
+ 	netxen_nic_pci_change_crbwindow_128M(adapter, 1);
+ 	write_unlock_irqrestore(&adapter->adapter_lock, flags);
+ 
+-	if (j >= MAX_CTL_CHECK)
+-		return -1;
+-
+-	if (sz[0] == 8) {
+-		val = word[0];
+-	} else {
+-		val = ((word[0] >> (off0[0] * 8)) & (~(~0ULL << (sz[0] * 8)))) |
+-			((word[1] & (~(~0ULL << (sz[1] * 8)))) << (sz[0] * 8));
+-	}
+-
+-	switch (size) {
+-	case 1:
+-		*(uint8_t  *)data = val;
+-		break;
+-	case 2:
+-		*(uint16_t *)data = val;
+-		break;
+-	case 4:
+-		*(uint32_t *)data = val;
+-		break;
+-	case 8:
+-		*(uint64_t *)data = val;
+-		break;
+-	}
+-	return 0;
++	return ret;
+ }
+ 
+ static int
+ netxen_nic_pci_mem_write_2M(struct netxen_adapter *adapter,
+-		u64 off, void *data, int size)
++		u64 off, u64 data)
+ {
+-	int i, j, ret = 0, loop, sz[2], off0;
+-	uint32_t temp;
+-	uint64_t off8, tmpw, word[2] = {0, 0};
++	unsigned long   flags;
++	int j, ret;
++	u32 temp, off8;
+ 	void __iomem *mem_crb;
+ 
+-	if (size != 8)
++	/* Only 64-bit aligned access */
++	if (off & 7)
+ 		return -EIO;
+ 
++	/* P3 onward, test agent base for MIU and SIU is same */
+ 	if (ADDR_IN_RANGE(off, NETXEN_ADDR_QDR_NET,
+ 				NETXEN_ADDR_QDR_NET_MAX_P3)) {
+-		mem_crb = netxen_get_ioaddr(adapter, NETXEN_CRB_QDR_NET);
++		mem_crb = netxen_get_ioaddr(adapter,
++				NETXEN_CRB_QDR_NET+MIU_TEST_AGT_BASE);
+ 		goto correct;
+ 	}
+ 
+ 	if (ADDR_IN_RANGE(off, NETXEN_ADDR_DDR_NET, NETXEN_ADDR_DDR_NET_MAX)) {
+-		mem_crb = netxen_get_ioaddr(adapter, NETXEN_CRB_DDR_NET);
++		mem_crb = netxen_get_ioaddr(adapter,
++				NETXEN_CRB_DDR_NET+MIU_TEST_AGT_BASE);
+ 		goto correct;
+ 	}
+ 
+ 	return -EIO;
+ 
+ correct:
+-	off8 = off & 0xfffffff8;
+-	off0 = off & 0x7;
+-	sz[0] = (size < (8 - off0)) ? size : (8 - off0);
+-	sz[1] = size - sz[0];
+-	loop = ((off0 + size - 1) >> 3) + 1;
+-
+-	if ((size != 8) || (off0 != 0)) {
+-		for (i = 0; i < loop; i++) {
+-			if (adapter->pci_mem_read(adapter,
+-					off8 + (i << 3), &word[i], 8))
+-				return -1;
+-		}
+-	}
+-
+-	switch (size) {
+-	case 1:
+-		tmpw = *((uint8_t *)data);
+-		break;
+-	case 2:
+-		tmpw = *((uint16_t *)data);
+-		break;
+-	case 4:
+-		tmpw = *((uint32_t *)data);
+-		break;
+-	case 8:
+-	default:
+-		tmpw = *((uint64_t *)data);
+-	break;
+-	}
+-
+-	word[0] &= ~((~(~0ULL << (sz[0] * 8))) << (off0 * 8));
+-	word[0] |= tmpw << (off0 * 8);
+-
+-	if (loop == 2) {
+-		word[1] &= ~(~0ULL << (sz[1] * 8));
+-		word[1] |= tmpw >> (sz[0] * 8);
+-	}
+-
+-	/*
+-	 * don't lock here - write_wx gets the lock if each time
+-	 * write_lock_irqsave(&adapter->adapter_lock, flags);
+-	 * netxen_nic_pci_change_crbwindow_128M(adapter, 0);
+-	 */
++	off8 = off & MIU_TEST_AGT_ADDR_MASK;
+ 
+-	for (i = 0; i < loop; i++) {
+-		writel(off8 + (i << 3), mem_crb+MIU_TEST_AGT_ADDR_LO);
+-		writel(0, mem_crb+MIU_TEST_AGT_ADDR_HI);
+-		writel(word[i] & 0xffffffff, mem_crb+MIU_TEST_AGT_WRDATA_LO);
+-		writel((word[i] >> 32) & 0xffffffff,
+-				mem_crb+MIU_TEST_AGT_WRDATA_HI);
+-		writel((MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE),
+-				mem_crb+MIU_TEST_AGT_CTRL);
+-		writel(MIU_TA_CTL_START | MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE,
+-				mem_crb+MIU_TEST_AGT_CTRL);
+-
+-		for (j = 0; j < MAX_CTL_CHECK; j++) {
+-			temp = readl(mem_crb + MIU_TEST_AGT_CTRL);
+-			if ((temp & MIU_TA_CTL_BUSY) == 0)
+-				break;
+-		}
++	write_lock_irqsave(&adapter->adapter_lock, flags);
+ 
+-		if (j >= MAX_CTL_CHECK) {
+-			if (printk_ratelimit())
+-				dev_err(&adapter->pdev->dev,
+-					"failed to write through agent\n");
+-			ret = -1;
++	writel(off8, (mem_crb + MIU_TEST_AGT_ADDR_LO));
++	writel(0, (mem_crb + MIU_TEST_AGT_ADDR_HI));
++	writel(data & 0xffffffff, mem_crb + MIU_TEST_AGT_WRDATA_LO);
++	writel((data >> 32) & 0xffffffff, mem_crb + MIU_TEST_AGT_WRDATA_HI);
++	writel((TA_CTL_ENABLE | TA_CTL_WRITE), (mem_crb + TEST_AGT_CTRL));
++	writel((TA_CTL_START | TA_CTL_ENABLE | TA_CTL_WRITE),
++			(mem_crb + TEST_AGT_CTRL));
++
++	for (j = 0; j < MAX_CTL_CHECK; j++) {
++		temp = readl(mem_crb + TEST_AGT_CTRL);
++		if ((temp & TA_CTL_BUSY) == 0)
+ 			break;
+-		}
+ 	}
+ 
+-	/*
+-	 * netxen_nic_pci_change_crbwindow_128M(adapter, 1);
+-	 * write_unlock_irqrestore(&adapter->adapter_lock, flags);
+-	 */
++	if (j >= MAX_CTL_CHECK) {
++		if (printk_ratelimit())
++			dev_err(&adapter->pdev->dev,
++					"failed to write through agent\n");
++		ret = -EIO;
++	} else
++		ret = 0;
++
++	write_unlock_irqrestore(&adapter->adapter_lock, flags);
++
+ 	return ret;
+ }
+ 
+ static int
+ netxen_nic_pci_mem_read_2M(struct netxen_adapter *adapter,
+-		u64 off, void *data, int size)
++		u64 off, u64 *data)
+ {
+-	int i, j = 0, k, start, end, loop, sz[2], off0[2];
+-	uint32_t      temp;
+-	uint64_t      off8, val, word[2] = {0, 0};
++	unsigned long   flags;
++	int j, ret;
++	u32 temp, off8;
++	u64 val;
+ 	void __iomem *mem_crb;
+ 
+-	if (size != 8)
++	/* Only 64-bit aligned access */
++	if (off & 7)
+ 		return -EIO;
+ 
++	/* P3 onward, test agent base for MIU and SIU is same */
+ 	if (ADDR_IN_RANGE(off, NETXEN_ADDR_QDR_NET,
+ 				NETXEN_ADDR_QDR_NET_MAX_P3)) {
+-		mem_crb = netxen_get_ioaddr(adapter, NETXEN_CRB_QDR_NET);
++		mem_crb = netxen_get_ioaddr(adapter,
++				NETXEN_CRB_QDR_NET+MIU_TEST_AGT_BASE);
+ 		goto correct;
+ 	}
+ 
+ 	if (ADDR_IN_RANGE(off, NETXEN_ADDR_DDR_NET, NETXEN_ADDR_DDR_NET_MAX)) {
+-		mem_crb = netxen_get_ioaddr(adapter, NETXEN_CRB_DDR_NET);
++		mem_crb = netxen_get_ioaddr(adapter,
++				NETXEN_CRB_DDR_NET+MIU_TEST_AGT_BASE);
+ 		goto correct;
+ 	}
+ 
+ 	return -EIO;
+ 
+ correct:
+-	off8 = off & 0xfffffff8;
+-	off0[0] = off & 0x7;
+-	off0[1] = 0;
+-	sz[0] = (size < (8 - off0[0])) ? size : (8 - off0[0]);
+-	sz[1] = size - sz[0];
+-	loop = ((off0[0] + size - 1) >> 3) + 1;
+-
+-	/*
+-	 * don't lock here - write_wx gets the lock if each time
+-	 * write_lock_irqsave(&adapter->adapter_lock, flags);
+-	 * netxen_nic_pci_change_crbwindow_128M(adapter, 0);
+-	 */
++	off8 = off & MIU_TEST_AGT_ADDR_MASK;
+ 
+-	for (i = 0; i < loop; i++) {
+-		writel(off8 + (i << 3), mem_crb + MIU_TEST_AGT_ADDR_LO);
+-		writel(0, mem_crb + MIU_TEST_AGT_ADDR_HI);
+-		writel(MIU_TA_CTL_ENABLE, mem_crb + MIU_TEST_AGT_CTRL);
+-		writel(MIU_TA_CTL_START | MIU_TA_CTL_ENABLE,
+-				mem_crb + MIU_TEST_AGT_CTRL);
+-
+-		for (j = 0; j < MAX_CTL_CHECK; j++) {
+-			temp = readl(mem_crb + MIU_TEST_AGT_CTRL);
+-			if ((temp & MIU_TA_CTL_BUSY) == 0)
+-				break;
+-		}
++	write_lock_irqsave(&adapter->adapter_lock, flags);
+ 
+-		if (j >= MAX_CTL_CHECK) {
+-			if (printk_ratelimit())
+-				dev_err(&adapter->pdev->dev,
+-					"failed to read through agent\n");
++	writel(off8, (mem_crb + MIU_TEST_AGT_ADDR_LO));
++	writel(0, (mem_crb + MIU_TEST_AGT_ADDR_HI));
++	writel(TA_CTL_ENABLE, (mem_crb + TEST_AGT_CTRL));
++	writel((TA_CTL_START | TA_CTL_ENABLE), (mem_crb + TEST_AGT_CTRL));
++
++	for (j = 0; j < MAX_CTL_CHECK; j++) {
++		temp = readl(mem_crb + TEST_AGT_CTRL);
++		if ((temp & TA_CTL_BUSY) == 0)
+ 			break;
+-		}
+-
+-		start = off0[i] >> 2;
+-		end   = (off0[i] + sz[i] - 1) >> 2;
+-		for (k = start; k <= end; k++) {
+-			temp = readl(mem_crb + MIU_TEST_AGT_RDDATA(k));
+-			word[i] |= ((uint64_t)temp << (32 * k));
+-		}
+ 	}
+ 
+-	/*
+-	 * netxen_nic_pci_change_crbwindow_128M(adapter, 1);
+-	 * write_unlock_irqrestore(&adapter->adapter_lock, flags);
+-	 */
+-
+-	if (j >= MAX_CTL_CHECK)
+-		return -1;
+-
+-	if (sz[0] == 8) {
+-		val = word[0];
++	if (j >= MAX_CTL_CHECK) {
++		if (printk_ratelimit())
++			dev_err(&adapter->pdev->dev,
++					"failed to read through agent\n");
++		ret = -EIO;
+ 	} else {
+-		val = ((word[0] >> (off0[0] * 8)) & (~(~0ULL << (sz[0] * 8)))) |
+-		((word[1] & (~(~0ULL << (sz[1] * 8)))) << (sz[0] * 8));
++		temp = readl(mem_crb + MIU_TEST_AGT_RDDATA_HI);
++		val = (u64)temp << 32;
++		val |= readl(mem_crb + MIU_TEST_AGT_RDDATA_LO);
++		*data = val;
++		ret = 0;
+ 	}
+ 
+-	switch (size) {
+-	case 1:
+-		*(uint8_t  *)data = val;
+-		break;
+-	case 2:
+-		*(uint16_t *)data = val;
+-		break;
+-	case 4:
+-		*(uint32_t *)data = val;
+-		break;
+-	case 8:
+-		*(uint64_t *)data = val;
+-		break;
+-	}
+-	return 0;
++	write_unlock_irqrestore(&adapter->adapter_lock, flags);
++
++	return ret;
+ }
+ 
+ void
+diff -urpN a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c
+--- a/drivers/net/netxen/netxen_nic_init.c	2010-08-30 19:40:21.000000000 -0600
++++ b/drivers/net/netxen/netxen_nic_init.c	2010-08-30 19:42:40.000000000 -0600
+@@ -46,6 +46,7 @@ static unsigned int crb_addr_xform[NETXE
+ static void
+ netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter,
+ 		struct nx_host_rds_ring *rds_ring);
++static int netxen_p3_has_mn(struct netxen_adapter *adapter);
+ 
+ static void crb_addr_transform_setup(void)
+ {
+@@ -607,6 +608,310 @@ int netxen_pinit_from_rom(struct netxen_
+ 	return 0;
+ }
+ 
++static struct uni_table_desc *nx_get_table_desc(const u8 *unirom, int section)
++{
++	uint32_t i;
++	struct uni_table_desc *directory = (struct uni_table_desc *) &unirom[0];
++	__le32 entries = cpu_to_le32(directory->num_entries);
++
++	for (i = 0; i < entries; i++) {
++
++		__le32 offs = cpu_to_le32(directory->findex) +
++				(i * cpu_to_le32(directory->entry_size));
++		__le32 tab_type = cpu_to_le32(*((u32 *)&unirom[offs] + 8));
++
++		if (tab_type == section)
++			return (struct uni_table_desc *) &unirom[offs];
++	}
++
++	return NULL;
++}
++
++#define	QLCNIC_FILEHEADER_SIZE	(14 * 4)
++
++static int
++netxen_nic_validate_header(struct netxen_adapter *adapter)
++ {
++	const u8 *unirom = adapter->fw->data;
++	struct uni_table_desc *directory = (struct uni_table_desc *) &unirom[0];
++	u32 fw_file_size = adapter->fw->size;
++	u32 tab_size;
++	__le32 entries;
++	__le32 entry_size;
++
++	if (fw_file_size < QLCNIC_FILEHEADER_SIZE)
++		return -EINVAL;
++
++	entries = cpu_to_le32(directory->num_entries);
++	entry_size = cpu_to_le32(directory->entry_size);
++	tab_size = cpu_to_le32(directory->findex) + (entries * entry_size);
++
++	if (fw_file_size < tab_size)
++		return -EINVAL;
++
++	return 0;
++}
++
++static int
++netxen_nic_validate_bootld(struct netxen_adapter *adapter)
++{
++	struct uni_table_desc *tab_desc;
++	struct uni_data_desc *descr;
++	const u8 *unirom = adapter->fw->data;
++	__le32 idx = cpu_to_le32(*((int *)&unirom[adapter->file_prd_off] +
++				NX_UNI_BOOTLD_IDX_OFF));
++	u32 offs;
++	u32 tab_size;
++	u32 data_size;
++
++	tab_desc = nx_get_table_desc(unirom, NX_UNI_DIR_SECT_BOOTLD);
++
++	if (!tab_desc)
++		return -EINVAL;
++
++	tab_size = cpu_to_le32(tab_desc->findex) +
++			(cpu_to_le32(tab_desc->entry_size) * (idx + 1));
++
++	if (adapter->fw->size < tab_size)
++		return -EINVAL;
++
++	offs = cpu_to_le32(tab_desc->findex) +
++		(cpu_to_le32(tab_desc->entry_size) * (idx));
++	descr = (struct uni_data_desc *)&unirom[offs];
++
++	data_size = cpu_to_le32(descr->findex) + cpu_to_le32(descr->size);
++
++	if (adapter->fw->size < data_size)
++		return -EINVAL;
++
++	return 0;
++}
++
++static int
++netxen_nic_validate_fw(struct netxen_adapter *adapter)
++{
++	struct uni_table_desc *tab_desc;
++	struct uni_data_desc *descr;
++	const u8 *unirom = adapter->fw->data;
++	__le32 idx = cpu_to_le32(*((int *)&unirom[adapter->file_prd_off] +
++				NX_UNI_FIRMWARE_IDX_OFF));
++	u32 offs;
++	u32 tab_size;
++	u32 data_size;
++
++	tab_desc = nx_get_table_desc(unirom, NX_UNI_DIR_SECT_FW);
++
++	if (!tab_desc)
++		return -EINVAL;
++
++	tab_size = cpu_to_le32(tab_desc->findex) +
++			(cpu_to_le32(tab_desc->entry_size) * (idx + 1));
++
++	if (adapter->fw->size < tab_size)
++		return -EINVAL;
++
++	offs = cpu_to_le32(tab_desc->findex) +
++		(cpu_to_le32(tab_desc->entry_size) * (idx));
++	descr = (struct uni_data_desc *)&unirom[offs];
++	data_size = cpu_to_le32(descr->findex) + cpu_to_le32(descr->size);
++
++	if (adapter->fw->size < data_size)
++		return -EINVAL;
++
++	return 0;
++}
++
++
++static int
++netxen_nic_validate_product_offs(struct netxen_adapter *adapter)
++{
++	struct uni_table_desc *ptab_descr;
++	const u8 *unirom = adapter->fw->data;
++	int mn_present = (NX_IS_REVISION_P2(adapter->ahw.revision_id)) ?
++			1 : netxen_p3_has_mn(adapter);
++	__le32 entries;
++	__le32 entry_size;
++	u32 tab_size;
++	u32 i;
++
++	ptab_descr = nx_get_table_desc(unirom, NX_UNI_DIR_SECT_PRODUCT_TBL);
++	if (ptab_descr == NULL)
++		return -EINVAL;
++
++	entries = cpu_to_le32(ptab_descr->num_entries);
++	entry_size = cpu_to_le32(ptab_descr->entry_size);
++	tab_size = cpu_to_le32(ptab_descr->findex) + (entries * entry_size);
++
++	if (adapter->fw->size < tab_size)
++		return -EINVAL;
++
++nomn:
++	for (i = 0; i < entries; i++) {
++
++		__le32 flags, file_chiprev, offs;
++		u8 chiprev = adapter->ahw.revision_id;
++		uint32_t flagbit;
++
++		offs = cpu_to_le32(ptab_descr->findex) +
++				(i * cpu_to_le32(ptab_descr->entry_size));
++		flags = cpu_to_le32(*((int *)&unirom[offs] + NX_UNI_FLAGS_OFF));
++		file_chiprev = cpu_to_le32(*((int *)&unirom[offs] +
++							NX_UNI_CHIP_REV_OFF));
++
++		flagbit = mn_present ? 1 : 2;
++
++		if ((chiprev == file_chiprev) &&
++					((1ULL << flagbit) & flags)) {
++			adapter->file_prd_off = offs;
++			return 0;
++		}
++	}
++
++	if (mn_present && NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
++		mn_present = 0;
++		goto nomn;
++	}
++
++	return -EINVAL;
++}
++
++static int
++netxen_nic_validate_unified_romimage(struct netxen_adapter *adapter)
++{
++	if (netxen_nic_validate_header(adapter)) {
++		dev_err(&adapter->pdev->dev,
++				"unified image: header validation failed\n");
++		return -EINVAL;
++	}
++
++	if (netxen_nic_validate_product_offs(adapter)) {
++		dev_err(&adapter->pdev->dev,
++				"unified image: product validation failed\n");
++		return -EINVAL;
++	}
++
++	if (netxen_nic_validate_bootld(adapter)) {
++		dev_err(&adapter->pdev->dev,
++				"unified image: bootld validation failed\n");
++		return -EINVAL;
++	}
++
++	if (netxen_nic_validate_fw(adapter)) {
++		dev_err(&adapter->pdev->dev,
++				"unified image: firmware validation failed\n");
++		return -EINVAL;
++	}
++
++	return 0;
++}
++
++static struct uni_data_desc *nx_get_data_desc(struct netxen_adapter *adapter,
++			u32 section, u32 idx_offset)
++{
++	const u8 *unirom = adapter->fw->data;
++	int idx = cpu_to_le32(*((int *)&unirom[adapter->file_prd_off] +
++								idx_offset));
++	struct uni_table_desc *tab_desc;
++	__le32 offs;
++
++	tab_desc = nx_get_table_desc(unirom, section);
++
++	if (tab_desc == NULL)
++		return NULL;
++
++	offs = cpu_to_le32(tab_desc->findex) +
++			(cpu_to_le32(tab_desc->entry_size) * idx);
++
++	return (struct uni_data_desc *)&unirom[offs];
++}
++
++static u8 *
++nx_get_bootld_offs(struct netxen_adapter *adapter)
++{
++	u32 offs = NETXEN_BOOTLD_START;
++
++	if (adapter->fw_type == NX_UNIFIED_ROMIMAGE)
++		offs = cpu_to_le32((nx_get_data_desc(adapter,
++					NX_UNI_DIR_SECT_BOOTLD,
++					NX_UNI_BOOTLD_IDX_OFF))->findex);
++
++	return (u8 *)&adapter->fw->data[offs];
++}
++
++static u8 *
++nx_get_fw_offs(struct netxen_adapter *adapter)
++{
++	u32 offs = NETXEN_IMAGE_START;
++
++	if (adapter->fw_type == NX_UNIFIED_ROMIMAGE)
++		offs = cpu_to_le32((nx_get_data_desc(adapter,
++					NX_UNI_DIR_SECT_FW,
++					NX_UNI_FIRMWARE_IDX_OFF))->findex);
++
++	return (u8 *)&adapter->fw->data[offs];
++}
++
++static __le32
++nx_get_fw_size(struct netxen_adapter *adapter)
++{
++	if (adapter->fw_type == NX_UNIFIED_ROMIMAGE)
++		return cpu_to_le32((nx_get_data_desc(adapter,
++					NX_UNI_DIR_SECT_FW,
++					NX_UNI_FIRMWARE_IDX_OFF))->size);
++	else
++		return cpu_to_le32(
++				*(u32 *)&adapter->fw->data[NX_FW_SIZE_OFFSET]);
++}
++
++static __le32
++nx_get_fw_version(struct netxen_adapter *adapter)
++{
++	struct uni_data_desc *fw_data_desc;
++	const struct firmware *fw = adapter->fw;
++	__le32 major, minor, sub;
++	const u8 *ver_str;
++	int i, ret = 0;
++
++	if (adapter->fw_type == NX_UNIFIED_ROMIMAGE) {
++
++		fw_data_desc = nx_get_data_desc(adapter,
++				NX_UNI_DIR_SECT_FW, NX_UNI_FIRMWARE_IDX_OFF);
++		ver_str = fw->data + cpu_to_le32(fw_data_desc->findex) +
++				cpu_to_le32(fw_data_desc->size) - 17;
++
++		for (i = 0; i < 12; i++) {
++			if (!strncmp(&ver_str[i], "REV=", 4)) {
++				ret = sscanf(&ver_str[i+4], "%u.%u.%u ",
++							&major, &minor, &sub);
++				break;
++			}
++		}
++
++		if (ret != 3)
++			return 0;
++
++		return major + (minor << 8) + (sub << 16);
++
++	} else
++		return cpu_to_le32(*(u32 *)&fw->data[NX_FW_VERSION_OFFSET]);
++}
++
++static __le32
++nx_get_bios_version(struct netxen_adapter *adapter)
++{
++	const struct firmware *fw = adapter->fw;
++	__le32 bios_ver, prd_off = adapter->file_prd_off;
++
++	if (adapter->fw_type == NX_UNIFIED_ROMIMAGE) {
++		bios_ver = cpu_to_le32(*((u32 *) (&fw->data[prd_off])
++						+ NX_UNI_BIOS_VERSION_OFF));
++		return (bios_ver << 16) + ((bios_ver >> 8) & 0xff00) +
++							(bios_ver >> 24);
++	} else
++		return cpu_to_le32(*(u32 *)&fw->data[NX_BIOS_VERSION_OFFSET]);
++
++}
++
+ int
+ netxen_need_fw_reset(struct netxen_adapter *adapter)
+ {
+@@ -646,9 +951,8 @@ netxen_need_fw_reset(struct netxen_adapt
+ 	/* check if we have got newer or different file firmware */
+ 	if (adapter->fw) {
+ 
+-		const struct firmware *fw = adapter->fw;
++		val = nx_get_fw_version(adapter);
+ 
+-		val = cpu_to_le32(*(u32 *)&fw->data[NX_FW_VERSION_OFFSET]);
+ 		version = NETXEN_DECODE_VERSION(val);
+ 
+ 		major = NXRD32(adapter, NETXEN_FW_VERSION_MAJOR);
+@@ -658,7 +962,8 @@ netxen_need_fw_reset(struct netxen_adapt
+ 		if (version > NETXEN_VERSION_CODE(major, minor, build))
+ 			return 1;
+ 
+-		if (version == NETXEN_VERSION_CODE(major, minor, build)) {
++		if (version == NETXEN_VERSION_CODE(major, minor, build) &&
++			adapter->fw_type != NX_UNIFIED_ROMIMAGE) {
+ 
+ 			val = NXRD32(adapter, NETXEN_MIU_MN_CONTROL);
+ 			fw_type = (val & 0x4) ?
+@@ -676,6 +981,7 @@ static char *fw_name[] = {
+ 	NX_P2_MN_ROMIMAGE_NAME,
+ 	NX_P3_CT_ROMIMAGE_NAME,
+ 	NX_P3_MN_ROMIMAGE_NAME,
++	NX_UNIFIED_ROMIMAGE_NAME,
+ 	NX_FLASH_ROMIMAGE_NAME,
+ };
+ 
+@@ -698,30 +1004,42 @@ netxen_load_firmware(struct netxen_adapt
+ 
+ 		size = (NETXEN_IMAGE_START - NETXEN_BOOTLD_START) / 8;
+ 
+-		ptr64 = (u64 *)&fw->data[NETXEN_BOOTLD_START];
++		ptr64 = (u64 *)nx_get_bootld_offs(adapter);
+ 		flashaddr = NETXEN_BOOTLD_START;
+ 
+ 		for (i = 0; i < size; i++) {
+ 			data = cpu_to_le64(ptr64[i]);
+-			adapter->pci_mem_write(adapter, flashaddr, &data, 8);
++
++			if (adapter->pci_mem_write(adapter, flashaddr, data))
++				return -EIO;
++
+ 			flashaddr += 8;
+ 		}
+ 
+-		size = *(u32 *)&fw->data[NX_FW_SIZE_OFFSET];
+-		size = (__force u32)cpu_to_le32(size) / 8;
++		size = (__force u32)nx_get_fw_size(adapter) / 8;
+ 
+-		ptr64 = (u64 *)&fw->data[NETXEN_IMAGE_START];
++		ptr64 = (u64 *)nx_get_fw_offs(adapter);
+ 		flashaddr = NETXEN_IMAGE_START;
+ 
+ 		for (i = 0; i < size; i++) {
+ 			data = cpu_to_le64(ptr64[i]);
+ 
+ 			if (adapter->pci_mem_write(adapter,
+-						flashaddr, &data, 8))
++						flashaddr, data))
+ 				return -EIO;
+ 
+ 			flashaddr += 8;
+ 		}
++
++		size = (__force u32)nx_get_fw_size(adapter) % 8;
++		if (size) {
++			data = cpu_to_le64(ptr64[i]);
++
++			if (adapter->pci_mem_write(adapter,
++						flashaddr, data))
++				return -EIO;
++		}
++
+ 	} else {
+ 		u64 data;
+ 		u32 hi, lo;
+@@ -731,17 +1049,17 @@ netxen_load_firmware(struct netxen_adapt
+ 
+ 		for (i = 0; i < size; i++) {
+ 			if (netxen_rom_fast_read(adapter,
+-					flashaddr, &lo) != 0)
++					flashaddr, (int *)&lo) != 0)
+ 				return -EIO;
+ 			if (netxen_rom_fast_read(adapter,
+-					flashaddr + 4, &hi) != 0)
++					flashaddr + 4, (int *)&hi) != 0)
+ 				return -EIO;
+ 
+ 			/* hi, lo are already in host endian byteorder */
+ 			data = (((u64)hi << 32) | lo);
+ 
+ 			if (adapter->pci_mem_write(adapter,
+-						flashaddr, &data, 8))
++						flashaddr, data))
+ 				return -EIO;
+ 
+ 			flashaddr += 8;
+@@ -760,21 +1078,27 @@ netxen_load_firmware(struct netxen_adapt
+ }
+ 
+ static int
+-netxen_validate_firmware(struct netxen_adapter *adapter, const char *fwname)
++netxen_validate_firmware(struct netxen_adapter *adapter)
+ {
+ 	__le32 val;
+ 	u32 ver, min_ver, bios;
+ 	struct pci_dev *pdev = adapter->pdev;
+ 	const struct firmware *fw = adapter->fw;
++	u8 fw_type = adapter->fw_type;
+ 
+-	if (fw->size < NX_FW_MIN_SIZE)
+-		return -EINVAL;
++	if (fw_type == NX_UNIFIED_ROMIMAGE) {
++		if (netxen_nic_validate_unified_romimage(adapter))
++			return -EINVAL;
++	} else {
++		val = cpu_to_le32(*(u32 *)&fw->data[NX_FW_MAGIC_OFFSET]);
++		if ((__force u32)val != NETXEN_BDINFO_MAGIC)
++			return -EINVAL;
+ 
+-	val = cpu_to_le32(*(u32 *)&fw->data[NX_FW_MAGIC_OFFSET]);
+-	if ((__force u32)val != NETXEN_BDINFO_MAGIC)
+-		return -EINVAL;
++		if (fw->size < NX_FW_MIN_SIZE)
++			return -EINVAL;
++	}
+ 
+-	val = cpu_to_le32(*(u32 *)&fw->data[NX_FW_VERSION_OFFSET]);
++	val = nx_get_fw_version(adapter);
+ 
+ 	if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
+ 		min_ver = NETXEN_VERSION_CODE(4, 0, 216);
+@@ -786,15 +1110,15 @@ netxen_validate_firmware(struct netxen_a
+ 	if ((_major(ver) > _NETXEN_NIC_LINUX_MAJOR) || (ver < min_ver)) {
+ 		dev_err(&pdev->dev,
+ 				"%s: firmware version %d.%d.%d unsupported\n",
+-				fwname, _major(ver), _minor(ver), _build(ver));
++		fw_name[fw_type], _major(ver), _minor(ver), _build(ver));
+ 		return -EINVAL;
+ 	}
+ 
+-	val = cpu_to_le32(*(u32 *)&fw->data[NX_BIOS_VERSION_OFFSET]);
++	val = nx_get_bios_version(adapter);
+ 	netxen_rom_fast_read(adapter, NX_BIOS_VERSION_OFFSET, (int *)&bios);
+ 	if ((__force u32)val != bios) {
+ 		dev_err(&pdev->dev, "%s: firmware bios is incompatible\n",
+-				fwname);
++				fw_name[fw_type]);
+ 		return -EINVAL;
+ 	}
+ 
+@@ -805,7 +1129,7 @@ netxen_validate_firmware(struct netxen_a
+ 	val = NETXEN_DECODE_VERSION(val);
+ 	if (val > ver) {
+ 		dev_info(&pdev->dev, "%s: firmware is older than flash\n",
+-				fwname);
++				fw_name[fw_type]);
+ 		return -EINVAL;
+ 	}
+ 
+@@ -813,12 +1137,51 @@ netxen_validate_firmware(struct netxen_a
+ 	return 0;
+ }
+ 
++static void
++nx_get_next_fwtype(struct netxen_adapter *adapter)
++{
++	u8 fw_type;
++
++	switch (adapter->fw_type) {
++	case NX_UNKNOWN_ROMIMAGE:
++		fw_type = NX_UNIFIED_ROMIMAGE;
++		break;
++
++	case NX_UNIFIED_ROMIMAGE:
++		if (NX_IS_REVISION_P3P(adapter->ahw.revision_id))
++			fw_type = NX_FLASH_ROMIMAGE;
++		else if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
++			fw_type = NX_P2_MN_ROMIMAGE;
++		else if (netxen_p3_has_mn(adapter))
++			fw_type = NX_P3_MN_ROMIMAGE;
++		else
++			fw_type = NX_P3_CT_ROMIMAGE;
++		break;
++
++	case NX_P3_MN_ROMIMAGE:
++		fw_type = NX_P3_CT_ROMIMAGE;
++		break;
++
++	case NX_P2_MN_ROMIMAGE:
++	case NX_P3_CT_ROMIMAGE:
++	default:
++		fw_type = NX_FLASH_ROMIMAGE;
++		break;
++	}
++
++	adapter->fw_type = fw_type;
++}
++
+ static int
+ netxen_p3_has_mn(struct netxen_adapter *adapter)
+ {
+ 	u32 capability, flashed_ver;
+ 	capability = 0;
+ 
++	/* NX2031 always had MN */
++	if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
++		return 1;
++
+ 	netxen_rom_fast_read(adapter,
+ 			NX_FW_VERSION_OFFSET, (int *)&flashed_ver);
+ 	flashed_ver = NETXEN_DECODE_VERSION(flashed_ver);
+@@ -834,49 +1197,29 @@ netxen_p3_has_mn(struct netxen_adapter *
+ 
+ void netxen_request_firmware(struct netxen_adapter *adapter)
+ {
+-	u8 fw_type;
+ 	struct pci_dev *pdev = adapter->pdev;
+ 	int rc = 0;
+ 
+-	if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
+-		fw_type = NX_P2_MN_ROMIMAGE;
+-		goto request_fw;
+-	}
++	adapter->fw_type = NX_UNKNOWN_ROMIMAGE;
+ 
+-	fw_type = netxen_p3_has_mn(adapter) ?
+-		NX_P3_MN_ROMIMAGE : NX_P3_CT_ROMIMAGE;
++next:
++	nx_get_next_fwtype(adapter);
+ 
+-request_fw:
+-	rc = request_firmware(&adapter->fw, fw_name[fw_type], &pdev->dev);
+-	if (rc != 0) {
+-		if (fw_type == NX_P3_MN_ROMIMAGE) {
+-			msleep(1);
+-			fw_type = NX_P3_CT_ROMIMAGE;
+-			goto request_fw;
+-		}
+-
+-		fw_type = NX_FLASH_ROMIMAGE;
++	if (adapter->fw_type == NX_FLASH_ROMIMAGE) {
+ 		adapter->fw = NULL;
+-		goto done;
+-	}
+-
+-	rc = netxen_validate_firmware(adapter, fw_name[fw_type]);
+-	if (rc != 0) {
+-		release_firmware(adapter->fw);
+-
+-		if (fw_type == NX_P3_MN_ROMIMAGE) {
++	} else {
++		rc = request_firmware(&adapter->fw,
++				fw_name[adapter->fw_type], &pdev->dev);
++		if (rc != 0)
++			goto next;
++
++		rc = netxen_validate_firmware(adapter);
++		if (rc != 0) {
++			release_firmware(adapter->fw);
+ 			msleep(1);
+-			fw_type = NX_P3_CT_ROMIMAGE;
+-			goto request_fw;
++			goto next;
+ 		}
+-
+-		fw_type = NX_FLASH_ROMIMAGE;
+-		adapter->fw = NULL;
+-		goto done;
+ 	}
+-
+-done:
+-	adapter->fw_type = fw_type;
+ }
+ 
+ 
+diff -urpN a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c
+--- a/drivers/net/netxen/netxen_nic_main.c	2010-08-30 19:40:21.000000000 -0600
++++ b/drivers/net/netxen/netxen_nic_main.c	2010-08-30 19:42:40.000000000 -0600
+@@ -41,6 +41,7 @@ MODULE_VERSION(NETXEN_NIC_LINUX_VERSIONI
+ MODULE_FIRMWARE(NX_P2_MN_ROMIMAGE_NAME);
+ MODULE_FIRMWARE(NX_P3_CT_ROMIMAGE_NAME);
+ MODULE_FIRMWARE(NX_P3_MN_ROMIMAGE_NAME);
++MODULE_FIRMWARE(NX_UNIFIED_ROMIMAGE_NAME);
+ 
+ char netxen_nic_driver_name[] = "netxen_nic";
+ static char netxen_nic_driver_string[] = "NetXen Network Driver version "

Modified: dists/sid/linux-2.6/debian/patches/series/22
==============================================================================
--- dists/sid/linux-2.6/debian/patches/series/22	Tue Sep  7 01:17:59 2010	(r16247)
+++ dists/sid/linux-2.6/debian/patches/series/22	Wed Sep  8 21:39:07 2010	(r16248)
@@ -100,3 +100,4 @@
 + features/arm/kirkwood-unbreak-pcie-io-port.patch
 + features/arm/dockstar-support.patch
 + bugfix/all/3c59x-Fix-deadlock-in-vortex_error.patch
++ features/all/netxen-unified-fw-image.patch



More information about the Kernel-svn-changes mailing list