/* * net/spidupd.c * * Copyright (C) 2009 SPiDCOM Technologies * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * Author(s): * Drasko DRASKOVIC, drasko.draskovic@spidcom.com */ #include #include #include #include #include #include #include "spidupd.h" /** Debug management */ #undef ET_DEBUG //#define ET_DEBUG #ifdef ET_DEBUG #define TRACE(...) printf("SPiDUPD: " __VA_ARGS__) #else #define TRACE(...) #endif /** Flash image status */ #define BAD_MAGIC_NUMBER 1 #define INDEX_NOT_VALID 2 #define IMAGE_NOT_VALID 3 #define WRONG_IMAGE_ARCH 4 #define WRONG_IMAGE_TYPE 5 #define UPD_NOT_FINISHED 6 #define IMAGE_NOT_SUCCESS 7 #define IMAGE_OK 8 #define IMAGE_OK_ORIGIN 9 /** Max flash images allowed */ #define MAX_IMG 10 #if (CONFIG_COMMANDS & CFG_CMD_NET) /** Timeouts to stop Netloop */ #define TIMEOUT 1 /* TO for a lost pkt in seconds */ #ifndef CONFIG_NET_RETRY_COUNT #define TIMEOUT_COUNT 0 /* TO before giving up */ #else #define TIMEOUT_COUNT (CONFIG_NET_RETRY_COUNT * 2) #endif /** Flash writing timeout */ #define FLASH_WRITE_TOUT 2*60 /* TO in seconds */ /** Different states of FSM */ #define STATE_UPD_START 1 #define STATE_UPD_TRANSFER 2 #define STATE_UPD_END 3 #define STATE_UPD_IND 4 #define UPD_START STATE_UPD_START #define UPD_TRANSFER STATE_UPD_TRANSFER #define UPD_END STATE_UPD_END #define UPD_IND STATE_UPD_IND /** Informations about place to update image */ struct update_place { ulong flash_addr; ulong ram_addr; ulong index; ulong nb_img; ulong img_0_addr; ulong img_max_size; ulong correct_img_exist; ulong correct_type; ulong correct_archi; char versions[MAX_IMG][16]; }; /** Informations about image to update */ struct update_image { int num_rx_blk; int len; }; /** Processus management */ struct update_process { int state; int response; int modem_busy; int timeout; struct update_place *place; struct update_image *image; VsUpdStartCnf_t start_cnf; VsUpdTransfCnf_t transfer_cnf; VsUpdEndCnf_t end_cnf; VsUpdEndInd_t end_ind; }; /** Global processus structure */ struct update_process ctx; /** Global image structure */ struct update_image g_upd_image; /** Global place structure */ struct update_place g_upd_place; /** Global image desc structure */ spidcom_image_desc_t g_img_desc; /** Reference to flash organization */ extern flash_info_t flash_info[]; /**************************| Utility functions |***************************/ /** * Flush Instruction and Data caches. */ static void flush_caches(void) { unsigned int c7format = 0; __asm__ __volatile__( "mcr p15, 0, %0, c7, c6, 0 @ invalidate caches \n\t" : : "r" (c7format) : "memory"); } /** * Copy the Image descriptor in RAM. * * \param addr source address of the descriptor. * \param desc RAM address of the copy. * \return error code. */ static int load_header(spidcom_image_desc_t *desc, uchar *addr) { if(IS_IN_SPI_RANGE(addr)) { /* Source address is in flash */ if(flash_read_spi(addr, (unsigned char *)desc, sizeof(spidcom_image_desc_t), 1, 0) != ERR_OK) { return -1; } } else { /* Source is in RAM */ memmove(desc, addr, sizeof(spidcom_image_desc_t)); } return 0; } /** * Check Image descriptor to see if it is correct or not. * * \param desc Image descriptor pointer. * \return Image status. */ static int check_img(spidcom_image_desc_t *desc) { if(strcmp(desc->magic, SPIDCOM_IMG_DESC_MAGIC)) { return BAD_MAGIC_NUMBER; } if(desc->arch != SPIDCOM_IMG_DESC_SPC300) { return WRONG_IMAGE_ARCH; } if(desc->type != SPIDCOM_IMG_DESC_NORMAL_TYPE) { return WRONG_IMAGE_TYPE; } if(desc->index == SPIDCOM_IMG_DESC_ORIGIN_INDEX) { return IMAGE_OK_ORIGIN; } if(desc->is_not_update != 0) { return UPD_NOT_FINISHED; } if(desc->is_valid == 0) { return IMAGE_NOT_VALID; } if(desc->index == SPIDCOM_IMG_DESC_INVALID_INDEX) { return INDEX_NOT_VALID; } if(!desc->is_1st_boot && desc->is_not_success) { return IMAGE_NOT_SUCCESS; } return IMAGE_OK; } /** * Find image max size. * * \param bd board info structure. * \return image max size. */ static __inline__ ulong find_img_max_size(bd_t *bd) { /* First image address is stored under NVRAM */ spc300_nvram_t *nvram = (spc300_nvram_t *)(bd->bi_nvram_addr); /* We can use SPI Direct Access because image_max_size is a uint32_t */ return nvram->img_max_size; } /** * Find Flash offset of image 0. * * \param bd board info structure. * \return image 0 offset. */ static __inline__ ulong find_img_1st_offset(bd_t *bd) { /* First image address is stored under NVRAM */ spc300_nvram_t *nvram = (spc300_nvram_t *)(bd->bi_nvram_addr); /* We can use SPI Direct Access because nb_images is a uint32_t */ return nvram->img_0_offset; } /** * Find the number of allowed images in flash. * * \param bd board info structure. * \return number of image allowed. */ static __inline__ ulong find_nb_images(bd_t* bd) { /* Number of allowed images is stored under NVRAM */ spc300_nvram_t *nvram = (spc300_nvram_t *)(bd->bi_nvram_addr); /* We can use SPI Direct Access because nb_images is a uint32_t */ return nvram->nb_images; } /** * Choose the better update place. * * \param img_nb number of allowed images in flash. * \param img_max_size max size of an image. * \param place update place information structure. * \return error code. */ static int select_image(int img_nb, ulong img_0_addr, ulong img_max_size, struct update_place *place) { spidcom_image_desc_t *desc = &g_img_desc; int img_state; ulong min_index = 0xFFFFFFFF; ulong max_index = 0; int sel_img_ok = -1; int sel_img_or = -1; int sel_img_ko = -1; int one_img_ok = 0; int i; place->correct_img_exist = 0; /* Clear previous stored version */ for(i=0 ; iversions[i][0] = '\0'; for(i=0 ; i select it */ if (desc->index <= min_index) { min_index = desc->index; sel_img_ok = i; } /* Store max index */ if (desc->index > max_index) { max_index = desc->index; } /* Precise type and archi allowed */ place->correct_img_exist = 1; place->correct_type = desc->type; place->correct_archi = desc->arch; /* Store the version */ strncpy(place->versions[i], desc->version, 16); break; case IMAGE_OK_ORIGIN: /* It's a JTAG image */ sel_img_or = i; break; default: /* It's a corrupt image */ if (sel_img_ko == -1) /* change sel_img_ko just first time */ { sel_img_ko = i; /* we are taking first corrupt image for update candidate */ } } } if(one_img_ok) { /* at least one image OK present */ /* update index will be max + 1 */ place->index = max_index + 1; } else { /* No image OK present */ /* update index will be 0 */ place->index = 0; } if(sel_img_ko != -1) { place->flash_addr = (sel_img_ko * img_max_size) + img_0_addr; return 0; } else if(sel_img_ok != -1) { if(max_index == min_index) { /* there is only one image OK that will be overwritten */ /* update index will be 0 */ place->index = 0; } place->flash_addr = (sel_img_ok * img_max_size) + img_0_addr; return 0; } else if(sel_img_or != -1) { place->flash_addr = (sel_img_or * img_max_size) + img_0_addr; return 0; } /* Never use */ return -1; } /** * Store the new update image into the flash. * * \return error code. */ static int store_img(void) { int rc = 0; flash_info_t *flinfo = &(flash_info[0]); /* we expect HW to have only one flash, thus only one flinfo */ int i = 0; ulong last_addr = 0; struct update_image *image = ctx.image; struct update_place *place = ctx.place; /* Erase the flash */ /* In order to erase flash, we will use function flash_sect_erase (ulong addr_first, ulong addr_last), * which demands first parameter to be on sector boundary, and the second actually last addr in some sector. * We have to find last adress of the last sector that holds our image. * Note: if we write 0x360000 bytes long image to address 0x140000 * last addr will be 49ffff (0x140000 + 0x35ffff), not 0x4a0000 (0x14000 + 0x360000) */ if( place->flash_addr + image->len > flinfo->start[0] + flinfo->size ) { printf("Error (Not enough place).\n"); return -1; } /* find the last_addr in the flash */ while( flinfo->start[i] < place->flash_addr + image->len && i < flinfo->sector_count) { i++; } if(i == flinfo->sector_count) { last_addr = flinfo->start[0] + flinfo->size - 1; /* address of the last sector in flash */ } else { last_addr = flinfo->start[i] - 1; } TRACE("Erasing the flash from the addr %#x to the addr %#x...\n", place->flash_addr, last_addr); rc = flash_sect_erase(place->flash_addr, last_addr); if(rc!=ERR_OK) { printf("Error (Flash Erase).\n"); flash_perror(rc); return rc; } else { TRACE("done.\n"); } TRACE("Copy to flash..."); #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) { size_t l = upd_img_len; void *to = (void *)place->flash_addr; void *from = (void *)place->ram_addr; while(l > 0) { size_t tail = (l > CHUNKSZ) ? CHUNKSZ : l; WATCHDOG_RESET(); rc = flash_write(from, to, tail); to += tail; from += tail; l -= tail; } } #else /* !(CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG) */ { rc = flash_write((char*)place->ram_addr, place->flash_addr, image->len); TRACE("\n"); } #endif /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */ if(rc) { flash_perror(rc); printf("Error (Flash Write).\n"); } return rc; } /** * Update the index of a image already present in flash. * * \param num image number. * \return error code. */ static int update_img_index(ulong num) { flash_info_t *flinfo = &(flash_info[0]); struct update_image *image = ctx.image; struct update_place *place = ctx.place; ulong i; place->flash_addr = (num * place->img_max_size) + place->img_0_addr; image->len = sizeof(spidcom_image_desc_t); for(i=0 ; ((flinfo->start[i] < place->flash_addr + sizeof(spidcom_image_desc_t)) && (i < flinfo->sector_count)) ; i++); if(i == flinfo->sector_count) image->len = (flinfo->start[0] + flinfo->size) - place->flash_addr; else image->len = flinfo->start[i] - place->flash_addr; /* copy image header in ram word by word */ for(i=0 ; i < (image->len/4) ; i++) { *(((ulong*)(place->ram_addr))+i) = *(((ulong*)(place->flash_addr))+i); } /* change index */ ((spidcom_image_desc_t *)place->ram_addr)->index = place->index; /* copy header in flash */ return store_img(); } /* * MD5 functions */ #ifdef ET_DEBUG /** * Print the MD5 Sum result. * * \param digest md5 to print. */ static void md5_print(md5_byte_t digest[16]) { unsigned int i; for(i = 0; i < 16; i++) printf("%02x", digest[i]); } #endif /** * Calculate MD5 of an image. * * \param md5_sum md5 result. */ static void md5_image(md5_byte_t md5_sum[16]) { md5_state_t state; struct update_image *image = ctx.image; struct update_place *place = ctx.place; #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) ulong bdata = place->ram_addr; ulong edata = bdata + image->len; #endif /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */ md5_init(&state); TRACE(" Verifying MD5 Checksum ... "); #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) while (bdata < edata) { ulong chunk = edata - bdata; if (chunk > CHUNKSZ) { chunk = CHUNKSZ; } md5_append(&state, (const md5_byte_t *)bdata, chunk); bdata += chunk; WATCHDOG_RESET(); } #else /* !(CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG) */ md5_append(&state, (const md5_byte_t *)place->ram_addr, image->len); #endif /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */ md5_finish(&state, md5_sum); #ifdef ET_DEBUG printf("MD5 (Linux image) = "); md5_print(md5_sum); printf("\n"); #endif } /**************************| Protocol functions |***************************/ static void SpidupdTimeout(void); /** * Send a SPiDUpdate confirm packet. */ static void SpidupdSend(int rsp_type) { int len = 0; int transfer_end = 0; volatile uchar *pkt; VSMS_MME_t *mme; VsUpdStartCnf_t *vs_update_start_cnf; VsUpdTransfCnf_t *vs_update_transfer_cnf; VsUpdEndCnf_t *vs_update_end_cnf; VsUpdEndInd_t *vs_update_end_ind; /* Set structures pointers */ pkt = NetTxPacket; mme = (VSMS_MME_t *)pkt; vs_update_start_cnf = (VsUpdStartCnf_t *)(mme+1); vs_update_transfer_cnf = (VsUpdTransfCnf_t *)(mme+1); vs_update_end_cnf = (VsUpdEndCnf_t *)(mme+1); vs_update_end_ind = (VsUpdEndInd_t *)(mme+1); /* Set the MME version, FMI and OUI */ mme->mmv = MME_MMV; mme->fmi = 0; VSMS_MME_SET_OUI(mme, OUI_SPIDCOM); /* Set MAC Address */ NetSetEther(pkt, NetClientEther, PROT_HPAV); TRACE("Inside SpidupdSend()\n"); TRACE("SpidupdState = %d\n", rsp_type); switch (rsp_type) { case UPD_START: /* Set mmtype to VS_UPDATE_START_CNF */ mme->mmtype = htommes(VS_UPDATE_START_CNF); /* Append the message */ vs_update_start_cnf->start_update = ctx.start_cnf.start_update; /* This is the end of packet, determine length */ len = ((ulong)vs_update_start_cnf - (ulong)pkt) + sizeof(VsUpdStartCnf_t); break; case UPD_TRANSFER: /* Set mmtype to VS_UPDATE_TRANSFER_CNF */ mme->mmtype = htommes(VS_UPDATE_TRANSFER_CNF); /* Append the message */ vs_update_transfer_cnf->ack = ctx.transfer_cnf.ack; vs_update_transfer_cnf->next_block = htommel(ctx.transfer_cnf.next_block); /* This is the end of packet, determine length */ len = ((ulong)vs_update_transfer_cnf - (ulong)pkt) + sizeof(VsUpdTransfCnf_t); break; case UPD_END: /* Set mmtype to VS_UPDATE_END_CNF */ mme->mmtype = htommes(VS_UPDATE_END_CNF); /* Append the message */ vs_update_end_cnf->result = ctx.end_cnf.result; /* This is the end of packet, determine length */ len = ((ulong)vs_update_end_cnf - (ulong)pkt) + sizeof(VsUpdEndCnf_t); transfer_end = 1; break; case UPD_IND: /* Set mmtype to VS_UPDATE_END_IND */ mme->mmtype = htommes(VS_UPDATE_END_IND); /* Append the message */ vs_update_end_ind->result = ctx.end_ind.result; /* This is the end of packet, determine length */ len = ((ulong)vs_update_end_ind - (ulong)pkt) + sizeof(VsUpdEndInd_t); break; default : /* WOW - How the hell did we get here ? */ printf("Error (Unknown State).\n"); NetState = NETLOOP_FAIL; break; } /* Send packet */ NetSendPacket(pkt, len); if(transfer_end) printf("Transfer Done, Write image to flash...\n"); } /** * Receive a SPiDUpdate request packet. * * \param pkt received packet pointer. * \param dest destination MAC address. * \param src source MAC address. * \param len packet length. */ static void SpidupdHandler(uchar *pkt, unsigned dest, unsigned src, unsigned len) { int i; VSMS_MME_t *mme; VsUpdStartReq_t *vs_update_start_req; VsUpdTransfReq_t *vs_update_transfer_req; VsUpdEndReq_t *vs_update_end_req; uchar md5_server[16]; uchar md5_client[16]; struct update_image *image = ctx.image; struct update_place *place = ctx.place; ushort mmtype; /* Set structures pointers */ mme = (VSMS_MME_t *)pkt; vs_update_start_req = (VsUpdStartReq_t *)(mme+1); vs_update_transfer_req = (VsUpdTransfReq_t *)(mme+1); vs_update_end_req = (VsUpdEndReq_t *)(mme+1); mmtype = (ushort)(mmetohs(mme->mmtype)); if(!VS_UPDATE_RANGE(mmtype) || !VSMS_MME_IS_CORRECT_OUI(mme, OUI_SPIDCOM)) return; /* We received MME packet from PC client, reset the NETLOOP Timeout */ NetSetTimeout(TIMEOUT * CFG_HZ, SpidupdTimeout); /* * Server will now analyze the message and * depending on the message and current state : * 1) shape the cnf message (struct members) * 2) send the response * 3) go to the next state */ switch(mmtype) { case VS_UPDATE_START_REQ: TRACE("Got VS_UPDATE_START_REQ\n"); ctx.response = UPD_START; #ifdef ET_DEBUG { int i = 0; puts("version = "); for (i=0; i<16; i++) { printf("%c", (vs_update_start_req->version)[i]); } printf("\n"); } printf("arch = %#x\n", vs_update_start_req->arch); printf("upd_type = %#x\n", vs_update_start_req->upd_type); #endif /* Check that no previous update is running */ if((ctx.state == STATE_UPD_START) && !ctx.modem_busy) { /* default send cnf */ ctx.modem_busy = 1; ctx.start_cnf.start_update = SPIDUPD_OK; ctx.state = STATE_UPD_TRANSFER; /* shape the response to client */ if(place->correct_img_exist) { if(place->correct_archi != vs_update_start_req->arch) { /* Request bad architecture */ printf("Error (New image bad Architecture).\n"); ctx.modem_busy = 0; ctx.start_cnf.start_update = SPIDUPD_BAD_ARCH; ctx.state = STATE_UPD_START; /* Abort the update */ NetState = NETLOOP_FAIL; break; } if(place->correct_type != vs_update_start_req->upd_type) { /* Request doesn't concern a sImage */ printf("Error (New image bad type).\n" ); ctx.modem_busy = 0; ctx.start_cnf.start_update = SPIDUPD_BAD_UPD_TYPE; ctx.state = STATE_UPD_START; /* Abort the update */ NetState = NETLOOP_FAIL; break; } if(vs_update_start_req->version[0] == '0') { printf("Error (Bad Version).\n" ); ctx.modem_busy = 0; ctx.start_cnf.start_update = SPIDUPD_BAD_VERSION; ctx.state = STATE_UPD_START; /* Abort the update */ NetState = NETLOOP_FAIL; break; } NetSetTimeout((ulong)(FLASH_WRITE_TOUT * CFG_HZ), SpidupdTimeout); /* if we already have valid image with the same version, don't update it */ for(i=0 ; inb_img ; i++) { if(strcmp(place->versions[i], (char*)vs_update_start_req->version) == 0) { printf("Same Version, only update index.\n" ); update_img_index(i); ctx.modem_busy = 0; ctx.start_cnf.start_update = SPIDUPD_BAD_VERSION; ctx.state = STATE_UPD_START; /* update is finished */ NetState = NETLOOP_SUCCESS; break; } } } } else { printf("Error (Already in use).\n"); ctx.start_cnf.start_update = SPIDUPD_MODEM_BUSY; } break; case VS_UPDATE_TRANSFER_REQ: TRACE("Got VS_UPDATE_TRANSFER_REQ\n"); ctx.response = UPD_TRANSFER; TRACE("received_block = %#x\n", image->num_rx_blk); TRACE("block_id = %#x\n", mmetohl(vs_update_transfer_req->block_id) ); TRACE("length = %d\n", mmetohl(vs_update_transfer_req->length) ); if(ctx.state == STATE_UPD_TRANSFER) { /* Block IDs are starting from 1. * We are expecting to receive next block * of the one that we received last time */ if( mmetohl(vs_update_transfer_req->block_id) != image->num_rx_blk ) { TRACE("FAILURE : Received block ID does not match expected.\n" ); ctx.transfer_cnf.ack = SPIDUPD_FAILURE; ctx.transfer_cnf.next_block = image->num_rx_blk; } else /* OK, we received block we expected */ { /* give a small visual indication */ if((image->num_rx_blk % 50) == 0) printf("."); /* Put block in RAM */ memcpy((void*)(place->ram_addr + image->len), vs_update_transfer_req->data, vs_update_transfer_req->length); /* Increase transfered length */ image->len += mmetohl(vs_update_transfer_req->length); /* we successfully received block, increment received counter */ image->num_rx_blk++; /* shape the response */ ctx.transfer_cnf.ack = SPIDUPD_SUCCESS; ctx.transfer_cnf.next_block = image->num_rx_blk; } } else { TRACE("Wrong message...\n"); } break; case VS_UPDATE_END_REQ: TRACE("Got VS_UPDATE_END_REQ\n"); TRACE("|\n"); ctx.response = UPD_END; if (ctx.state == STATE_UPD_TRANSFER) { /* Transfer is finished so calculate MD5 */ memcpy(md5_client, vs_update_end_req->md5_sum, 16); md5_image((md5_byte_t *)md5_server); if( memcmp(md5_server, md5_client, 16) != 0 ) { /* Wrong MD5 */ printf("Error (MD5 Error).\n"); ctx.end_cnf.result = SPIDUPD_MD5_ERROR; /* Abort the update */ NetState = NETLOOP_FAIL; } ctx.state = STATE_UPD_END; } else { TRACE("Wrong message...\n"); } break; } /* Acknowledge the block just received, which will prompt * the client for the next one. */ SpidupdSend(ctx.response); /* Update communication is finish correctly lets copy image in flash */ if(ctx.state == STATE_UPD_END) { /* Correct MD5 */ TRACE("MD5 sum OK, will burn image...\n"); NetSetTimeout((ulong)(FLASH_WRITE_TOUT * CFG_HZ), SpidupdTimeout); /* We will start to write new image from RAM to FLASH. * Set the index to correct value. */ ((spidcom_image_desc_t *)place->ram_addr)->index = place->index; if(store_img() != ERR_OK) { /* Error writing flash */ TRACE("Error.\nUpdate failure : image cannot be written to flash.\n"); /* Image on flash is corrupted! */ ((spidcom_image_desc_t *)place->ram_addr)->is_valid = 0; flash_write( (char *)place->ram_addr, place->flash_addr, sizeof(spidcom_image_desc_t) ); /* * We have no valid image anymore! * Update failed. */ ctx.end_ind.result = SPIDUPD_FLASH_WRITE_ERROR; NetState = NETLOOP_FAIL; } else { /* Flash write OK */ TRACE("Update image successfully written to flash.\n"); ctx.end_ind.result = SPIDUPD_SUCCESS; NetBootFileXferSize = image->len; NetState = NETLOOP_SUCCESS; } /* We finished update : * re-write header, but with the normal state indication - * put is_update flag to 0, because update is finished * (it was put to 1 by default when image is generated) */ ((spidcom_image_desc_t *)place->ram_addr)->is_not_update = 0; if ( flash_write( (char*)place->ram_addr, place->flash_addr, sizeof(spidcom_image_desc_t) ) != ERR_OK ) { printf("Error writting img desc header to flash -- image will not be valid.\n"); ctx.end_ind.result = SPIDUPD_FLASH_WRITE_ERROR; } SpidupdSend(UPD_IND); } } /** * Calculate timeout procedure. */ static void SpidupdTimeout(void) { if(++ctx.timeout > TIMEOUT_COUNT) { printf("Timeout.\n"); /* TIMEOUT occurred. */ /* Send to client an error message */ if(ctx.state != STATE_UPD_START) { ctx.end_ind.result = SPIDUPD_TOUT; SpidupdSend(UPD_IND); } /* Stop eth driver */ eth_halt(); /* Go out of NETLOOP and notify the caller about failure */ NetState = NETLOOP_FAIL; } else { NetSetTimeout(TIMEOUT * CFG_HZ, SpidupdTimeout); SpidupdSend(ctx.response); } } /** * Start SPiPUpdate procedure. */ void SpidupdStart(void) { DECLARE_GLOBAL_DATA_PTR; ulong nb_img; ulong img_0_addr; ulong img_max_size; /* Flush caches just to be sure */ flush_caches(); puts("SPiDUpdate..."); /* Prepare Networking Handler and timeout */ NetSetTimeout(TIMEOUT * CFG_HZ, SpidupdTimeout); NetSetHandler(SpidupdHandler); /* Find number of allowed places on flash */ nb_img = find_nb_images(gd->bd); if(nb_img > MAX_IMG) { printf("Max allowed images is %d\n", MAX_IMG); nb_img = MAX_IMG; } /* Find the first image offset on flash */ img_0_addr = PHYS_FLASH_SPI_1 + find_img_1st_offset(gd->bd); /* Find max image size */ img_max_size = find_img_max_size(gd->bd); /* Find better place to update a new image */ select_image(nb_img, img_0_addr, img_max_size, &g_upd_place); /* Reset globals */ g_upd_place.nb_img = nb_img; g_upd_place.img_0_addr = img_0_addr; g_upd_place.img_max_size = img_max_size; /* We will use free space in SDRAM to temporary store incoming image packets, * before copying it to flash when all image packets are collected. * Begining address will be right after u-boot image, _bss_end + 1, but aligned to 4 byte boundary */ g_upd_place.ram_addr = ( (_bss_end + 1) + 3 ) & ~3; g_upd_image.len = 0; g_upd_image.num_rx_blk = 1; ctx.place = &g_upd_place; ctx.image = &g_upd_image; ctx.modem_busy = 0; ctx.timeout = 0; ctx.state = STATE_UPD_START; #ifdef ET_DEBUG printf("place.flash_addr=%x\n",g_upd_place.flash_addr); printf("place.ram_addr=%x\n",g_upd_place.ram_addr); printf("place.index=%d\n",g_upd_place.index); printf("place.nb_img=%d\n",g_upd_place.nb_img); printf("place.c_img_exist=%d\n",g_upd_place.correct_img_exist); printf("place.c_type=%x\n",g_upd_place.correct_type); printf("place.c_archi=%x\n",g_upd_place.correct_archi); { int i; printf("Versions:\n"); for(i=0 ; i