Source: firmware-nonfree Version: 0.14 Severity: wishlist Tags: patch I have written a firmware cutter for the bnx2x driver, as well as a patch to the driver itself (which will be filed as a separate bug report) to use the resulting firmware file.
The firmware cutter works with the versions of the driver in Linux 2.6.26 and 2.6.28-rc9. As I will explain in my other report, I don't have hardware that works with the 2.6.26 version, so my kernel patch is actually a backport of the new driver plus a patch to use the firmware file. Use of this firmware cutter is virtually identical to that of the bnx2 cutter, as I initially followed that design. Basically, $ cd ~/src/linux-2.6 $ git checkout v2.6.28-rc9 $ export KERNEL_VERSION=2.6.28 KERNEL_SOURCE=$(pwd) $ cd ~/src/firmware-nonfree/bnx2x/fwcutter $ make $ ./bnx2x_fwcutter_2.6.28 That will spit out bnx2x-e1-1.45.23.fw and bnx2x-e1h-1.45.23.fw, which contain big-endian representations of init_ops and the data blobs in bnx2x_init_values.h. Also generated in this process is bnx2x_init_ops_offsets_2.6.28.h, which I also include in the linux-2.6 patch. (The offsets to functions in the init_ops array are defined as constants in bnx2x_init_values.h, so I just extract those constants to their own header.) -- John Wright <j...@debian.org>
diff --git a/bnx2x/fwcutter/Makefile b/bnx2x/fwcutter/Makefile new file mode 100644 index 0000000..7f6b93b --- /dev/null +++ b/bnx2x/fwcutter/Makefile @@ -0,0 +1,34 @@ +test := +ifdef KERNEL_SOURCE +test += source +endif +ifdef KERNEL_VERSION +test += version +endif + +ifeq "$(test)" " source version" +CFLAGS += -I$(KERNEL_SOURCE)/include -I$(KERNEL_SOURCE)/drivers/net +#LDFLAGS += -lz + +all: bnx2x_fwcutter_$(KERNEL_VERSION) + +bnx2x_fwcutter_$(KERNEL_VERSION): bnx2x_fwcutter_$(KERNEL_VERSION).c bnx2x_fwcutter_$(KERNEL_VERSION).h bnx2x_fwcutter_$(KERNEL_VERSION)_init.h bnx2x_fwcutter.c bnx2x_init_ops_offsets_$(KERNEL_VERSION).h + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< + +bnx2x_fwcutter_$(KERNEL_VERSION).h: $(KERNEL_SOURCE)/drivers/net/bnx2x.h + grep "^#define BNX2" $^ | grep -v '\\' > $@ + +bnx2x_fwcutter_$(KERNEL_VERSION)_init.h: $(KERNEL_SOURCE)/drivers/net/bnx2x_init.h + grep "^#define OP_" $^ > $@ + +bnx2x_init_ops_offsets_$(KERNEL_VERSION).h: $(KERNEL_SOURCE)/drivers/net/bnx2x_init_values.h + grep -E '^#define .*_(START|END)' $< > $@ + +else +all: + $(error Please define KERNEL_SOURCE and KERNEL_VERSION) +endif + +clean: ALL = $(basename $(wildcard bnx2x_fwcutter_*.c)) +clean: + rm -f $(ALL) $(ALL:=.h) $(ALL:=_init.h) diff --git a/bnx2x/fwcutter/bnx2x_fw_file.h b/bnx2x/fwcutter/bnx2x_fw_file.h new file mode 100644 index 0000000..9b86518 --- /dev/null +++ b/bnx2x/fwcutter/bnx2x_fw_file.h @@ -0,0 +1,17 @@ +struct bnx2x_fw_file_section { + uint32_t len; + uint32_t offset; +}; + +struct bnx2x_fw_file { + struct bnx2x_fw_file_section init_ops; + struct bnx2x_fw_file_section init_data; + struct bnx2x_fw_file_section tsem_int_table_data; + struct bnx2x_fw_file_section tsem_pram_data; + struct bnx2x_fw_file_section usem_int_table_data; + struct bnx2x_fw_file_section usem_pram_data; + struct bnx2x_fw_file_section csem_int_table_data; + struct bnx2x_fw_file_section csem_pram_data; + struct bnx2x_fw_file_section xsem_int_table_data; + struct bnx2x_fw_file_section xsem_pram_data; +}; diff --git a/bnx2x/fwcutter/bnx2x_fwcutter.c b/bnx2x/fwcutter/bnx2x_fwcutter.c new file mode 100644 index 0000000..c0df7a4 --- /dev/null +++ b/bnx2x/fwcutter/bnx2x_fwcutter.c @@ -0,0 +1,101 @@ +#include <byteswap.h> +#include <endian.h> +#include <fcntl.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +typedef uint32_t u32; + +struct raw_op { + u32 op:8; + u32 offset:24; + u32 raw_data; +}; + +#include "bnx2x_fw_file.h" + +#include "bnx2x_reg.h" +#include "bnx2x_init_values.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 uint32_t_buf_to_be32(const uint32_t *input, uint32_t *output, size_t len) +{ + int j; + for (j = 0; j < (len / 4); j++) { + output[j] = cpu_to_be32(input[j]); + } +} + +void write_firmware_data(int fd, struct bnx2x_fw_file_section *section, + const uint32_t *data, size_t len) +{ + off_t offset = lseek(fd, 0, SEEK_CUR); + uint32_t *buf; + unsigned int j; + + section->len = cpu_to_be32(len); + section->offset = cpu_to_be32(offset); + + buf = malloc(len); + uint32_t_buf_to_be32(data, buf, len); + write(fd, buf, len); + free(buf); +} + +void write_firmware(const char *filename, + const uint32_t *init_data, size_t init_data_len, + const uint32_t *tsem_int_table_data, + size_t tsem_int_table_data_len, + const uint32_t *tsem_pram_data, size_t tsem_pram_data_len, + const uint32_t *usem_int_table_data, + size_t usem_int_table_data_len, + const uint32_t *usem_pram_data, size_t usem_pram_data_len, + const uint32_t *csem_int_table_data, + size_t csem_int_table_data_len, + const uint32_t *csem_pram_data, size_t csem_pram_data_len, + const uint32_t *xsem_int_table_data, + size_t xsem_int_table_data_len, + const uint32_t *xsem_pram_data, size_t xsem_pram_data_len) +{ + struct bnx2x_fw_file out; + int fd; + + memset(&out, 0, sizeof(out)); + + printf("Write firmware file: %s\n", filename); + fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666); + lseek(fd, sizeof(out), SEEK_SET); + + write_firmware_data(fd, &out.init_ops, + (uint32_t *)init_ops, sizeof(init_ops)); + write_firmware_data(fd, &out.init_data, + init_data, init_data_len); + write_firmware_data(fd, &out.tsem_int_table_data, + tsem_int_table_data, tsem_int_table_data_len); + write_firmware_data(fd, &out.tsem_pram_data, + tsem_pram_data, tsem_pram_data_len); + write_firmware_data(fd, &out.usem_int_table_data, + usem_int_table_data, usem_int_table_data_len); + write_firmware_data(fd, &out.usem_pram_data, + usem_pram_data, usem_pram_data_len); + write_firmware_data(fd, &out.csem_int_table_data, + csem_int_table_data, csem_int_table_data_len); + write_firmware_data(fd, &out.csem_pram_data, + csem_pram_data, csem_pram_data_len); + write_firmware_data(fd, &out.xsem_int_table_data, + xsem_int_table_data, xsem_int_table_data_len); + write_firmware_data(fd, &out.xsem_pram_data, + xsem_pram_data, xsem_pram_data_len); + + lseek(fd, 0, SEEK_SET); + write(fd, &out, sizeof(out)); + close(fd); +} diff --git a/bnx2x/fwcutter/bnx2x_fwcutter_2.6.26.c b/bnx2x/fwcutter/bnx2x_fwcutter_2.6.26.c new file mode 100644 index 0000000..44e3eda --- /dev/null +++ b/bnx2x/fwcutter/bnx2x_fwcutter_2.6.26.c @@ -0,0 +1,18 @@ +#include "bnx2x_fwcutter_2.6.26.h" +#include "bnx2x_fwcutter_2.6.26_init.h" +#include "bnx2x_fwcutter.c" + +int main() +{ + write_firmware("bnx2x-1.42.4.fw", + init_data, sizeof(init_data), + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0); + return 0; +} diff --git a/bnx2x/fwcutter/bnx2x_fwcutter_2.6.28.c b/bnx2x/fwcutter/bnx2x_fwcutter_2.6.28.c new file mode 100644 index 0000000..f45f22a --- /dev/null +++ b/bnx2x/fwcutter/bnx2x_fwcutter_2.6.28.c @@ -0,0 +1,28 @@ +#include "bnx2x_fwcutter_2.6.28.h" +#include "bnx2x_fwcutter_2.6.28_init.h" +#include "bnx2x_fwcutter.c" + +int main() +{ + write_firmware("bnx2x-e1-1.45.23.fw", + init_data_e1, sizeof(init_data_e1), + tsem_int_table_data_e1, sizeof(tsem_int_table_data_e1), + tsem_pram_data_e1, sizeof(tsem_pram_data_e1), + usem_int_table_data_e1, sizeof(usem_int_table_data_e1), + usem_pram_data_e1, sizeof(usem_pram_data_e1), + csem_int_table_data_e1, sizeof(csem_int_table_data_e1), + csem_pram_data_e1, sizeof(csem_pram_data_e1), + xsem_int_table_data_e1, sizeof(xsem_int_table_data_e1), + xsem_pram_data_e1, sizeof(xsem_pram_data_e1)); + write_firmware("bnx2x-e1h-1.45.23.fw", + init_data_e1h, sizeof(init_data_e1h), + tsem_int_table_data_e1h, sizeof(tsem_int_table_data_e1h), + tsem_pram_data_e1h, sizeof(tsem_pram_data_e1h), + usem_int_table_data_e1h, sizeof(usem_int_table_data_e1h), + usem_pram_data_e1h, sizeof(usem_pram_data_e1h), + csem_int_table_data_e1h, sizeof(csem_int_table_data_e1h), + csem_pram_data_e1h, sizeof(csem_pram_data_e1h), + xsem_int_table_data_e1h, sizeof(xsem_int_table_data_e1h), + xsem_pram_data_e1h, sizeof(xsem_pram_data_e1h)); + return 0; +}