Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f7185c71 authored by Dhananjay Phadke's avatar Dhananjay Phadke Committed by David S. Miller
Browse files

netxen: fix firmware download



o hold the firmware in memory across suspend, since filesystem
  may not be up after resuming.
o reset the chip after requesting firmware, to minimize downtime
  for NC-SI.

Signed-off-by: default avatarDhananjay Phadke <dhananjay@netxen.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 4ea528a1
Loading
Loading
Loading
Loading
+7 −2
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@
#include <linux/in.h>
#include <linux/tcp.h>
#include <linux/skbuff.h>
#include <linux/firmware.h>

#include <linux/ethtool.h>
#include <linux/mii.h>
@@ -1255,8 +1256,6 @@ struct netxen_adapter {
	u32 flags;
	u32 irq;
	u32 temp;
	u32 fw_major;
	u32 fw_version;

	struct netxen_adapter_stats stats;

@@ -1295,6 +1294,10 @@ struct netxen_adapter {
	struct net_device_stats net_stats;

	nx_nic_intr_coalesce_t coal;

	u32 fw_major;
	u32 fw_version;
	const struct firmware *fw;
};

/*
@@ -1376,6 +1379,8 @@ void netxen_free_adapter_offload(struct netxen_adapter *adapter);
int netxen_initialize_adapter_offload(struct netxen_adapter *adapter);
int netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val);
int netxen_load_firmware(struct netxen_adapter *adapter);
void netxen_request_firmware(struct netxen_adapter *adapter);
void netxen_release_firmware(struct netxen_adapter *adapter);
int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose);

int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp);
+0 −195
Original line number Diff line number Diff line
@@ -32,7 +32,6 @@
#include "netxen_nic_hw.h"
#include "netxen_nic_phan_reg.h"

#include <linux/firmware.h>
#include <net/ip.h>

#define MASK(n) ((1ULL<<(n))-1)
@@ -1016,200 +1015,6 @@ netxen_nic_pci_set_crbwindow_2M(struct netxen_adapter *adapter, ulong *off)
		(ulong)adapter->ahw.pci_base0;
}

static int
netxen_do_load_firmware(struct netxen_adapter *adapter, const char *fwname,
		const struct firmware *fw)
{
	u64 *ptr64;
	u32 i, flashaddr, size;
	struct pci_dev *pdev = adapter->pdev;

	if (fw)
		dev_info(&pdev->dev, "loading firmware from file %s\n", fwname);
	else
		dev_info(&pdev->dev, "loading firmware from flash\n");

	if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
		NXWR32(adapter, NETXEN_ROMUSB_GLB_CAS_RST, 1);

	if (fw) {
		__le64 data;

		size = (NETXEN_IMAGE_START - NETXEN_BOOTLD_START) / 8;

		ptr64 = (u64 *)&fw->data[NETXEN_BOOTLD_START];
		flashaddr = NETXEN_BOOTLD_START;

		for (i = 0; i < size; i++) {
			data = cpu_to_le64(ptr64[i]);
			adapter->pci_mem_write(adapter, flashaddr, &data, 8);
			flashaddr += 8;
		}

		size = *(u32 *)&fw->data[NX_FW_SIZE_OFFSET];
		size = (__force u32)cpu_to_le32(size) / 8;

		ptr64 = (u64 *)&fw->data[NETXEN_IMAGE_START];
		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))
				return -EIO;

			flashaddr += 8;
		}
	} else {
		u32 data;

		size = (NETXEN_IMAGE_START - NETXEN_BOOTLD_START) / 4;
		flashaddr = NETXEN_BOOTLD_START;

		for (i = 0; i < size; i++) {
			if (netxen_rom_fast_read(adapter,
					flashaddr, (int *)&data) != 0)
				return -EIO;

			if (adapter->pci_mem_write(adapter,
						flashaddr, &data, 4))
				return -EIO;

			flashaddr += 4;
		}
	}
	msleep(1);

	if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
		NXWR32(adapter, NETXEN_ROMUSB_GLB_SW_RESET, 0x80001d);
	else {
		NXWR32(adapter, NETXEN_ROMUSB_GLB_CHIP_CLK_CTRL, 0x3fff);
		NXWR32(adapter, NETXEN_ROMUSB_GLB_CAS_RST, 0);
	}

	return 0;
}

static int
netxen_validate_firmware(struct netxen_adapter *adapter, const char *fwname,
		const struct firmware *fw)
{
	__le32 val;
	u32 major, minor, build, ver, min_ver, bios;
	struct pci_dev *pdev = adapter->pdev;

	if (fw->size < NX_FW_MIN_SIZE)
		return -EINVAL;

	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_VERSION_OFFSET]);
	major = (__force u32)val & 0xff;
	minor = ((__force u32)val >> 8) & 0xff;
	build = (__force u32)val >> 16;

	if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
		min_ver = NETXEN_VERSION_CODE(4, 0, 216);
	else
		min_ver = NETXEN_VERSION_CODE(3, 4, 216);

	ver = NETXEN_VERSION_CODE(major, minor, build);

	if ((major > _NETXEN_NIC_LINUX_MAJOR) || (ver < min_ver)) {
		dev_err(&pdev->dev,
				"%s: firmware version %d.%d.%d unsupported\n",
				fwname, major, minor, build);
		return -EINVAL;
	}

	val = cpu_to_le32(*(u32 *)&fw->data[NX_BIOS_VERSION_OFFSET]);
	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);
		return -EINVAL;
	}

	/* check if flashed firmware is newer */
	if (netxen_rom_fast_read(adapter,
			NX_FW_VERSION_OFFSET, (int *)&val))
		return -EIO;
	major = (__force u32)val & 0xff;
	minor = ((__force u32)val >> 8) & 0xff;
	build = (__force u32)val >> 16;
	if (NETXEN_VERSION_CODE(major, minor, build) > ver)
		return -EINVAL;

	NXWR32(adapter, NETXEN_CAM_RAM(0x1fc), NETXEN_BDINFO_MAGIC);
	return 0;
}

static char *fw_name[] = { "nxromimg.bin", "nx3fwct.bin", "nx3fwmn.bin" };

int netxen_load_firmware(struct netxen_adapter *adapter)
{
	u32 capability, flashed_ver;
	const struct firmware *fw;
	int 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;
	} else {
		fw_type = NX_P3_CT_ROMIMAGE;
		goto request_fw;
	}

request_mn:
	capability = 0;

	netxen_rom_fast_read(adapter,
			NX_FW_VERSION_OFFSET, (int *)&flashed_ver);
	if (flashed_ver >= NETXEN_VERSION_CODE(4, 0, 220)) {
		capability = NXRD32(adapter, NX_PEG_TUNE_CAPABILITY);
		if (capability & NX_PEG_TUNE_MN_PRESENT) {
			fw_type = NX_P3_MN_ROMIMAGE;
			goto request_fw;
		}
	}

request_fw:
	rc = request_firmware(&fw, fw_name[fw_type], &pdev->dev);
	if (rc != 0) {
		if (fw_type == NX_P3_CT_ROMIMAGE) {
			msleep(1);
			goto request_mn;
		}

		fw = NULL;
		goto load_fw;
	}

	rc = netxen_validate_firmware(adapter, fw_name[fw_type], fw);
	if (rc != 0) {
		release_firmware(fw);

		if (fw_type == NX_P3_CT_ROMIMAGE) {
			msleep(1);
			goto request_mn;
		}

		fw = NULL;
	}

load_fw:
	rc = netxen_do_load_firmware(adapter, fw_name[fw_type], fw);

	if (fw)
		release_firmware(fw);
	return rc;
}

int
netxen_nic_hw_write_wx_128M(struct netxen_adapter *adapter, ulong off, u32 data)
{
+196 −0
Original line number Diff line number Diff line
@@ -683,6 +683,202 @@ int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose)
	return 0;
}

int
netxen_load_firmware(struct netxen_adapter *adapter)
{
	u64 *ptr64;
	u32 i, flashaddr, size;
	const struct firmware *fw = adapter->fw;

	if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
		NXWR32(adapter, NETXEN_ROMUSB_GLB_CAS_RST, 1);

	if (fw) {
		__le64 data;

		size = (NETXEN_IMAGE_START - NETXEN_BOOTLD_START) / 8;

		ptr64 = (u64 *)&fw->data[NETXEN_BOOTLD_START];
		flashaddr = NETXEN_BOOTLD_START;

		for (i = 0; i < size; i++) {
			data = cpu_to_le64(ptr64[i]);
			adapter->pci_mem_write(adapter, flashaddr, &data, 8);
			flashaddr += 8;
		}

		size = *(u32 *)&fw->data[NX_FW_SIZE_OFFSET];
		size = (__force u32)cpu_to_le32(size) / 8;

		ptr64 = (u64 *)&fw->data[NETXEN_IMAGE_START];
		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))
				return -EIO;

			flashaddr += 8;
		}
	} else {
		u32 data;

		size = (NETXEN_IMAGE_START - NETXEN_BOOTLD_START) / 4;
		flashaddr = NETXEN_BOOTLD_START;

		for (i = 0; i < size; i++) {
			if (netxen_rom_fast_read(adapter,
					flashaddr, (int *)&data) != 0)
				return -EIO;

			if (adapter->pci_mem_write(adapter,
						flashaddr, &data, 4))
				return -EIO;

			flashaddr += 4;
		}
	}
	msleep(1);

	if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
		NXWR32(adapter, NETXEN_ROMUSB_GLB_SW_RESET, 0x80001d);
	else {
		NXWR32(adapter, NETXEN_ROMUSB_GLB_CHIP_CLK_CTRL, 0x3fff);
		NXWR32(adapter, NETXEN_ROMUSB_GLB_CAS_RST, 0);
	}

	return 0;
}

static int
netxen_validate_firmware(struct netxen_adapter *adapter, const char *fwname)
{
	__le32 val;
	u32 major, minor, build, ver, min_ver, bios;
	struct pci_dev *pdev = adapter->pdev;
	const struct firmware *fw = adapter->fw;

	if (fw->size < NX_FW_MIN_SIZE)
		return -EINVAL;

	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_VERSION_OFFSET]);
	major = (__force u32)val & 0xff;
	minor = ((__force u32)val >> 8) & 0xff;
	build = (__force u32)val >> 16;

	if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
		min_ver = NETXEN_VERSION_CODE(4, 0, 216);
	else
		min_ver = NETXEN_VERSION_CODE(3, 4, 216);

	ver = NETXEN_VERSION_CODE(major, minor, build);

	if ((major > _NETXEN_NIC_LINUX_MAJOR) || (ver < min_ver)) {
		dev_err(&pdev->dev,
				"%s: firmware version %d.%d.%d unsupported\n",
				fwname, major, minor, build);
		return -EINVAL;
	}

	val = cpu_to_le32(*(u32 *)&fw->data[NX_BIOS_VERSION_OFFSET]);
	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);
		return -EINVAL;
	}

	/* check if flashed firmware is newer */
	if (netxen_rom_fast_read(adapter,
			NX_FW_VERSION_OFFSET, (int *)&val))
		return -EIO;
	major = (__force u32)val & 0xff;
	minor = ((__force u32)val >> 8) & 0xff;
	build = (__force u32)val >> 16;
	if (NETXEN_VERSION_CODE(major, minor, build) > ver)
		return -EINVAL;

	NXWR32(adapter, NETXEN_CAM_RAM(0x1fc), NETXEN_BDINFO_MAGIC);
	return 0;
}

static char *fw_name[] = { "nxromimg.bin", "nx3fwct.bin", "nx3fwmn.bin" };

void netxen_request_firmware(struct netxen_adapter *adapter)
{
	u32 capability, flashed_ver;
	int 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;
	} else {
		fw_type = NX_P3_CT_ROMIMAGE;
		goto request_fw;
	}

request_mn:
	capability = 0;

	netxen_rom_fast_read(adapter,
			NX_FW_VERSION_OFFSET, (int *)&flashed_ver);
	if (flashed_ver >= NETXEN_VERSION_CODE(4, 0, 220)) {
		capability = NXRD32(adapter, NX_PEG_TUNE_CAPABILITY);
		if (capability & NX_PEG_TUNE_MN_PRESENT) {
			fw_type = NX_P3_MN_ROMIMAGE;
			goto request_fw;
		}
	}

request_fw:
	rc = request_firmware(&adapter->fw, fw_name[fw_type], &pdev->dev);
	if (rc != 0) {
		if (fw_type == NX_P3_CT_ROMIMAGE) {
			msleep(1);
			goto request_mn;
		}

		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_CT_ROMIMAGE) {
			msleep(1);
			goto request_mn;
		}

		adapter->fw = NULL;
		goto done;
	}

done:
	if (adapter->fw)
		dev_info(&pdev->dev, "loading firmware from file %s\n",
				fw_name[fw_type]);
	else
		dev_info(&pdev->dev, "loading firmware from flash\n");
}


void
netxen_release_firmware(struct netxen_adapter *adapter)
{
	if (adapter->fw)
		release_firmware(adapter->fw);
}

int netxen_initialize_adapter_offload(struct netxen_adapter *adapter)
{
	uint64_t addr;
+13 −10
Original line number Diff line number Diff line
@@ -654,19 +654,17 @@ netxen_setup_pci_map(struct netxen_adapter *adapter)
}

static int
netxen_start_firmware(struct netxen_adapter *adapter)
netxen_start_firmware(struct netxen_adapter *adapter, int request_fw)
{
	int val, err, first_boot;
	struct pci_dev *pdev = adapter->pdev;

	int first_driver = 0;
	if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
		if (adapter->ahw.pci_func == 0)
			first_driver = 1;
	} else {
		if (adapter->portnum == 0)
			first_driver = 1;
	}

	if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
		first_driver = (adapter->portnum == 0);
	else
		first_driver = (adapter->ahw.pci_func == 0);

	if (!first_driver)
		return 0;
@@ -679,6 +677,9 @@ netxen_start_firmware(struct netxen_adapter *adapter)
		return err;
	}

	if (request_fw)
		netxen_request_firmware(adapter);

	if (first_boot != 0x55555555) {
		NXWR32(adapter, CRB_CMDPEG_STATE, 0);
		netxen_pinit_from_rom(adapter, 0);
@@ -1014,7 +1015,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
		break;
	}

	err = netxen_start_firmware(adapter);
	err = netxen_start_firmware(adapter, 1);
	if (err)
		goto err_out_iounmap;

@@ -1125,6 +1126,8 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev)

	netxen_cleanup_pci_map(adapter);

	netxen_release_firmware(adapter);

	pci_release_regions(pdev);
	pci_disable_device(pdev);
	pci_set_drvdata(pdev, NULL);
@@ -1176,7 +1179,7 @@ netxen_nic_resume(struct pci_dev *pdev)

	adapter->curr_window = 255;

	err = netxen_start_firmware(adapter);
	err = netxen_start_firmware(adapter, 0);
	if (err) {
		dev_err(&pdev->dev, "failed to start firmware\n");
		return err;