Hi folks This is the first version of the bnx2 request_firmware patch. It works with the 4.0.5 firmware from the bnx2 version in 2.6.25.
I also attached the firmware extractor. Known problems: - MODULE_FIRMWARE spec missing. - Firmware is loaded in netdevice open method. Bastian -- Genius doesn't work on an assembly line basis. You can't simply say, "Today I will be brilliant." -- Kirk, "The Ultimate Computer", stardate 4731.3
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 8b552c6..a42b052 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -46,11 +46,10 @@ #include <linux/crc32.h> #include <linux/prefetch.h> #include <linux/cache.h> -#include <linux/zlib.h> +#include <linux/firmware.h> #include "bnx2.h" -#include "bnx2_fw.h" -#include "bnx2_fw2.h" +#include "bnx2_fw_file.h" #define FW_BUF_SIZE 0x10000 @@ -58,12 +57,20 @@ #define PFX DRV_MODULE_NAME ": " #define DRV_MODULE_VERSION "1.7.3" #define DRV_MODULE_RELDATE "January 29, 2008" +#define FW_FILE_06 "bnx2-06-4.0.5" +#define FW_FILE_09 "bnx2-09-4.0.5" #define RUN_AT(x) (jiffies + (x)) /* Time in jiffies before concluding the transmitter is hung. */ #define TX_TIMEOUT (5*HZ) +#ifdef DEBUG +# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) +#else +# define DPRINTK(fmt, args...) +#endif + static const char version[] __devinitdata = "Broadcom NetXtreme II Gigabit Ethernet Driver " DRV_MODULE_NAME " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; @@ -3161,26 +3168,33 @@ 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 +load_rv2p_fw(struct bnx2 *bp, u32 rv2p_proc, + const struct bnx2_fw_file_section *fw_section, const struct firmware *fw) { - int i; + int i, len, offset; + u32 *data; u32 val; + len = be32_to_cpu(fw_section->len); + offset = be32_to_cpu(fw_section->offset); - for (i = 0; i < rv2p_code_len; i += 8) { - REG_WR(bp, BNX2_RV2P_INSTR_HIGH, le32_to_cpu(*rv2p_code)); - rv2p_code++; - REG_WR(bp, BNX2_RV2P_INSTR_LOW, le32_to_cpu(*rv2p_code)); - rv2p_code++; + if (!len || !offset || len + offset > fw->size) + return -EINVAL; + DPRINTK("load rv2p firmware with length %u from file offset %u\n", len, offset); + + data = (u32 *)(fw->data + offset); + + for (i = 0; i < (len / 4); i += 2) { + REG_WR(bp, BNX2_RV2P_INSTR_HIGH, be32_to_cpu(data[i])); + REG_WR(bp, BNX2_RV2P_INSTR_LOW, be32_to_cpu(data[i+1])); if (rv2p_proc == RV2P_PROC1) { - val = (i / 8) | BNX2_RV2P_PROC1_ADDR_CMD_RDWR; + val = (i / 2) | BNX2_RV2P_PROC1_ADDR_CMD_RDWR; REG_WR(bp, BNX2_RV2P_PROC1_ADDR_CMD, val); } else { - val = (i / 8) | BNX2_RV2P_PROC2_ADDR_CMD_RDWR; + val = (i / 2) | BNX2_RV2P_PROC2_ADDR_CMD_RDWR; REG_WR(bp, BNX2_RV2P_PROC2_ADDR_CMD, val); } } @@ -3192,14 +3206,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, struct cpu_reg *cpu_reg, struct fw_info *fw) +load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, + const struct bnx2_fw_file_entry *fw_entry, const struct firmware *fw) { + u32 addr, len, file_offset; u32 offset; u32 val; - int rc; + u32 *data; /* Halt the CPU. */ val = bnx2_reg_rd_ind(bp, cpu_reg->mode); @@ -3208,64 +3226,87 @@ load_cpu_fw(struct bnx2 *bp, 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) { + 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 = (u32 *)(fw->data + file_offset); + DPRINTK("load text section to %x with length %u from file offset %x\n", addr, len, file_offset); + + offset = cpu_reg->spad_base + (addr - cpu_reg->mips_view_base); + if (len) { int j; - rc = zlib_inflate_blob(fw->text, FW_BUF_SIZE, fw->gz_text, - fw->gz_text_len); - if (rc < 0) - return rc; - - for (j = 0; j < (fw->text_len / 4); j++, offset += 4) { - bnx2_reg_wr_ind(bp, offset, le32_to_cpu(fw->text[j])); + for (j = 0; j < (len / 4); j++, offset += 4) { + bnx2_reg_wr_ind(bp, offset, be32_to_cpu(data[j])); } } /* Load the Data area. */ - offset = cpu_reg->spad_base + (fw->data_addr - cpu_reg->mips_view_base); - if (fw->data) { + 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 = (u32 *)(fw->data + file_offset); + DPRINTK("load data section to %x with length %u from file offset %x\n", addr, len, file_offset); + + 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) { + addr = be32_to_cpu(fw_entry->sbss.addr); + len = be32_to_cpu(fw_entry->sbss.len); + DPRINTK("init sbss section on %x with length %u\n", addr, len); + + offset = cpu_reg->spad_base + (addr - cpu_reg->mips_view_base); + if (len) { int j; - for (j = 0; j < (fw->sbss_len / 4); j++, offset += 4) { + for (j = 0; j < (len / 4); j++, offset += 4) { bnx2_reg_wr_ind(bp, offset, 0); } } /* Load the BSS area. */ - offset = cpu_reg->spad_base + (fw->bss_addr - cpu_reg->mips_view_base); - if (fw->bss_len) { + addr = be32_to_cpu(fw_entry->bss.addr); + len = be32_to_cpu(fw_entry->bss.len); + DPRINTK("init bss section on %x with length %u\n", addr, 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) { + for (j = 0; j < (len / 4); j++, offset += 4) { bnx2_reg_wr_ind(bp, offset, 0); } } /* 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 = (u32 *)(fw->data + file_offset); + DPRINTK("load rodata section to %x with length %u from file offset %x\n", addr, len, 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); + DPRINTK("starting cpu on %x\n", val); + bnx2_reg_wr_ind(bp, cpu_reg->pc, val); /* Start the CPU. */ val = bnx2_reg_rd_ind(bp, cpu_reg->mode); @@ -3280,39 +3321,33 @@ static int bnx2_init_cpus(struct bnx2 *bp) { struct cpu_reg cpu_reg; - struct fw_info *fw; - int rc, rv2p_len; - void *text, *rv2p; + const struct bnx2_fw_file *fw = NULL; + const struct firmware *fw_entry = NULL; + int rc; + const char *fw_file; - /* 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; + if (CHIP_NUM(bp) == CHIP_NUM_5709) + fw_file = FW_FILE_09; + else + fw_file = FW_FILE_06; - load_rv2p_fw(bp, text, rc /* == len */, RV2P_PROC1); + rc = request_firmware(&fw_entry, fw_file, &bp->pdev->dev); + if (rc) { + printk(KERN_ERR PFX "Can't load firmware file %s\n", fw_file); + return rc; + } - 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); + if (fw_entry->size < sizeof(struct bnx2_fw_file)) { + printk(KERN_ERR PFX "Firmware file too smal\n"); + rc = -EINVAL; + goto error; } - 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); + fw = (struct bnx2_fw_file *)fw_entry->data; + + /* Initialize the RV2P processor. */ + load_rv2p_fw(bp, RV2P_PROC1, &fw->rv2p_proc1, fw_entry); + load_rv2p_fw(bp, RV2P_PROC2, &fw->rv2p_proc2, fw_entry); /* Initialize the RX Processor. */ cpu_reg.mode = BNX2_RXP_CPU_MODE; @@ -3328,15 +3363,9 @@ bnx2_init_cpus(struct bnx2 *bp) cpu_reg.spad_base = BNX2_RXP_SCRATCH; cpu_reg.mips_view_base = 0x8000000; - 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, fw); + rc = load_cpu_fw(bp, &cpu_reg, &fw->rxp, fw_entry); if (rc) - goto init_cpu_err; + goto error; /* Initialize the TX Processor. */ cpu_reg.mode = BNX2_TXP_CPU_MODE; @@ -3352,15 +3381,9 @@ bnx2_init_cpus(struct bnx2 *bp) cpu_reg.spad_base = BNX2_TXP_SCRATCH; cpu_reg.mips_view_base = 0x8000000; - 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, fw); + rc = load_cpu_fw(bp, &cpu_reg, &fw->txp, fw_entry); if (rc) - goto init_cpu_err; + goto error; /* Initialize the TX Patch-up Processor. */ cpu_reg.mode = BNX2_TPAT_CPU_MODE; @@ -3376,15 +3399,9 @@ bnx2_init_cpus(struct bnx2 *bp) cpu_reg.spad_base = BNX2_TPAT_SCRATCH; cpu_reg.mips_view_base = 0x8000000; - 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, fw); + rc = load_cpu_fw(bp, &cpu_reg, &fw->tpat, fw_entry); if (rc) - goto init_cpu_err; + goto error; /* Initialize the Completion Processor. */ cpu_reg.mode = BNX2_COM_CPU_MODE; @@ -3400,15 +3417,9 @@ bnx2_init_cpus(struct bnx2 *bp) cpu_reg.spad_base = BNX2_COM_SCRATCH; cpu_reg.mips_view_base = 0x8000000; - 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, fw); + rc = load_cpu_fw(bp, &cpu_reg, &fw->com, fw_entry); if (rc) - goto init_cpu_err; + goto error; /* Initialize the Command Processor. */ cpu_reg.mode = BNX2_CP_CPU_MODE; @@ -3424,16 +3435,10 @@ bnx2_init_cpus(struct bnx2 *bp) cpu_reg.spad_base = BNX2_CP_SCRATCH; cpu_reg.mips_view_base = 0x8000000; - 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, fw); + rc = load_cpu_fw(bp, &cpu_reg, &fw->cp, fw_entry); -init_cpu_err: - vfree(text); +error: + release_firmware(fw_entry); return rc; } diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index 3aa0364..9f67f3d 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -6842,44 +6842,6 @@ 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; -}; - #define RV2P_PROC1 0 #define RV2P_PROC2 1 diff --git a/drivers/net/bnx2_fw_file.h b/drivers/net/bnx2_fw_file.h new file mode 100644 index 0000000..06c003c --- /dev/null +++ b/drivers/net/bnx2_fw_file.h @@ -0,0 +1,25 @@ +struct bnx2_fw_file_section { + uint32_t addr; + uint32_t len; + uint32_t offset; +}; + +struct bnx2_fw_file_entry { + uint32_t start_addr; + struct bnx2_fw_file_section text; + struct bnx2_fw_file_section data; + struct bnx2_fw_file_section sbss; + struct bnx2_fw_file_section bss; + struct bnx2_fw_file_section rodata; +}; + +struct bnx2_fw_file { + struct bnx2_fw_file_entry com; + struct bnx2_fw_file_entry cp; + struct bnx2_fw_file_entry rxp; + struct bnx2_fw_file_entry tpat; + struct bnx2_fw_file_entry txp; + struct bnx2_fw_file_section rv2p_proc1; + struct bnx2_fw_file_section rv2p_proc2; +}; +
#include <assert.h> #include <byteswap.h> #include <endian.h> #include <fcntl.h> #include <sys/stat.h> #include <sys/types.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <zlib.h> #include "bnx2_fw_file.h" struct fw_info { const uint32_t ver_major; const uint32_t ver_minor; const uint32_t ver_fix; const uint32_t start_addr; /* Text section. */ const uint32_t text_addr; const uint32_t text_len; const uint32_t text_index; void *text; const void *gz_text; const uint32_t gz_text_len; /* Data section. */ const uint32_t data_addr; const uint32_t data_len; const uint32_t data_index; const uint32_t *data; /* SBSS section. */ const uint32_t sbss_addr; const uint32_t sbss_len; const uint32_t sbss_index; /* BSS section. */ const uint32_t bss_addr; const uint32_t bss_len; const uint32_t bss_index; /* Read-only section. */ const uint32_t rodata_addr; const uint32_t rodata_len; const uint32_t rodata_index; const uint32_t *rodata; }; typedef uint8_t u8; typedef uint32_t u32; #include "bnx2_fw.h" #include "bnx2_fw2.h" #if __BYTE_ORDER == __LITTLE_ENDIAN #define cpu_to_be32(x) bswap_32(x) #elif __BYTE_ORDER == __BIG_ENDIAN #define cpu_to_be32(x) (x) #endif #define le32_to_be32(x) bswap_32(x) void set_firmware_image_part(struct bnx2_fw_file_section *s, uint32_t addr, uint32_t len) { s->addr = cpu_to_be32(addr); s->len = cpu_to_be32(len); } void write_firmware_flat(int fd, struct bnx2_fw_file_section *out, void *data, int len) { off_t offset = lseek(fd, 0, SEEK_CUR); uint32_t buf[0x10000]; struct z_stream_s strm; memset(&strm, 0, sizeof strm); strm.next_in = (void *)data; strm.avail_in = len; strm.next_out = (void *)buf; strm.avail_out = sizeof buf; int ret = inflateInit2(&strm, -MAX_WBITS); assert(ret == Z_OK); ret = inflate(&strm, Z_FINISH); assert(ret == Z_STREAM_END); unsigned int l = strm.total_out; out->len = cpu_to_be32(l); out->offset = cpu_to_be32(offset); inflateEnd(&strm); for (unsigned int j = 0; j < (l / 4); j++) buf[j] = le32_to_be32(buf[j]); write(fd, buf, l); } void write_firmware_image(int fd, struct bnx2_fw_file_entry *out, struct fw_info *fw) { off_t offset = lseek(fd, 0, SEEK_CUR); out->start_addr = cpu_to_be32(fw->start_addr); set_firmware_image_part(&out->text, fw->text_addr, fw->text_len); out->text.offset = cpu_to_be32(offset); uint32_t buf[0x10000]; struct z_stream_s strm; memset(&strm, 0, sizeof strm); strm.next_in = (void *)fw->gz_text; strm.avail_in = fw->gz_text_len; strm.next_out = (void *)buf; strm.avail_out = sizeof buf; int ret = inflateInit2(&strm, -MAX_WBITS); assert(ret == Z_OK); ret = inflate(&strm, Z_FINISH); assert(ret == Z_STREAM_END); inflateEnd(&strm); for (unsigned int j = 0; j < (fw->text_len / 4); j++) buf[j] = le32_to_be32(buf[j]); offset += write(fd, buf, fw->text_len); if (fw->data_addr) { set_firmware_image_part(&out->data, fw->data_addr, fw->data_len); out->data.offset = cpu_to_be32(offset); for (unsigned int j = 0; j < (fw->data_len / 4); j++) buf[j] = cpu_to_be32(fw->data[j]); offset += write(fd, buf, fw->data_len); } if (fw->sbss_len) set_firmware_image_part(&out->sbss, fw->sbss_addr, fw->sbss_len); if (fw->bss_len) set_firmware_image_part(&out->bss, fw->bss_addr, fw->bss_len); if (fw->rodata_addr) { set_firmware_image_part(&out->rodata, fw->rodata_addr, fw->rodata_len); out->rodata.offset = cpu_to_be32(offset); for (unsigned int j = 0; j < (fw->rodata_len / 4); j++) buf[j] = cpu_to_be32(fw->rodata[j]); offset += write(fd, buf, fw->rodata_len); } } void write_firmware(const char *filename_base, struct fw_info *com_fw, struct fw_info *cp_fw, struct fw_info *rxp_fw, struct fw_info *tpat_fw, struct fw_info *txp_fw, void *rv2p_proc1, int rv2p_proc1_len, void *rv2p_proc2, int rv2p_proc2_len) { struct bnx2_fw_file out; memset(&out, 0, sizeof out); char filename[64]; snprintf(filename, sizeof filename, "%s-%d.%d.%d", filename_base, com_fw->ver_major, com_fw->ver_minor, com_fw->ver_fix); int fd = open(filename, O_WRONLY | O_CREAT, 0666); lseek(fd, sizeof out, SEEK_SET); write_firmware_image(fd, &out.com, com_fw); write_firmware_image(fd, &out.cp, cp_fw); write_firmware_image(fd, &out.rxp, rxp_fw); write_firmware_image(fd, &out.tpat, tpat_fw); write_firmware_image(fd, &out.txp, txp_fw); write_firmware_flat(fd, &out.rv2p_proc1, rv2p_proc1, rv2p_proc1_len); write_firmware_flat(fd, &out.rv2p_proc2, rv2p_proc2, rv2p_proc2_len); lseek(fd, 0, SEEK_SET); write(fd, &out, sizeof out); close(fd); } int main() { write_firmware("bnx2-06", &bnx2_com_fw_06, &bnx2_cp_fw_06, &bnx2_rxp_fw_06, &bnx2_tpat_fw_06, &bnx2_txp_fw_06, bnx2_rv2p_proc1, sizeof bnx2_rv2p_proc1, bnx2_rv2p_proc2, sizeof bnx2_rv2p_proc2); write_firmware("bnx2-09", &bnx2_com_fw_09, &bnx2_cp_fw_09, &bnx2_rxp_fw_09, &bnx2_tpat_fw_09, &bnx2_txp_fw_09, bnx2_xi_rv2p_proc1, sizeof bnx2_xi_rv2p_proc2, bnx2_xi_rv2p_proc2, sizeof bnx2_xi_rv2p_proc2); return EXIT_SUCCESS; }
signature.asc
Description: Digital signature