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

Commit 57579f76 authored by Michael Chan's avatar Michael Chan Committed by David S. Miller
Browse files

bnx2: Use request_firmware()



Based on original patch by Ben Hutchings <ben@decadent.org.uk> and
Bastian Blank <waldi@debian.org>, with the following main changes:

Separated the mips firmware and rv2p firmware into different files
to make it easier to update them separately.

Added some code to fixup the rv2p code with run-time information
such as PAGE_SIZE.

Update version to 2.0.0.

Signed-off-by: default avatarMichael Chan <mchan@broadcom.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 5d4d9e8a
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -2234,7 +2234,7 @@ config BNX2
	tristate "Broadcom NetXtremeII support"
	depends on PCI
	select CRC32
	select ZLIB_INFLATE
	select FW_LOADER
	help
	  This driver supports Broadcom NetXtremeII gigabit Ethernet cards.

+210 −141
Original line number Diff line number Diff line
@@ -46,19 +46,20 @@
#include <linux/crc32.h>
#include <linux/prefetch.h>
#include <linux/cache.h>
#include <linux/zlib.h>
#include <linux/firmware.h>
#include <linux/log2.h>

#include "bnx2.h"
#include "bnx2_fw.h"
#include "bnx2_fw2.h"

#define FW_BUF_SIZE		0x10000

#define DRV_MODULE_NAME		"bnx2"
#define PFX DRV_MODULE_NAME	": "
#define DRV_MODULE_VERSION	"1.9.3"
#define DRV_MODULE_RELDATE	"March 17, 2009"
#define DRV_MODULE_VERSION	"2.0.0"
#define DRV_MODULE_RELDATE	"April 2, 2009"
#define FW_MIPS_FILE_06		"bnx2/bnx2-mips-06-4.6.16.fw"
#define FW_RV2P_FILE_06		"bnx2/bnx2-rv2p-06-4.6.16.fw"
#define FW_MIPS_FILE_09		"bnx2/bnx2-mips-09-4.6.17.fw"
#define FW_RV2P_FILE_09		"bnx2/bnx2-rv2p-09-4.6.15.fw"

#define RUN_AT(x) (jiffies + (x))

@@ -72,6 +73,10 @@ MODULE_AUTHOR("Michael Chan <mchan@broadcom.com>");
MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708/5709/5716 Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_MODULE_VERSION);
MODULE_FIRMWARE(FW_MIPS_FILE_06);
MODULE_FIRMWARE(FW_RV2P_FILE_06);
MODULE_FIRMWARE(FW_MIPS_FILE_09);
MODULE_FIRMWARE(FW_RV2P_FILE_09);

static int disable_msi = 0;

@@ -3391,33 +3396,143 @@ bnx2_set_rx_mode(struct net_device *dev)
	spin_unlock_bh(&bp->phy_lock);
}

static void
load_rv2p_fw(struct bnx2 *bp, __le32 *rv2p_code, u32 rv2p_code_len,
	u32 rv2p_proc)
static int __devinit
check_fw_section(const struct firmware *fw,
		 const struct bnx2_fw_file_section *section,
		 u32 alignment, bool non_empty)
{
	u32 offset = be32_to_cpu(section->offset);
	u32 len = be32_to_cpu(section->len);

	if ((offset == 0 && len != 0) || offset >= fw->size || offset & 3)
		return -EINVAL;
	if ((non_empty && len == 0) || len > fw->size - offset ||
	    len & (alignment - 1))
		return -EINVAL;
	return 0;
}

static int __devinit
check_mips_fw_entry(const struct firmware *fw,
		    const struct bnx2_mips_fw_file_entry *entry)
{
	if (check_fw_section(fw, &entry->text, 4, true) ||
	    check_fw_section(fw, &entry->data, 4, false) ||
	    check_fw_section(fw, &entry->rodata, 4, false))
		return -EINVAL;
	return 0;
}

static int __devinit
bnx2_request_firmware(struct bnx2 *bp)
{
	const char *mips_fw_file, *rv2p_fw_file;
	const struct bnx2_mips_fw_file *mips;
	const struct bnx2_rv2p_fw_file *rv2p;
	int rc;

	if (CHIP_NUM(bp) == CHIP_NUM_5709) {
		mips_fw_file = FW_MIPS_FILE_09;
		rv2p_fw_file = FW_RV2P_FILE_09;
	} else {
		mips_fw_file = FW_MIPS_FILE_06;
		rv2p_fw_file = FW_RV2P_FILE_06;
	}

	rc = request_firmware(&bp->mips_firmware, mips_fw_file, &bp->pdev->dev);
	if (rc) {
		printk(KERN_ERR PFX "Can't load firmware file \"%s\"\n",
		       mips_fw_file);
		return rc;
	}

	rc = request_firmware(&bp->rv2p_firmware, rv2p_fw_file, &bp->pdev->dev);
	if (rc) {
		printk(KERN_ERR PFX "Can't load firmware file \"%s\"\n",
		       rv2p_fw_file);
		return rc;
	}
	mips = (const struct bnx2_mips_fw_file *) bp->mips_firmware->data;
	rv2p = (const struct bnx2_rv2p_fw_file *) bp->rv2p_firmware->data;
	if (bp->mips_firmware->size < sizeof(*mips) ||
	    check_mips_fw_entry(bp->mips_firmware, &mips->com) ||
	    check_mips_fw_entry(bp->mips_firmware, &mips->cp) ||
	    check_mips_fw_entry(bp->mips_firmware, &mips->rxp) ||
	    check_mips_fw_entry(bp->mips_firmware, &mips->tpat) ||
	    check_mips_fw_entry(bp->mips_firmware, &mips->txp)) {
		printk(KERN_ERR PFX "Firmware file \"%s\" is invalid\n",
		       mips_fw_file);
		return -EINVAL;
	}
	if (bp->rv2p_firmware->size < sizeof(*rv2p) ||
	    check_fw_section(bp->rv2p_firmware, &rv2p->proc1.rv2p, 8, true) ||
	    check_fw_section(bp->rv2p_firmware, &rv2p->proc2.rv2p, 8, true)) {
		printk(KERN_ERR PFX "Firmware file \"%s\" is invalid\n",
		       rv2p_fw_file);
		return -EINVAL;
	}

	return 0;
}

static u32
rv2p_fw_fixup(u32 rv2p_proc, int idx, u32 loc, u32 rv2p_code)
{
	switch (idx) {
	case RV2P_P1_FIXUP_PAGE_SIZE_IDX:
		rv2p_code &= ~RV2P_BD_PAGE_SIZE_MSK;
		rv2p_code |= RV2P_BD_PAGE_SIZE;
		break;
	}
	return rv2p_code;
}

static int
load_rv2p_fw(struct bnx2 *bp, u32 rv2p_proc,
	     const struct bnx2_rv2p_fw_file_entry *fw_entry)
{
	u32 rv2p_code_len, file_offset;
	__be32 *rv2p_code;
	int i;
	u32 val;
	u32 val, cmd, addr;

	if (rv2p_proc == RV2P_PROC2 && CHIP_NUM(bp) == CHIP_NUM_5709) {
		val = le32_to_cpu(rv2p_code[XI_RV2P_PROC2_MAX_BD_PAGE_LOC]);
		val &= ~XI_RV2P_PROC2_BD_PAGE_SIZE_MSK;
		val |= XI_RV2P_PROC2_BD_PAGE_SIZE;
		rv2p_code[XI_RV2P_PROC2_MAX_BD_PAGE_LOC] = cpu_to_le32(val);
	rv2p_code_len = be32_to_cpu(fw_entry->rv2p.len);
	file_offset = be32_to_cpu(fw_entry->rv2p.offset);

	rv2p_code = (__be32 *)(bp->rv2p_firmware->data + file_offset);

	if (rv2p_proc == RV2P_PROC1) {
		cmd = BNX2_RV2P_PROC1_ADDR_CMD_RDWR;
		addr = BNX2_RV2P_PROC1_ADDR_CMD;
	} else {
		cmd = BNX2_RV2P_PROC2_ADDR_CMD_RDWR;
		addr = BNX2_RV2P_PROC2_ADDR_CMD;
	}

	for (i = 0; i < rv2p_code_len; i += 8) {
		REG_WR(bp, BNX2_RV2P_INSTR_HIGH, le32_to_cpu(*rv2p_code));
		REG_WR(bp, BNX2_RV2P_INSTR_HIGH, be32_to_cpu(*rv2p_code));
		rv2p_code++;
		REG_WR(bp, BNX2_RV2P_INSTR_LOW, le32_to_cpu(*rv2p_code));
		REG_WR(bp, BNX2_RV2P_INSTR_LOW, be32_to_cpu(*rv2p_code));
		rv2p_code++;

		if (rv2p_proc == RV2P_PROC1) {
			val = (i / 8) | BNX2_RV2P_PROC1_ADDR_CMD_RDWR;
			REG_WR(bp, BNX2_RV2P_PROC1_ADDR_CMD, val);
		val = (i / 8) | cmd;
		REG_WR(bp, addr, val);
	}
		else {
			val = (i / 8) | BNX2_RV2P_PROC2_ADDR_CMD_RDWR;
			REG_WR(bp, BNX2_RV2P_PROC2_ADDR_CMD, val);

	rv2p_code = (__be32 *)(bp->rv2p_firmware->data + file_offset);
	for (i = 0; i < 8; i++) {
		u32 loc, code;

		loc = be32_to_cpu(fw_entry->fixup[i]);
		if (loc && ((loc * 4) < rv2p_code_len)) {
			code = be32_to_cpu(*(rv2p_code + loc - 1));
			REG_WR(bp, BNX2_RV2P_INSTR_HIGH, code);
			code = be32_to_cpu(*(rv2p_code + loc));
			code = rv2p_fw_fixup(rv2p_proc, i, loc, code);
			REG_WR(bp, BNX2_RV2P_INSTR_LOW, code);

			val = (loc / 2) | cmd;
			REG_WR(bp, addr, val);
		}
	}

@@ -3428,14 +3543,18 @@ load_rv2p_fw(struct bnx2 *bp, __le32 *rv2p_code, u32 rv2p_code_len,
	else {
		REG_WR(bp, BNX2_RV2P_COMMAND, BNX2_RV2P_COMMAND_PROC2_RESET);
	}

	return 0;
}

static int
load_cpu_fw(struct bnx2 *bp, const struct cpu_reg *cpu_reg, struct fw_info *fw)
load_cpu_fw(struct bnx2 *bp, const struct cpu_reg *cpu_reg,
	    const struct bnx2_mips_fw_file_entry *fw_entry)
{
	u32 addr, len, file_offset;
	__be32 *data;
	u32 offset;
	u32 val;
	int rc;

	/* Halt the CPU. */
	val = bnx2_reg_rd_ind(bp, cpu_reg->mode);
@@ -3444,64 +3563,52 @@ load_cpu_fw(struct bnx2 *bp, const struct cpu_reg *cpu_reg, struct fw_info *fw)
	bnx2_reg_wr_ind(bp, cpu_reg->state, cpu_reg->state_value_clear);

	/* Load the Text area. */
	offset = cpu_reg->spad_base + (fw->text_addr - cpu_reg->mips_view_base);
	if (fw->gz_text) {
		int j;

		rc = zlib_inflate_blob(fw->text, FW_BUF_SIZE, fw->gz_text,
				       fw->gz_text_len);
		if (rc < 0)
			return rc;
	addr = be32_to_cpu(fw_entry->text.addr);
	len = be32_to_cpu(fw_entry->text.len);
	file_offset = be32_to_cpu(fw_entry->text.offset);
	data = (__be32 *)(bp->mips_firmware->data + file_offset);

		for (j = 0; j < (fw->text_len / 4); j++, offset += 4) {
			bnx2_reg_wr_ind(bp, offset, le32_to_cpu(fw->text[j]));
	        }
	}

	/* Load the Data area. */
	offset = cpu_reg->spad_base + (fw->data_addr - cpu_reg->mips_view_base);
	if (fw->data) {
	offset = cpu_reg->spad_base + (addr - cpu_reg->mips_view_base);
	if (len) {
		int j;

		for (j = 0; j < (fw->data_len / 4); j++, offset += 4) {
			bnx2_reg_wr_ind(bp, offset, fw->data[j]);
		for (j = 0; j < (len / 4); j++, offset += 4)
			bnx2_reg_wr_ind(bp, offset, be32_to_cpu(data[j]));
	}
	}

	/* Load the SBSS area. */
	offset = cpu_reg->spad_base + (fw->sbss_addr - cpu_reg->mips_view_base);
	if (fw->sbss_len) {
		int j;

		for (j = 0; j < (fw->sbss_len / 4); j++, offset += 4) {
			bnx2_reg_wr_ind(bp, offset, 0);
		}
	}
	/* Load the Data area. */
	addr = be32_to_cpu(fw_entry->data.addr);
	len = be32_to_cpu(fw_entry->data.len);
	file_offset = be32_to_cpu(fw_entry->data.offset);
	data = (__be32 *)(bp->mips_firmware->data + file_offset);

	/* Load the BSS area. */
	offset = cpu_reg->spad_base + (fw->bss_addr - cpu_reg->mips_view_base);
	if (fw->bss_len) {
	offset = cpu_reg->spad_base + (addr - cpu_reg->mips_view_base);
	if (len) {
		int j;

		for (j = 0; j < (fw->bss_len/4); j++, offset += 4) {
			bnx2_reg_wr_ind(bp, offset, 0);
		}
		for (j = 0; j < (len / 4); j++, offset += 4)
			bnx2_reg_wr_ind(bp, offset, be32_to_cpu(data[j]));
	}

	/* Load the Read-Only area. */
	offset = cpu_reg->spad_base +
		(fw->rodata_addr - cpu_reg->mips_view_base);
	if (fw->rodata) {
	addr = be32_to_cpu(fw_entry->rodata.addr);
	len = be32_to_cpu(fw_entry->rodata.len);
	file_offset = be32_to_cpu(fw_entry->rodata.offset);
	data = (__be32 *)(bp->mips_firmware->data + file_offset);

	offset = cpu_reg->spad_base + (addr - cpu_reg->mips_view_base);
	if (len) {
		int j;

		for (j = 0; j < (fw->rodata_len / 4); j++, offset += 4) {
			bnx2_reg_wr_ind(bp, offset, fw->rodata[j]);
		}
		for (j = 0; j < (len / 4); j++, offset += 4)
			bnx2_reg_wr_ind(bp, offset, be32_to_cpu(data[j]));
	}

	/* Clear the pre-fetch instruction. */
	bnx2_reg_wr_ind(bp, cpu_reg->inst, 0);
	bnx2_reg_wr_ind(bp, cpu_reg->pc, fw->start_addr);

	val = be32_to_cpu(fw_entry->start_addr);
	bnx2_reg_wr_ind(bp, cpu_reg->pc, val);

	/* Start the CPU. */
	val = bnx2_reg_rd_ind(bp, cpu_reg->mode);
@@ -3515,95 +3622,40 @@ load_cpu_fw(struct bnx2 *bp, const struct cpu_reg *cpu_reg, struct fw_info *fw)
static int
bnx2_init_cpus(struct bnx2 *bp)
{
	struct fw_info *fw;
	int rc, rv2p_len;
	void *text, *rv2p;
	const struct bnx2_mips_fw_file *mips_fw =
		(const struct bnx2_mips_fw_file *) bp->mips_firmware->data;
	const struct bnx2_rv2p_fw_file *rv2p_fw =
		(const struct bnx2_rv2p_fw_file *) bp->rv2p_firmware->data;
	int rc;

	/* Initialize the RV2P processor. */
	text = vmalloc(FW_BUF_SIZE);
	if (!text)
		return -ENOMEM;
	if (CHIP_NUM(bp) == CHIP_NUM_5709) {
		rv2p = bnx2_xi_rv2p_proc1;
		rv2p_len = sizeof(bnx2_xi_rv2p_proc1);
	} else {
		rv2p = bnx2_rv2p_proc1;
		rv2p_len = sizeof(bnx2_rv2p_proc1);
	}
	rc = zlib_inflate_blob(text, FW_BUF_SIZE, rv2p, rv2p_len);
	if (rc < 0)
		goto init_cpu_err;

	load_rv2p_fw(bp, text, rc /* == len */, RV2P_PROC1);

	if (CHIP_NUM(bp) == CHIP_NUM_5709) {
		rv2p = bnx2_xi_rv2p_proc2;
		rv2p_len = sizeof(bnx2_xi_rv2p_proc2);
	} else {
		rv2p = bnx2_rv2p_proc2;
		rv2p_len = sizeof(bnx2_rv2p_proc2);
	}
	rc = zlib_inflate_blob(text, FW_BUF_SIZE, rv2p, rv2p_len);
	if (rc < 0)
		goto init_cpu_err;

	load_rv2p_fw(bp, text, rc /* == len */, RV2P_PROC2);
	load_rv2p_fw(bp, RV2P_PROC1, &rv2p_fw->proc1);
	load_rv2p_fw(bp, RV2P_PROC2, &rv2p_fw->proc2);

	/* Initialize the RX Processor. */
	if (CHIP_NUM(bp) == CHIP_NUM_5709)
		fw = &bnx2_rxp_fw_09;
	else
		fw = &bnx2_rxp_fw_06;

	fw->text = text;
	rc = load_cpu_fw(bp, &cpu_reg_rxp, fw);
	rc = load_cpu_fw(bp, &cpu_reg_rxp, &mips_fw->rxp);
	if (rc)
		goto init_cpu_err;

	/* Initialize the TX Processor. */
	if (CHIP_NUM(bp) == CHIP_NUM_5709)
		fw = &bnx2_txp_fw_09;
	else
		fw = &bnx2_txp_fw_06;

	fw->text = text;
	rc = load_cpu_fw(bp, &cpu_reg_txp, fw);
	rc = load_cpu_fw(bp, &cpu_reg_txp, &mips_fw->txp);
	if (rc)
		goto init_cpu_err;

	/* Initialize the TX Patch-up Processor. */
	if (CHIP_NUM(bp) == CHIP_NUM_5709)
		fw = &bnx2_tpat_fw_09;
	else
		fw = &bnx2_tpat_fw_06;

	fw->text = text;
	rc = load_cpu_fw(bp, &cpu_reg_tpat, fw);
	rc = load_cpu_fw(bp, &cpu_reg_tpat, &mips_fw->tpat);
	if (rc)
		goto init_cpu_err;

	/* Initialize the Completion Processor. */
	if (CHIP_NUM(bp) == CHIP_NUM_5709)
		fw = &bnx2_com_fw_09;
	else
		fw = &bnx2_com_fw_06;

	fw->text = text;
	rc = load_cpu_fw(bp, &cpu_reg_com, fw);
	rc = load_cpu_fw(bp, &cpu_reg_com, &mips_fw->com);
	if (rc)
		goto init_cpu_err;

	/* Initialize the Command Processor. */
	if (CHIP_NUM(bp) == CHIP_NUM_5709)
		fw = &bnx2_cp_fw_09;
	else
		fw = &bnx2_cp_fw_06;

	fw->text = text;
	rc = load_cpu_fw(bp, &cpu_reg_cp, fw);
	rc = load_cpu_fw(bp, &cpu_reg_cp, &mips_fw->cp);

init_cpu_err:
	vfree(text);
	return rc;
}

@@ -7807,6 +7859,10 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)

	pci_set_drvdata(pdev, dev);

	rc = bnx2_request_firmware(bp);
	if (rc)
		goto error;

	memcpy(dev->dev_addr, bp->mac_addr, 6);
	memcpy(dev->perm_addr, bp->mac_addr, 6);

@@ -7823,13 +7879,7 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)

	if ((rc = register_netdev(dev))) {
		dev_err(&pdev->dev, "Cannot register net device\n");
		if (bp->regview)
			iounmap(bp->regview);
		pci_release_regions(pdev);
		pci_disable_device(pdev);
		pci_set_drvdata(pdev, NULL);
		free_netdev(dev);
		return rc;
		goto error;
	}

	printk(KERN_INFO "%s: %s (%c%d) %s found at mem %lx, "
@@ -7843,6 +7893,20 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
		bp->pdev->irq, dev->dev_addr);

	return 0;

error:
	if (bp->mips_firmware)
		release_firmware(bp->mips_firmware);
	if (bp->rv2p_firmware)
		release_firmware(bp->rv2p_firmware);

	if (bp->regview)
		iounmap(bp->regview);
	pci_release_regions(pdev);
	pci_disable_device(pdev);
	pci_set_drvdata(pdev, NULL);
	free_netdev(dev);
	return rc;
}

static void __devexit
@@ -7855,6 +7919,11 @@ bnx2_remove_one(struct pci_dev *pdev)

	unregister_netdev(dev);

	if (bp->mips_firmware)
		release_firmware(bp->mips_firmware);
	if (bp->rv2p_firmware)
		release_firmware(bp->rv2p_firmware);

	if (bp->regview)
		iounmap(bp->regview);

+35 −36
Original line number Diff line number Diff line
@@ -6885,6 +6885,8 @@ struct bnx2 {

	u32			idle_chk_status_idx;

	const struct firmware	*mips_firmware;
	const struct firmware	*rv2p_firmware;
};

#define REG_RD(bp, offset)					\
@@ -6915,44 +6917,41 @@ struct cpu_reg {
	u32 mips_view_base;
};

struct fw_info {
	const u32 ver_major;
	const u32 ver_minor;
	const u32 ver_fix;

	const u32 start_addr;

	/* Text section. */
	const u32 text_addr;
	const u32 text_len;
	const u32 text_index;
	__le32 *text;
	u8 *gz_text;
	const u32 gz_text_len;

	/* Data section. */
	const u32 data_addr;
	const u32 data_len;
	const u32 data_index;
	const u32 *data;

	/* SBSS section. */
	const u32 sbss_addr;
	const u32 sbss_len;
	const u32 sbss_index;

	/* BSS section. */
	const u32 bss_addr;
	const u32 bss_len;
	const u32 bss_index;

	/* Read-only section. */
	const u32 rodata_addr;
	const u32 rodata_len;
	const u32 rodata_index;
	const u32 *rodata;
struct bnx2_fw_file_section {
	__be32 addr;
	__be32 len;
	__be32 offset;
};

struct bnx2_mips_fw_file_entry {
	__be32 start_addr;
	struct bnx2_fw_file_section text;
	struct bnx2_fw_file_section data;
	struct bnx2_fw_file_section rodata;
};

struct bnx2_rv2p_fw_file_entry {
	struct bnx2_fw_file_section rv2p;
	__be32 fixup[8];
};

struct bnx2_mips_fw_file {
	struct bnx2_mips_fw_file_entry com;
	struct bnx2_mips_fw_file_entry cp;
	struct bnx2_mips_fw_file_entry rxp;
	struct bnx2_mips_fw_file_entry tpat;
	struct bnx2_mips_fw_file_entry txp;
};

struct bnx2_rv2p_fw_file {
	struct bnx2_rv2p_fw_file_entry proc1;
	struct bnx2_rv2p_fw_file_entry proc2;
};

#define RV2P_P1_FIXUP_PAGE_SIZE_IDX		0
#define RV2P_BD_PAGE_SIZE_MSK			0xffff
#define RV2P_BD_PAGE_SIZE			((BCM_PAGE_SIZE / 16) - 1)

#define RV2P_PROC1                              0
#define RV2P_PROC2                              1

+1 −4377

File changed.

File size exceeds preview limit.

drivers/net/bnx2_fw2.h

deleted100644 → 0
+0 −4547

File deleted.

File size exceeds preview limit.

Loading