aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/bnx2.c
diff options
context:
space:
mode:
authorMichael Chan <mchan@broadcom.com>2006-06-13 01:21:25 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2006-06-18 00:30:44 -0400
commitfba9fe911bb4213c3de1d142fe0ee127cd361a78 (patch)
tree2fc7a68e612644cc8ce3ff8e44f210e20f6964b4 /drivers/net/bnx2.c
parent160882722cb21cbe5cead55cf38a5e70fc3af63e (diff)
[BNX2]: Add firmware decompression
Add functions to decompress firmware before loading to the internal CPUs. Compressing the firmware reduces the driver size significantly. Added file name length sanity check in the gzip header to prevent going past the end of buffer [suggested by DaveM]. Signed-off-by: Michael Chan <mchan@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/bnx2.c')
-rw-r--r--drivers/net/bnx2.c159
1 files changed, 147 insertions, 12 deletions
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 031455a8d1dd..c6510e17551b 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -49,6 +49,7 @@
49#include <linux/crc32.h> 49#include <linux/crc32.h>
50#include <linux/prefetch.h> 50#include <linux/prefetch.h>
51#include <linux/cache.h> 51#include <linux/cache.h>
52#include <linux/zlib.h>
52 53
53#include "bnx2.h" 54#include "bnx2.h"
54#include "bnx2_fw.h" 55#include "bnx2_fw.h"
@@ -2083,6 +2084,92 @@ bnx2_set_rx_mode(struct net_device *dev)
2083 spin_unlock_bh(&bp->phy_lock); 2084 spin_unlock_bh(&bp->phy_lock);
2084} 2085}
2085 2086
2087#define FW_BUF_SIZE 0x8000
2088
2089static int
2090bnx2_gunzip_init(struct bnx2 *bp)
2091{
2092 if ((bp->gunzip_buf = vmalloc(FW_BUF_SIZE)) == NULL)
2093 goto gunzip_nomem1;
2094
2095 if ((bp->strm = kmalloc(sizeof(*bp->strm), GFP_KERNEL)) == NULL)
2096 goto gunzip_nomem2;
2097
2098 bp->strm->workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
2099 if (bp->strm->workspace == NULL)
2100 goto gunzip_nomem3;
2101
2102 return 0;
2103
2104gunzip_nomem3:
2105 kfree(bp->strm);
2106 bp->strm = NULL;
2107
2108gunzip_nomem2:
2109 vfree(bp->gunzip_buf);
2110 bp->gunzip_buf = NULL;
2111
2112gunzip_nomem1:
2113 printk(KERN_ERR PFX "%s: Cannot allocate firmware buffer for "
2114 "uncompression.\n", bp->dev->name);
2115 return -ENOMEM;
2116}
2117
2118static void
2119bnx2_gunzip_end(struct bnx2 *bp)
2120{
2121 kfree(bp->strm->workspace);
2122
2123 kfree(bp->strm);
2124 bp->strm = NULL;
2125
2126 if (bp->gunzip_buf) {
2127 vfree(bp->gunzip_buf);
2128 bp->gunzip_buf = NULL;
2129 }
2130}
2131
2132static int
2133bnx2_gunzip(struct bnx2 *bp, u8 *zbuf, int len, void **outbuf, int *outlen)
2134{
2135 int n, rc;
2136
2137 /* check gzip header */
2138 if ((zbuf[0] != 0x1f) || (zbuf[1] != 0x8b) || (zbuf[2] != Z_DEFLATED))
2139 return -EINVAL;
2140
2141 n = 10;
2142
2143#define FNAME 0x8
2144 if (zbuf[3] & FNAME)
2145 while ((zbuf[n++] != 0) && (n < len));
2146
2147 bp->strm->next_in = zbuf + n;
2148 bp->strm->avail_in = len - n;
2149 bp->strm->next_out = bp->gunzip_buf;
2150 bp->strm->avail_out = FW_BUF_SIZE;
2151
2152 rc = zlib_inflateInit2(bp->strm, -MAX_WBITS);
2153 if (rc != Z_OK)
2154 return rc;
2155
2156 rc = zlib_inflate(bp->strm, Z_FINISH);
2157
2158 *outlen = FW_BUF_SIZE - bp->strm->avail_out;
2159 *outbuf = bp->gunzip_buf;
2160
2161 if ((rc != Z_OK) && (rc != Z_STREAM_END))
2162 printk(KERN_ERR PFX "%s: Firmware decompression error: %s\n",
2163 bp->dev->name, bp->strm->msg);
2164
2165 zlib_inflateEnd(bp->strm);
2166
2167 if (rc == Z_STREAM_END)
2168 return 0;
2169
2170 return rc;
2171}
2172
2086static void 2173static void
2087load_rv2p_fw(struct bnx2 *bp, u32 *rv2p_code, u32 rv2p_code_len, 2174load_rv2p_fw(struct bnx2 *bp, u32 *rv2p_code, u32 rv2p_code_len,
2088 u32 rv2p_proc) 2175 u32 rv2p_proc)
@@ -2092,9 +2179,9 @@ load_rv2p_fw(struct bnx2 *bp, u32 *rv2p_code, u32 rv2p_code_len,
2092 2179
2093 2180
2094 for (i = 0; i < rv2p_code_len; i += 8) { 2181 for (i = 0; i < rv2p_code_len; i += 8) {
2095 REG_WR(bp, BNX2_RV2P_INSTR_HIGH, *rv2p_code); 2182 REG_WR(bp, BNX2_RV2P_INSTR_HIGH, cpu_to_le32(*rv2p_code));
2096 rv2p_code++; 2183 rv2p_code++;
2097 REG_WR(bp, BNX2_RV2P_INSTR_LOW, *rv2p_code); 2184 REG_WR(bp, BNX2_RV2P_INSTR_LOW, cpu_to_le32(*rv2p_code));
2098 rv2p_code++; 2185 rv2p_code++;
2099 2186
2100 if (rv2p_proc == RV2P_PROC1) { 2187 if (rv2p_proc == RV2P_PROC1) {
@@ -2134,7 +2221,7 @@ load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw)
2134 int j; 2221 int j;
2135 2222
2136 for (j = 0; j < (fw->text_len / 4); j++, offset += 4) { 2223 for (j = 0; j < (fw->text_len / 4); j++, offset += 4) {
2137 REG_WR_IND(bp, offset, fw->text[j]); 2224 REG_WR_IND(bp, offset, cpu_to_le32(fw->text[j]));
2138 } 2225 }
2139 } 2226 }
2140 2227
@@ -2190,15 +2277,32 @@ load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw)
2190 REG_WR_IND(bp, cpu_reg->mode, val); 2277 REG_WR_IND(bp, cpu_reg->mode, val);
2191} 2278}
2192 2279
2193static void 2280static int
2194bnx2_init_cpus(struct bnx2 *bp) 2281bnx2_init_cpus(struct bnx2 *bp)
2195{ 2282{
2196 struct cpu_reg cpu_reg; 2283 struct cpu_reg cpu_reg;
2197 struct fw_info fw; 2284 struct fw_info fw;
2285 int rc = 0;
2286 void *text;
2287 u32 text_len;
2288
2289 if ((rc = bnx2_gunzip_init(bp)) != 0)
2290 return rc;
2198 2291
2199 /* Initialize the RV2P processor. */ 2292 /* Initialize the RV2P processor. */
2200 load_rv2p_fw(bp, bnx2_rv2p_proc1, sizeof(bnx2_rv2p_proc1), RV2P_PROC1); 2293 rc = bnx2_gunzip(bp, bnx2_rv2p_proc1, sizeof(bnx2_rv2p_proc1), &text,
2201 load_rv2p_fw(bp, bnx2_rv2p_proc2, sizeof(bnx2_rv2p_proc2), RV2P_PROC2); 2294 &text_len);
2295 if (rc)
2296 goto init_cpu_err;
2297
2298 load_rv2p_fw(bp, text, text_len, RV2P_PROC1);
2299
2300 rc = bnx2_gunzip(bp, bnx2_rv2p_proc2, sizeof(bnx2_rv2p_proc2), &text,
2301 &text_len);
2302 if (rc)
2303 goto init_cpu_err;
2304
2305 load_rv2p_fw(bp, text, text_len, RV2P_PROC2);
2202 2306
2203 /* Initialize the RX Processor. */ 2307 /* Initialize the RX Processor. */
2204 cpu_reg.mode = BNX2_RXP_CPU_MODE; 2308 cpu_reg.mode = BNX2_RXP_CPU_MODE;
@@ -2222,7 +2326,13 @@ bnx2_init_cpus(struct bnx2 *bp)
2222 fw.text_addr = bnx2_RXP_b06FwTextAddr; 2326 fw.text_addr = bnx2_RXP_b06FwTextAddr;
2223 fw.text_len = bnx2_RXP_b06FwTextLen; 2327 fw.text_len = bnx2_RXP_b06FwTextLen;
2224 fw.text_index = 0; 2328 fw.text_index = 0;
2225 fw.text = bnx2_RXP_b06FwText; 2329
2330 rc = bnx2_gunzip(bp, bnx2_RXP_b06FwText, sizeof(bnx2_RXP_b06FwText),
2331 &text, &text_len);
2332 if (rc)
2333 goto init_cpu_err;
2334
2335 fw.text = text;
2226 2336
2227 fw.data_addr = bnx2_RXP_b06FwDataAddr; 2337 fw.data_addr = bnx2_RXP_b06FwDataAddr;
2228 fw.data_len = bnx2_RXP_b06FwDataLen; 2338 fw.data_len = bnx2_RXP_b06FwDataLen;
@@ -2268,7 +2378,13 @@ bnx2_init_cpus(struct bnx2 *bp)
2268 fw.text_addr = bnx2_TXP_b06FwTextAddr; 2378 fw.text_addr = bnx2_TXP_b06FwTextAddr;
2269 fw.text_len = bnx2_TXP_b06FwTextLen; 2379 fw.text_len = bnx2_TXP_b06FwTextLen;
2270 fw.text_index = 0; 2380 fw.text_index = 0;
2271 fw.text = bnx2_TXP_b06FwText; 2381
2382 rc = bnx2_gunzip(bp, bnx2_TXP_b06FwText, sizeof(bnx2_TXP_b06FwText),
2383 &text, &text_len);
2384 if (rc)
2385 goto init_cpu_err;
2386
2387 fw.text = text;
2272 2388
2273 fw.data_addr = bnx2_TXP_b06FwDataAddr; 2389 fw.data_addr = bnx2_TXP_b06FwDataAddr;
2274 fw.data_len = bnx2_TXP_b06FwDataLen; 2390 fw.data_len = bnx2_TXP_b06FwDataLen;
@@ -2314,7 +2430,13 @@ bnx2_init_cpus(struct bnx2 *bp)
2314 fw.text_addr = bnx2_TPAT_b06FwTextAddr; 2430 fw.text_addr = bnx2_TPAT_b06FwTextAddr;
2315 fw.text_len = bnx2_TPAT_b06FwTextLen; 2431 fw.text_len = bnx2_TPAT_b06FwTextLen;
2316 fw.text_index = 0; 2432 fw.text_index = 0;
2317 fw.text = bnx2_TPAT_b06FwText; 2433
2434 rc = bnx2_gunzip(bp, bnx2_TPAT_b06FwText, sizeof(bnx2_TPAT_b06FwText),
2435 &text, &text_len);
2436 if (rc)
2437 goto init_cpu_err;
2438
2439 fw.text = text;
2318 2440
2319 fw.data_addr = bnx2_TPAT_b06FwDataAddr; 2441 fw.data_addr = bnx2_TPAT_b06FwDataAddr;
2320 fw.data_len = bnx2_TPAT_b06FwDataLen; 2442 fw.data_len = bnx2_TPAT_b06FwDataLen;
@@ -2360,7 +2482,13 @@ bnx2_init_cpus(struct bnx2 *bp)
2360 fw.text_addr = bnx2_COM_b06FwTextAddr; 2482 fw.text_addr = bnx2_COM_b06FwTextAddr;
2361 fw.text_len = bnx2_COM_b06FwTextLen; 2483 fw.text_len = bnx2_COM_b06FwTextLen;
2362 fw.text_index = 0; 2484 fw.text_index = 0;
2363 fw.text = bnx2_COM_b06FwText; 2485
2486 rc = bnx2_gunzip(bp, bnx2_COM_b06FwText, sizeof(bnx2_COM_b06FwText),
2487 &text, &text_len);
2488 if (rc)
2489 goto init_cpu_err;
2490
2491 fw.text = text;
2364 2492
2365 fw.data_addr = bnx2_COM_b06FwDataAddr; 2493 fw.data_addr = bnx2_COM_b06FwDataAddr;
2366 fw.data_len = bnx2_COM_b06FwDataLen; 2494 fw.data_len = bnx2_COM_b06FwDataLen;
@@ -2384,6 +2512,9 @@ bnx2_init_cpus(struct bnx2 *bp)
2384 2512
2385 load_cpu_fw(bp, &cpu_reg, &fw); 2513 load_cpu_fw(bp, &cpu_reg, &fw);
2386 2514
2515init_cpu_err:
2516 bnx2_gunzip_end(bp);
2517 return rc;
2387} 2518}
2388 2519
2389static int 2520static int
@@ -3256,7 +3387,9 @@ bnx2_init_chip(struct bnx2 *bp)
3256 * context block must have already been enabled. */ 3387 * context block must have already been enabled. */
3257 bnx2_init_context(bp); 3388 bnx2_init_context(bp);
3258 3389
3259 bnx2_init_cpus(bp); 3390 if ((rc = bnx2_init_cpus(bp)) != 0)
3391 return rc;
3392
3260 bnx2_init_nvram(bp); 3393 bnx2_init_nvram(bp);
3261 3394
3262 bnx2_set_mac_addr(bp); 3395 bnx2_set_mac_addr(bp);
@@ -3556,7 +3689,9 @@ bnx2_reset_nic(struct bnx2 *bp, u32 reset_code)
3556 if (rc) 3689 if (rc)
3557 return rc; 3690 return rc;
3558 3691
3559 bnx2_init_chip(bp); 3692 if ((rc = bnx2_init_chip(bp)) != 0)
3693 return rc;
3694
3560 bnx2_init_tx_ring(bp); 3695 bnx2_init_tx_ring(bp);
3561 bnx2_init_rx_ring(bp); 3696 bnx2_init_rx_ring(bp);
3562 return 0; 3697 return 0;