rendered paste body#include "flash.h"
#include "debug.h"
#include "hv.h"
#include "time.h"
/* flash device only allows 256K writes */
#define FLASH_WRITE_UNIT (256*1024)
static __inline__ int check_otheros_flash(unsigned char *buf)
{
int i;
for(i=0; i<16; i++)
if(buf[i] != "cell_ext_os_area"[i])
return 0;
return *(int *)(buf+16) == 1;
}
static int wait_for_io(unsigned long device_id, unsigned long tag,
unsigned long *status, unsigned long timeout)
{
unsigned long rtag;
long r;
for(;;) {
r = lv1_storage_get_async_status(device_id, &rtag, status);
if(!r && rtag == tag)
return 1;
if(!timeout) {
DBG(" TIMEOUT ");
break;
} else if(timeout > 25000) {
usleep(25000);
timeout -= 25000;
} else {
usleep(timeout);
timeout = 0;
}
}
return 0;
}
int set_boot_flag(int boot_flag)
{
long r;
unsigned long v1, v2, ndev, nreg, blk_size, nblks, dma_addr, tag, status;
int bus_index;
unsigned long dev_index, reg_index;
unsigned long bus_id, device_id, region_id;
static unsigned char buf[FLASH_WRITE_UNIT] __attribute__((section(".bss.page_aligned")));
int rc = 0;
/* Find storage bus */
for(bus_index=0; bus_index<128; bus_index++) {
r = lv1_get_repository_node_value(1,
0x0000000062757300+bus_index, /* "bus" */
0x7479706500000000, /* "type" */
0, 0, &v1, &v2);
if(r)
return 0;
if(v1 != 5 /* storage type */)
continue;
r = lv1_get_repository_node_value(1,
0x0000000062757300+bus_index, /* "bus" */
0x6964000000000000, /* "id" */
0, 0, &v1, &v2);
if(r)
return 0;
bus_id = v1;
r = lv1_get_repository_node_value(1,
0x0000000062757300+bus_index, /* "bus" */
0x6e756d5f64657600, /* "num_dev" */
0, 0, &v1, &v2);
if(r)
return 0;
ndev = v1;
/* Look for flash devices */
for(dev_index=0; dev_index<ndev; dev_index++) {
r = lv1_get_repository_node_value(1,
0x0000000062757300+bus_index, /* "bus" */
0x6465760000000000+dev_index, /* "dev" */
0x7479706500000000, /* "type" */
0, &v1, &v2);
if(r)
return 0;
if(v1 != 14 /* SCSI device type for RBC */)
continue;
r = lv1_get_repository_node_value(1,
0x0000000062757300+bus_index, /* "bus" */
0x6465760000000000+dev_index, /* "dev" */
0x626c6b5f73697a65, /* "blk_size" */
0, &v1, &v2);
if(r)
return 0;
blk_size = v1;
if(blk_size < 1 || blk_size > sizeof(buf))
continue;
nblks = sizeof(buf)/blk_size;
r = lv1_get_repository_node_value(1,
0x0000000062757300+bus_index, /* "bus" */
0x6465760000000000+dev_index, /* "dev" */
0x6964000000000000, /* "id" */
0, &v1, &v2);
device_id = v1;
r = lv1_get_repository_node_value(1,
0x0000000062757300+bus_index, /* "bus" */
0x6465760000000000+dev_index, /* "dev" */
0x6e5f726567730000, /* "n_regs" */
0, &v1, &v2);
if(r)
return 0;
nreg = v1;
r = lv1_open_device(bus_id, device_id, 0);
if(r)
continue;
r = lv1_allocate_device_dma_region(bus_id, device_id,
128*1024*1024, 12, 0, &dma_addr);
if(r) {
lv1_close_device(bus_id, device_id);
continue;
}
r = lv1_map_device_dma_region(bus_id, device_id, 0, dma_addr,
128*1024*1024, 0xf800000000000000UL);
if(r) {
lv1_free_device_dma_region(bus_id, device_id, dma_addr);
lv1_close_device(bus_id, device_id);
continue;
}
for(reg_index=0; reg_index<nreg; reg_index++) {
r = lv1_get_repository_node_value(1,
0x0000000062757300+bus_index, /* "bus" */
0x6465760000000000+dev_index, /* "dev" */
0x726567696f6e0000+reg_index, /* "region" */
0x6964000000000000, /* "id" */
&v1, &v2);
if(r)
continue;
region_id = v1;
r = lv1_storage_read(device_id, region_id, 0, nblks, 0,
(unsigned long)buf, &tag);
if(r)
continue;
if(!wait_for_io(device_id, tag, &status, 1000000) ||
status != 0)
continue;
if(!check_otheros_flash(buf))
continue;
rc = -1;
/* Set boot flag */
buf[0x203] = boot_flag;
DBG("lv1_storage_write(%lx, %lx, 0, %lx, 0, %p, %p)",
device_id, region_id, nblks, buf, &tag);
r = lv1_storage_write(device_id, region_id, 0, nblks, 0,
(unsigned long)buf, &tag);
DBG("storage_write => %ld [%lx]\n", r, tag);
if(r)
break;
if(!wait_for_io(device_id, tag, &status, 5000000) ||
status != 0)
break;
DBG("Bootflag successfully set to %d!\n", boot_flag);
rc = 1;
break;
}
lv1_unmap_device_dma_region(bus_id, device_id, dma_addr, 128*1024*1024);
lv1_free_device_dma_region(bus_id, device_id, dma_addr);
lv1_close_device(bus_id, device_id);
if(rc)
return rc;
}
}
return 0;
}