Skip to content

Commit

Permalink
firmware: convert Ambassador ATM driver to request_firmware()
Browse files Browse the repository at this point in the history
Since it had various regions to be loaded to separate addresses, and it
wanted to do them in fairly small chunks anyway, switch it to use the
new ihex code. Encode the start address in the first record.

Signed-off-by: David Woodhouse <[email protected]>
Acked-by: Chas Williams <[email protected]>
  • Loading branch information
dwmw2 authored and David Woodhouse committed Jul 10, 2008
1 parent ec6752f commit 27d202f
Show file tree
Hide file tree
Showing 8 changed files with 265 additions and 2,170 deletions.
6 changes: 3 additions & 3 deletions drivers/atm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ fore_200e-objs := fore200e.o
hostprogs-y := fore200e_mkfirm

# Files generated that shall be removed upon make clean
clean-files := atmsar11.bin atmsar11.bin1 atmsar11.bin2 pca200e.bin \
pca200e.bin1 pca200e.bin2 pca200e_ecd.bin pca200e_ecd.bin1 \
pca200e_ecd.bin2 sba200e_ecd.bin sba200e_ecd.bin1 sba200e_ecd.bin2
clean-files := pca200e.bin pca200e.bin1 pca200e.bin2 pca200e_ecd.bin \
pca200e_ecd.bin1 pca200e_ecd.bin2 sba200e_ecd.bin sba200e_ecd.bin1 \
sba200e_ecd.bin2
# Firmware generated that shall be removed upon make clean
clean-files += fore200e_pca_fw.c fore200e_sba_fw.c

Expand Down
140 changes: 57 additions & 83 deletions drivers/atm/ambassador.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
#include <linux/poison.h>
#include <linux/bitrev.h>
#include <linux/mutex.h>
#include <linux/firmware.h>
#include <linux/ihex.h>

#include <asm/atomic.h>
#include <asm/io.h>
Expand Down Expand Up @@ -290,29 +292,6 @@ static inline void __init show_version (void) {
*/

/********** microcode **********/

#ifdef AMB_NEW_MICROCODE
#define UCODE(x) UCODE2(atmsar12.x)
#else
#define UCODE(x) UCODE2(atmsar11.x)
#endif
#define UCODE2(x) #x

static u32 __devinitdata ucode_start =
#include UCODE(start)
;

static region __devinitdata ucode_regions[] = {
#include UCODE(regions)
{ 0, 0 }
};

static u32 __devinitdata ucode_data[] = {
#include UCODE(data)
0xdeadbeef
};

static void do_housekeeping (unsigned long arg);
/********** globals **********/

Expand Down Expand Up @@ -1841,45 +1820,34 @@ static int __devinit get_loader_version (loader_block * lb,

/* loader: write memory data blocks */

static int __devinit loader_write (loader_block * lb,
const amb_dev * dev, const u32 * data,
u32 address, unsigned int count) {
unsigned int i;
static int __devinit loader_write (loader_block* lb,
const amb_dev *dev,
const struct ihex_binrec *rec) {
transfer_block * tb = &lb->payload.transfer;

PRINTD (DBG_FLOW|DBG_LOAD, "loader_write");

if (count > MAX_TRANSFER_DATA)
return -EINVAL;
tb->address = cpu_to_be32 (address);
tb->count = cpu_to_be32 (count);
for (i = 0; i < count; ++i)
tb->data[i] = cpu_to_be32 (data[i]);

tb->address = rec->addr;
tb->count = cpu_to_be32(be16_to_cpu(rec->len) / 4);
memcpy(tb->data, rec->data, be16_to_cpu(rec->len));
return do_loader_command (lb, dev, write_adapter_memory);
}

/* loader: verify memory data blocks */

static int __devinit loader_verify (loader_block * lb,
const amb_dev * dev, const u32 * data,
u32 address, unsigned int count) {
unsigned int i;
const amb_dev *dev,
const struct ihex_binrec *rec) {
transfer_block * tb = &lb->payload.transfer;
int res;

PRINTD (DBG_FLOW|DBG_LOAD, "loader_verify");

if (count > MAX_TRANSFER_DATA)
return -EINVAL;
tb->address = cpu_to_be32 (address);
tb->count = cpu_to_be32 (count);
tb->address = rec->addr;
tb->count = cpu_to_be32(be16_to_cpu(rec->len) / 4);
res = do_loader_command (lb, dev, read_adapter_memory);
if (!res)
for (i = 0; i < count; ++i)
if (tb->data[i] != cpu_to_be32 (data[i])) {
res = -EINVAL;
break;
}
if (!res && memcmp(tb->data, rec->data, be16_to_cpu(rec->len)))
res = -EINVAL;
return res;
}

Expand Down Expand Up @@ -1962,47 +1930,53 @@ static int amb_reset (amb_dev * dev, int diags) {
/********** transfer and start the microcode **********/

static int __devinit ucode_init (loader_block * lb, amb_dev * dev) {
unsigned int i = 0;
unsigned int total = 0;
const u32 * pointer = ucode_data;
u32 address;
unsigned int count;
const struct firmware *fw;
unsigned long start_address;
const struct ihex_binrec *rec;
int res;

res = request_ihex_firmware(&fw, "atmsar11.fw", &dev->pci_dev->dev);
if (res) {
PRINTK (KERN_ERR, "Cannot load microcode data");
return res;
}

/* First record contains just the start address */
rec = (const struct ihex_binrec *)fw->data;
if (be16_to_cpu(rec->len) != sizeof(__be32) || be32_to_cpu(rec->addr)) {
PRINTK (KERN_ERR, "Bad microcode data (no start record)");
return -EINVAL;
}
start_address = be32_to_cpup((__be32 *)rec->data);

rec = ihex_next_binrec(rec);

PRINTD (DBG_FLOW|DBG_LOAD, "ucode_init");

while (address = ucode_regions[i].start,
count = ucode_regions[i].count) {
PRINTD (DBG_LOAD, "starting region (%x, %u)", address, count);
while (count) {
unsigned int words;
if (count <= MAX_TRANSFER_DATA)
words = count;
else
words = MAX_TRANSFER_DATA;
total += words;
res = loader_write (lb, dev, pointer, address, words);
if (res)
return res;
res = loader_verify (lb, dev, pointer, address, words);
if (res)
return res;
count -= words;
address += sizeof(u32) * words;
pointer += words;

while (rec) {
PRINTD (DBG_LOAD, "starting region (%x, %u)", be32_to_cpu(rec->addr),
be16_to_cpu(rec->len));
if (be16_to_cpu(rec->len) > 4 * MAX_TRANSFER_DATA) {
PRINTK (KERN_ERR, "Bad microcode data (record too long)");
return -EINVAL;
}
i += 1;
}
if (*pointer == ATM_POISON) {
return loader_start (lb, dev, ucode_start);
} else {
// cast needed as there is no %? for pointer differnces
PRINTD (DBG_LOAD|DBG_ERR,
"offset=%li, *pointer=%x, address=%x, total=%u",
(long) (pointer - ucode_data), *pointer, address, total);
PRINTK (KERN_ERR, "incorrect microcode data");
return -ENOMEM;
if (be16_to_cpu(rec->len) & 3) {
PRINTK (KERN_ERR, "Bad microcode data (odd number of bytes)");
return -EINVAL;
}
res = loader_write(lb, dev, rec);
if (res)
break;

res = loader_verify(lb, dev, rec);
if (res)
break;
}
release_firmware(fw);
if (!res)
res = loader_start(lb, dev, start_address);

return res;
}

/********** give adapter parameters **********/
Expand Down
11 changes: 0 additions & 11 deletions drivers/atm/ambassador.h
Original file line number Diff line number Diff line change
Expand Up @@ -656,17 +656,6 @@ typedef struct amb_dev amb_dev;
#define AMB_DEV(atm_dev) ((amb_dev *) (atm_dev)->dev_data)
#define AMB_VCC(atm_vcc) ((amb_vcc *) (atm_vcc)->dev_data)

/* the microcode */

typedef struct {
u32 start;
unsigned int count;
} region;

static region ucode_regions[];
static u32 ucode_data[];
static u32 ucode_start;

/* rate rounding */

typedef enum {
Expand Down
Loading

0 comments on commit 27d202f

Please sign in to comment.