[PATCH 2.6.18 4/6] bnx2: Add firmware decompression

2006-06-12 Thread Michael Chan
Add functions to decompress firmware before loading to the internal
CPUs. Compressing the firmware reduces the driver size significantly.

Signed-off-by: Michael Chan [EMAIL PROTECTED]


diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index bdaaad8..1fb0a19 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -2163,6 +2163,8 @@ config TIGON3
 config BNX2
tristate Broadcom NetXtremeII support
depends on PCI
+   select CRC32
+   select ZLIB_INFLATE
help
  This driver supports Broadcom NetXtremeII gigabit Ethernet cards.
 
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 7a3d888..3b1fe1e 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -50,6 +50,7 @@
 #include linux/crc32.h
 #include linux/prefetch.h
 #include linux/cache.h
+#include linux/zlib.h
 
 #include bnx2.h
 #include bnx2_fw.h
@@ -2084,6 +2085,92 @@ bnx2_set_rx_mode(struct net_device *dev)
spin_unlock_bh(bp-phy_lock);
 }
 
+#define FW_BUF_SIZE0x8000
+
+static int
+bnx2_gunzip_init(struct bnx2 *bp)
+{
+   if ((bp-gunzip_buf = vmalloc(FW_BUF_SIZE)) == NULL)
+   goto gunzip_nomem1;
+
+   if ((bp-strm = kmalloc(sizeof(*bp-strm), GFP_KERNEL)) == NULL)
+   goto gunzip_nomem2;
+
+   bp-strm-workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
+   if (bp-strm-workspace == NULL)
+   goto gunzip_nomem3;
+
+   return 0;
+
+gunzip_nomem3:
+   kfree(bp-strm);
+   bp-strm = NULL;
+
+gunzip_nomem2:
+   vfree(bp-gunzip_buf);
+   bp-gunzip_buf = NULL;
+
+gunzip_nomem1:
+   printk(KERN_ERR PFX %s: Cannot allocate firmware buffer for 
+   uncompression.\n, bp-dev-name);
+   return -ENOMEM;
+}
+
+static void
+bnx2_gunzip_end(struct bnx2 *bp)
+{
+   kfree(bp-strm-workspace);
+
+   kfree(bp-strm);
+   bp-strm = NULL;
+
+   if (bp-gunzip_buf) {
+   vfree(bp-gunzip_buf);
+   bp-gunzip_buf = NULL;
+   }
+}
+
+static int
+bnx2_gunzip(struct bnx2 *bp, u8 *zbuf, int len, void **outbuf, int *outlen)
+{
+   int n, rc;
+
+   /* check gzip header */
+   if ((zbuf[0] != 0x1f) || (zbuf[1] != 0x8b) || (zbuf[2] != Z_DEFLATED))
+   return -EINVAL;
+
+   n = 10;
+
+#define FNAME  0x8
+   if (zbuf[3]  FNAME)
+   while (zbuf[n++] != 0);
+
+   bp-strm-next_in = zbuf + n;
+   bp-strm-avail_in = len - n;
+   bp-strm-next_out = bp-gunzip_buf;
+   bp-strm-avail_out = FW_BUF_SIZE;
+
+   rc = zlib_inflateInit2(bp-strm, -MAX_WBITS);
+   if (rc != Z_OK)
+   return rc;
+
+   rc = zlib_inflate(bp-strm, Z_FINISH);
+
+   *outlen = FW_BUF_SIZE - bp-strm-avail_out;
+   *outbuf = bp-gunzip_buf;
+
+   if ((rc != Z_OK)  (rc != Z_STREAM_END))
+   printk(KERN_ERR PFX %s: Firmware decompression error: %s\n,
+  bp-dev-name, bp-strm-msg);
+
+   zlib_inflateEnd(bp-strm);
+
+   if (rc == Z_STREAM_END)
+   return 0;
+
+   return rc;
+}
+
 static void
 load_rv2p_fw(struct bnx2 *bp, u32 *rv2p_code, u32 rv2p_code_len,
u32 rv2p_proc)
@@ -2093,9 +2180,9 @@ load_rv2p_fw(struct bnx2 *bp, u32 *rv2p_
 
 
for (i = 0; i  rv2p_code_len; i += 8) {
-   REG_WR(bp, BNX2_RV2P_INSTR_HIGH, *rv2p_code);
+   REG_WR(bp, BNX2_RV2P_INSTR_HIGH, cpu_to_le32(*rv2p_code));
rv2p_code++;
-   REG_WR(bp, BNX2_RV2P_INSTR_LOW, *rv2p_code);
+   REG_WR(bp, BNX2_RV2P_INSTR_LOW, cpu_to_le32(*rv2p_code));
rv2p_code++;
 
if (rv2p_proc == RV2P_PROC1) {
@@ -2135,7 +,7 @@ load_cpu_fw(struct bnx2 *bp, struct cpu_
int j;
 
for (j = 0; j  (fw-text_len / 4); j++, offset += 4) {
-   REG_WR_IND(bp, offset, fw-text[j]);
+   REG_WR_IND(bp, offset, cpu_to_le32(fw-text[j]));
}
}
 
@@ -2191,15 +2278,32 @@ load_cpu_fw(struct bnx2 *bp, struct cpu_
REG_WR_IND(bp, cpu_reg-mode, val);
 }
 
-static void
+static int
 bnx2_init_cpus(struct bnx2 *bp)
 {
struct cpu_reg cpu_reg;
struct fw_info fw;
+   int rc = 0;
+   void *text;
+   u32 text_len;
+
+   if ((rc = bnx2_gunzip_init(bp)) != 0)
+   return rc;
 
/* Initialize the RV2P processor. */
-   load_rv2p_fw(bp, bnx2_rv2p_proc1, sizeof(bnx2_rv2p_proc1), RV2P_PROC1);
-   load_rv2p_fw(bp, bnx2_rv2p_proc2, sizeof(bnx2_rv2p_proc2), RV2P_PROC2);
+   rc = bnx2_gunzip(bp, bnx2_rv2p_proc1, sizeof(bnx2_rv2p_proc1), text,
+text_len);
+   if (rc)
+   goto init_cpu_err;
+
+   load_rv2p_fw(bp, text, text_len, RV2P_PROC1);
+
+   rc = bnx2_gunzip(bp, bnx2_rv2p_proc2, sizeof(bnx2_rv2p_proc2), text,
+text_len);
+   if (rc)
+   goto init_cpu_err;
+
+   load_rv2p_fw(bp, text, text_len, 

Re: [PATCH 2.6.18 4/6] bnx2: Add firmware decompression

2006-06-12 Thread David Miller
From: Michael Chan [EMAIL PROTECTED]
Date: Mon, 12 Jun 2006 17:17:18 -0700

 Add functions to decompress firmware before loading to the internal
 CPUs. Compressing the firmware reduces the driver size significantly.
 
 Signed-off-by: Michael Chan [EMAIL PROTECTED]
 ...
 +#define FNAME0x8
 + if (zbuf[3]  FNAME)
 + while (zbuf[n++] != 0);

This can potentially loop past the end of zbuf[], so maybe
put a sanity check against 'len' and return non-zero if we
traverse past the end?


-
To unsubscribe from this list: send the line unsubscribe netdev in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html