From 9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00 Mon Sep 17 00:00:00 2001 From: Yunhong Jiang Date: Tue, 4 Aug 2015 12:17:53 -0700 Subject: Add the rt linux 4.1.3-rt3 as base Import the rt linux 4.1.3-rt3 as OPNFV kvm base. It's from git://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-rt-devel.git linux-4.1.y-rt and the base is: commit 0917f823c59692d751951bf5ea699a2d1e2f26a2 Author: Sebastian Andrzej Siewior Date: Sat Jul 25 12:13:34 2015 +0200 Prepare v4.1.3-rt3 Signed-off-by: Sebastian Andrzej Siewior We lose all the git history this way and it's not good. We should apply another opnfv project repo in future. Change-Id: I87543d81c9df70d99c5001fbdf646b202c19f423 Signed-off-by: Yunhong Jiang --- .../staging/ft1000/ft1000-usb/ft1000_download.c | 1052 ++++++++++++++++++++ 1 file changed, 1052 insertions(+) create mode 100644 kernel/drivers/staging/ft1000/ft1000-usb/ft1000_download.c (limited to 'kernel/drivers/staging/ft1000/ft1000-usb/ft1000_download.c') diff --git a/kernel/drivers/staging/ft1000/ft1000-usb/ft1000_download.c b/kernel/drivers/staging/ft1000/ft1000-usb/ft1000_download.c new file mode 100644 index 000000000..5def347be --- /dev/null +++ b/kernel/drivers/staging/ft1000/ft1000-usb/ft1000_download.c @@ -0,0 +1,1052 @@ +/* + * CopyRight (C) 2007 Qualcomm Inc. All Rights Reserved. + * + * This file is part of Express Card USB Driver + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include "ft1000_usb.h" + + +#define DWNLD_HANDSHAKE_LOC 0x02 +#define DWNLD_TYPE_LOC 0x04 +#define DWNLD_SIZE_MSW_LOC 0x06 +#define DWNLD_SIZE_LSW_LOC 0x08 +#define DWNLD_PS_HDR_LOC 0x0A + +#define MAX_DSP_WAIT_LOOPS 40 +#define DSP_WAIT_SLEEP_TIME 1000 /* 1 millisecond */ +#define DSP_WAIT_DISPATCH_LVL 50 /* 50 usec */ + +#define HANDSHAKE_TIMEOUT_VALUE 0xF1F1 +#define HANDSHAKE_RESET_VALUE 0xFEFE /* When DSP requests startover */ +#define HANDSHAKE_RESET_VALUE_USB 0xFE7E /* When DSP requests startover */ +#define HANDSHAKE_DSP_BL_READY 0xFEFE /* At start DSP writes this when bootloader ready */ +#define HANDSHAKE_DSP_BL_READY_USB 0xFE7E /* At start DSP writes this when bootloader ready */ +#define HANDSHAKE_DRIVER_READY 0xFFFF /* Driver writes after receiving 0xFEFE */ +#define HANDSHAKE_SEND_DATA 0x0000 /* DSP writes this when ready for more data */ + +#define HANDSHAKE_REQUEST 0x0001 /* Request from DSP */ +#define HANDSHAKE_RESPONSE 0x0000 /* Satisfied DSP request */ + +#define REQUEST_CODE_LENGTH 0x0000 +#define REQUEST_RUN_ADDRESS 0x0001 +#define REQUEST_CODE_SEGMENT 0x0002 /* In WORD count */ +#define REQUEST_DONE_BL 0x0003 +#define REQUEST_DONE_CL 0x0004 +#define REQUEST_VERSION_INFO 0x0005 +#define REQUEST_CODE_BY_VERSION 0x0006 +#define REQUEST_MAILBOX_DATA 0x0007 +#define REQUEST_FILE_CHECKSUM 0x0008 + +#define STATE_START_DWNLD 0x01 +#define STATE_BOOT_DWNLD 0x02 +#define STATE_CODE_DWNLD 0x03 +#define STATE_DONE_DWNLD 0x04 +#define STATE_SECTION_PROV 0x05 +#define STATE_DONE_PROV 0x06 +#define STATE_DONE_FILE 0x07 + +#define MAX_LENGTH 0x7f0 + +/* Temporary download mechanism for Magnemite */ +#define DWNLD_MAG_TYPE_LOC 0x00 +#define DWNLD_MAG_LEN_LOC 0x01 +#define DWNLD_MAG_ADDR_LOC 0x02 +#define DWNLD_MAG_CHKSUM_LOC 0x03 +#define DWNLD_MAG_VAL_LOC 0x04 + +#define HANDSHAKE_MAG_DSP_BL_READY 0xFEFE0000 /* At start DSP writes this when bootloader ready */ +#define HANDSHAKE_MAG_DSP_ENTRY 0x01000000 /* Dsp writes this to request for entry address */ +#define HANDSHAKE_MAG_DSP_DATA 0x02000000 /* Dsp writes this to request for data block */ +#define HANDSHAKE_MAG_DSP_DONE 0x03000000 /* Dsp writes this to indicate download done */ + +#define HANDSHAKE_MAG_DRV_READY 0xFFFF0000 /* Driver writes this to indicate ready to download */ +#define HANDSHAKE_MAG_DRV_DATA 0x02FECDAB /* Driver writes this to indicate data available to DSP */ +#define HANDSHAKE_MAG_DRV_ENTRY 0x01FECDAB /* Driver writes this to indicate entry point to DSP */ + +#define HANDSHAKE_MAG_TIMEOUT_VALUE 0xF1F1 + + +/* New Magnemite downloader */ +#define DWNLD_MAG1_HANDSHAKE_LOC 0x00 +#define DWNLD_MAG1_TYPE_LOC 0x01 +#define DWNLD_MAG1_SIZE_LOC 0x02 +#define DWNLD_MAG1_PS_HDR_LOC 0x03 + +struct dsp_file_hdr { + long version_id; /* Version ID of this image format. */ + long package_id; /* Package ID of code release. */ + long build_date; /* Date/time stamp when file was built. */ + long commands_offset; /* Offset to attached commands in Pseudo Hdr format. */ + long loader_offset; /* Offset to bootloader code. */ + long loader_code_address; /* Start address of bootloader. */ + long loader_code_end; /* Where bootloader code ends. */ + long loader_code_size; + long version_data_offset; /* Offset were scrambled version data begins. */ + long version_data_size; /* Size, in words, of scrambled version data. */ + long nDspImages; /* Number of DSP images in file. */ +}; + +#pragma pack(1) +struct dsp_image_info { + long coff_date; /* Date/time when DSP Coff image was built. */ + long begin_offset; /* Offset in file where image begins. */ + long end_offset; /* Offset in file where image begins. */ + long run_address; /* On chip Start address of DSP code. */ + long image_size; /* Size of image. */ + long version; /* Embedded version # of DSP code. */ + unsigned short checksum; /* DSP File checksum */ + unsigned short pad1; +}; + + +/* checks if the doorbell register is cleared */ +static int check_usb_db(struct ft1000_usb *ft1000dev) +{ + int loopcnt; + u16 temp; + int status; + + loopcnt = 0; + + while (loopcnt < 10) { + status = ft1000_read_register(ft1000dev, &temp, + FT1000_REG_DOORBELL); + pr_debug("read FT1000_REG_DOORBELL value is %x\n", temp); + if (temp & 0x0080) { + pr_debug("Got checkusb doorbell\n"); + status = ft1000_write_register(ft1000dev, 0x0080, + FT1000_REG_DOORBELL); + status = ft1000_write_register(ft1000dev, 0x0100, + FT1000_REG_DOORBELL); + status = ft1000_write_register(ft1000dev, 0x8000, + FT1000_REG_DOORBELL); + break; + } + loopcnt++; + msleep(10); + + } + + loopcnt = 0; + while (loopcnt < 20) { + status = ft1000_read_register(ft1000dev, &temp, + FT1000_REG_DOORBELL); + pr_debug("Doorbell = 0x%x\n", temp); + if (temp & 0x8000) { + loopcnt++; + msleep(10); + } else { + pr_debug("door bell is cleared, return 0\n"); + return 0; + } + } + + return -1; +} + +/* gets the handshake and compares it with the expected value */ +static u16 get_handshake(struct ft1000_usb *ft1000dev, u16 expected_value) +{ + u16 handshake; + int loopcnt; + int status = 0; + + loopcnt = 0; + + while (loopcnt < 100) { + /* Need to clear downloader doorbell if Hartley ASIC */ + status = ft1000_write_register(ft1000dev, FT1000_DB_DNLD_RX, + FT1000_REG_DOORBELL); + if (ft1000dev->fcodeldr) { + pr_debug("fcodeldr is %d\n", ft1000dev->fcodeldr); + ft1000dev->fcodeldr = 0; + status = check_usb_db(ft1000dev); + if (status != 0) { + pr_debug("check_usb_db failed\n"); + break; + } + status = ft1000_write_register(ft1000dev, + FT1000_DB_DNLD_RX, + FT1000_REG_DOORBELL); + } + + status = ft1000_read_dpram16(ft1000dev, + DWNLD_MAG1_HANDSHAKE_LOC, (u8 *)&handshake, 1); + handshake = ntohs(handshake); + + if (status) + return HANDSHAKE_TIMEOUT_VALUE; + + if ((handshake == expected_value) || + (handshake == HANDSHAKE_RESET_VALUE_USB)) { + return handshake; + } + loopcnt++; + msleep(10); + } + + return HANDSHAKE_TIMEOUT_VALUE; +} + +/* write the handshake value to the handshake location */ +static void put_handshake(struct ft1000_usb *ft1000dev, u16 handshake_value) +{ + u32 tempx; + u16 tempword; + int status; + + tempx = (u32)handshake_value; + tempx = ntohl(tempx); + + tempword = (u16)(tempx & 0xffff); + status = ft1000_write_dpram16(ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC, + tempword, 0); + tempword = (u16)(tempx >> 16); + status = ft1000_write_dpram16(ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC, + tempword, 1); + status = ft1000_write_register(ft1000dev, FT1000_DB_DNLD_TX, + FT1000_REG_DOORBELL); +} + +static u16 get_handshake_usb(struct ft1000_usb *ft1000dev, u16 expected_value) +{ + u16 handshake; + int loopcnt; + u16 temp; + int status = 0; + + loopcnt = 0; + handshake = 0; + + while (loopcnt < 100) { + if (ft1000dev->usbboot == 2) { + status = ft1000_read_dpram32(ft1000dev, 0, + (u8 *)&ft1000dev->tempbuf[0], 64); + for (temp = 0; temp < 16; temp++) { + pr_debug("tempbuf %d = 0x%x\n", + temp, ft1000dev->tempbuf[temp]); + } + status = ft1000_read_dpram16(ft1000dev, + DWNLD_MAG1_HANDSHAKE_LOC, + (u8 *)&handshake, 1); + pr_debug("handshake from read_dpram16 = 0x%x\n", + handshake); + if (ft1000dev->dspalive == ft1000dev->tempbuf[6]) { + handshake = 0; + } else { + handshake = ft1000dev->tempbuf[1]; + ft1000dev->dspalive = + ft1000dev->tempbuf[6]; + } + } else { + status = ft1000_read_dpram16(ft1000dev, + DWNLD_MAG1_HANDSHAKE_LOC, + (u8 *)&handshake, 1); + } + + loopcnt++; + msleep(10); + handshake = ntohs(handshake); + if ((handshake == expected_value) || + (handshake == HANDSHAKE_RESET_VALUE_USB)) + return handshake; + } + + return HANDSHAKE_TIMEOUT_VALUE; +} + +static void put_handshake_usb(struct ft1000_usb *ft1000dev, u16 handshake_value) +{ + int i; + + for (i = 0; i < 1000; i++) + ; +} + +static u16 get_request_type(struct ft1000_usb *ft1000dev) +{ + u16 request_type; + int status; + u16 tempword; + u32 tempx; + + if (ft1000dev->bootmode == 1) { + status = fix_ft1000_read_dpram32(ft1000dev, + DWNLD_MAG1_TYPE_LOC, (u8 *)&tempx); + tempx = ntohl(tempx); + } else { + tempx = 0; + status = ft1000_read_dpram16(ft1000dev, + DWNLD_MAG1_TYPE_LOC, (u8 *)&tempword, 1); + tempx |= (tempword << 16); + tempx = ntohl(tempx); + } + request_type = (u16)tempx; + + return request_type; +} + +static u16 get_request_type_usb(struct ft1000_usb *ft1000dev) +{ + u16 request_type; + int status; + u16 tempword; + u32 tempx; + + if (ft1000dev->bootmode == 1) { + status = fix_ft1000_read_dpram32(ft1000dev, + DWNLD_MAG1_TYPE_LOC, (u8 *)&tempx); + tempx = ntohl(tempx); + } else { + if (ft1000dev->usbboot == 2) { + tempx = ft1000dev->tempbuf[2]; + tempword = ft1000dev->tempbuf[3]; + } else { + tempx = 0; + status = ft1000_read_dpram16(ft1000dev, + DWNLD_MAG1_TYPE_LOC, + (u8 *)&tempword, 1); + } + tempx |= (tempword << 16); + tempx = ntohl(tempx); + } + request_type = (u16)tempx; + + return request_type; +} + +static long get_request_value(struct ft1000_usb *ft1000dev) +{ + u32 value; + u16 tempword; + int status; + + if (ft1000dev->bootmode == 1) { + status = fix_ft1000_read_dpram32(ft1000dev, + DWNLD_MAG1_SIZE_LOC, (u8 *)&value); + value = ntohl(value); + } else { + status = ft1000_read_dpram16(ft1000dev, + DWNLD_MAG1_SIZE_LOC, (u8 *)&tempword, 0); + value = tempword; + status = ft1000_read_dpram16(ft1000dev, + DWNLD_MAG1_SIZE_LOC, (u8 *)&tempword, 1); + value |= (tempword << 16); + value = ntohl(value); + } + + return value; +} + + +/* writes a value to DWNLD_MAG1_SIZE_LOC */ +static void put_request_value(struct ft1000_usb *ft1000dev, long lvalue) +{ + u32 tempx; + int status; + + tempx = ntohl(lvalue); + status = fix_ft1000_write_dpram32(ft1000dev, DWNLD_MAG1_SIZE_LOC, + (u8 *)&tempx); +} + + + +/* returns the checksum of the pseudo header */ +static u16 hdr_checksum(struct pseudo_hdr *pHdr) +{ + u16 *usPtr = (u16 *)pHdr; + u16 chksum; + + + chksum = (((((usPtr[0] ^ usPtr[1]) ^ usPtr[2]) ^ usPtr[3]) ^ + usPtr[4]) ^ usPtr[5]) ^ usPtr[6]; + + return chksum; +} + +static int check_buffers(u16 *buff_w, u16 *buff_r, int len, int offset) +{ + int i; + + for (i = 0; i < len; i++) { + if (buff_w[i] != buff_r[i + offset]) + return -EREMOTEIO; + } + + return 0; +} + +static int write_dpram32_and_check(struct ft1000_usb *ft1000dev, + u16 tempbuffer[], u16 dpram) +{ + int status; + u16 resultbuffer[64]; + int i; + + for (i = 0; i < 10; i++) { + status = ft1000_write_dpram32(ft1000dev, dpram, + (u8 *)&tempbuffer[0], 64); + if (status == 0) { + /* Work around for ASIC bit stuffing problem. */ + if ((tempbuffer[31] & 0xfe00) == 0xfe00) { + status = ft1000_write_dpram32(ft1000dev, + dpram+12, (u8 *)&tempbuffer[24], + 64); + } + /* Let's check the data written */ + status = ft1000_read_dpram32(ft1000dev, dpram, + (u8 *)&resultbuffer[0], 64); + if ((tempbuffer[31] & 0xfe00) == 0xfe00) { + if (check_buffers(tempbuffer, resultbuffer, 28, + 0)) { + pr_debug("DPRAM write failed 1 during bootloading\n"); + usleep_range(9000, 11000); + break; + } + status = ft1000_read_dpram32(ft1000dev, + dpram+12, + (u8 *)&resultbuffer[0], 64); + + if (check_buffers(tempbuffer, resultbuffer, 16, + 24)) { + pr_debug("DPRAM write failed 2 during bootloading\n"); + usleep_range(9000, 11000); + break; + } + } else { + if (check_buffers(tempbuffer, resultbuffer, 32, + 0)) { + pr_debug("DPRAM write failed 3 during bootloading\n"); + usleep_range(9000, 11000); + break; + } + } + if (status == 0) + break; + } + } + return status; +} + +/* writes a block of DSP image to DPRAM + * Parameters: struct ft1000_usb - device structure + * u16 **pUsFile - DSP image file pointer in u16 + * u8 **pUcFile - DSP image file pointer in u8 + * long word_length - length of the buffer to be written to DPRAM + */ +static int write_blk(struct ft1000_usb *ft1000dev, u16 **pUsFile, u8 **pUcFile, + long word_length) +{ + int status = 0; + u16 dpram; + int loopcnt, i; + u16 tempword; + u16 tempbuffer[64]; + + /*pr_debug("start word_length = %d\n",(int)word_length); */ + dpram = (u16)DWNLD_MAG1_PS_HDR_LOC; + tempword = *(*pUsFile); + (*pUsFile)++; + status = ft1000_write_dpram16(ft1000dev, dpram, tempword, 0); + tempword = *(*pUsFile); + (*pUsFile)++; + status = ft1000_write_dpram16(ft1000dev, dpram++, tempword, 1); + + *pUcFile = *pUcFile + 4; + word_length--; + tempword = (u16)word_length; + word_length = (word_length / 16) + 1; + for (; word_length > 0; word_length--) { /* In words */ + loopcnt = 0; + for (i = 0; i < 32; i++) { + if (tempword != 0) { + tempbuffer[i++] = *(*pUsFile); + (*pUsFile)++; + tempbuffer[i] = *(*pUsFile); + (*pUsFile)++; + *pUcFile = *pUcFile + 4; + loopcnt++; + tempword--; + } else { + tempbuffer[i++] = 0; + tempbuffer[i] = 0; + } + } + + /*pr_debug("loopcnt is %d\n", loopcnt); */ + /*pr_debug("write_blk: bootmode = %d\n", bootmode); */ + /*pr_debug("write_blk: dpram = %x\n", dpram); */ + if (ft1000dev->bootmode == 0) { + if (dpram >= 0x3F4) + status = ft1000_write_dpram32(ft1000dev, dpram, + (u8 *)&tempbuffer[0], 8); + else + status = ft1000_write_dpram32(ft1000dev, dpram, + (u8 *)&tempbuffer[0], 64); + } else { + status = write_dpram32_and_check(ft1000dev, tempbuffer, + dpram); + if (status != 0) { + pr_debug("Write failed tempbuffer[31] = 0x%x\n", + tempbuffer[31]); + break; + } + } + dpram = dpram + loopcnt; + } + return status; +} + +static void usb_dnld_complete(struct urb *urb) +{ + /* pr_debug("****** usb_dnld_complete\n"); */ +} + +/* writes a block of DSP image to DPRAM + * Parameters: struct ft1000_usb - device structure + * u16 **pUsFile - DSP image file pointer in u16 + * u8 **pUcFile - DSP image file pointer in u8 + * long word_length - length of the buffer to be written to DPRAM + */ +static int write_blk_fifo(struct ft1000_usb *ft1000dev, u16 **pUsFile, + u8 **pUcFile, long word_length) +{ + int byte_length; + + byte_length = word_length * 4; + + if (byte_length && ((byte_length % 64) == 0)) + byte_length += 4; + + if (byte_length < 64) + byte_length = 68; + + usb_init_urb(ft1000dev->tx_urb); + memcpy(ft1000dev->tx_buf, *pUcFile, byte_length); + usb_fill_bulk_urb(ft1000dev->tx_urb, + ft1000dev->dev, + usb_sndbulkpipe(ft1000dev->dev, + ft1000dev->bulk_out_endpointAddr), + ft1000dev->tx_buf, byte_length, usb_dnld_complete, + ft1000dev); + + usb_submit_urb(ft1000dev->tx_urb, GFP_ATOMIC); + + *pUsFile = *pUsFile + (word_length << 1); + *pUcFile = *pUcFile + (word_length << 2); + + return 0; +} + +static int scram_start_dwnld(struct ft1000_usb *ft1000dev, u16 *hshake, + u32 *state) +{ + int status = 0; + + if (ft1000dev->usbboot) + *hshake = get_handshake_usb(ft1000dev, HANDSHAKE_DSP_BL_READY); + else + *hshake = get_handshake(ft1000dev, HANDSHAKE_DSP_BL_READY); + if (*hshake == HANDSHAKE_DSP_BL_READY) { + pr_debug("handshake is HANDSHAKE_DSP_BL_READY, call put_handshake(HANDSHAKE_DRIVER_READY)\n"); + put_handshake(ft1000dev, HANDSHAKE_DRIVER_READY); + } else if (*hshake == HANDSHAKE_TIMEOUT_VALUE) { + status = -ETIMEDOUT; + } else { + pr_debug("Download error: Handshake failed\n"); + status = -ENETRESET; + } + *state = STATE_BOOT_DWNLD; + return status; +} + +static int request_code_segment(struct ft1000_usb *ft1000dev, u16 **s_file, + u8 **c_file, const u8 *endpoint, bool boot_case) +{ + long word_length; + int status = 0; + + word_length = get_request_value(ft1000dev); + /*pr_debug("word_length = 0x%x\n", (int)word_length); */ + /*NdisMSleep (100); */ + if (word_length > MAX_LENGTH) { + pr_debug("Download error: Max length exceeded\n"); + return -1; + } + if ((word_length * 2 + (long)c_file) > (long)endpoint) { + /* Error, beyond boot code range.*/ + pr_debug("Download error: Requested len=%d exceeds BOOT code boundary\n", + (int)word_length); + return -1; + } + if (word_length & 0x1) + word_length++; + word_length = word_length / 2; + + if (boot_case) { + status = write_blk(ft1000dev, s_file, c_file, word_length); + /*pr_debug("write_blk returned %d\n", status); */ + } else { + status = write_blk_fifo(ft1000dev, s_file, c_file, word_length); + if (ft1000dev->usbboot == 0) + ft1000dev->usbboot++; + if (ft1000dev->usbboot == 1) + status |= ft1000_write_dpram16(ft1000dev, + DWNLD_MAG1_PS_HDR_LOC, 0, 0); + } + return status; +} + +/* Scramble downloader for Harley based ASIC via USB interface */ +int scram_dnldr(struct ft1000_usb *ft1000dev, void *pFileStart, + u32 FileLength) +{ + int status = 0; + u32 state; + u16 handshake; + struct pseudo_hdr *pseudo_header; + u16 pseudo_header_len; + long word_length; + u16 request; + u16 temp; + + struct dsp_file_hdr *file_hdr; + struct dsp_image_info *dsp_img_info = NULL; + long requested_version; + bool correct_version; + struct drv_msg *mailbox_data; + u16 *data = NULL; + u16 *s_file = NULL; + u8 *c_file = NULL; + u8 *boot_end = NULL, *code_end = NULL; + int image; + long loader_code_address, loader_code_size = 0; + long run_address = 0, run_size = 0; + + u32 templong; + u32 image_chksum = 0; + + u16 dpram = 0; + u8 *pbuffer; + struct prov_record *pprov_record; + struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net); + + ft1000dev->fcodeldr = 0; + ft1000dev->usbboot = 0; + ft1000dev->dspalive = 0xffff; + + /* + * Get version id of file, at first 4 bytes of file, for newer files. + */ + + state = STATE_START_DWNLD; + + file_hdr = pFileStart; + + ft1000_write_register(ft1000dev, 0x800, FT1000_REG_MAG_WATERMARK); + + s_file = (u16 *) (pFileStart + file_hdr->loader_offset); + c_file = (u8 *) (pFileStart + file_hdr->loader_offset); + + boot_end = (u8 *) (pFileStart + file_hdr->loader_code_end); + + loader_code_address = file_hdr->loader_code_address; + loader_code_size = file_hdr->loader_code_size; + correct_version = false; + + while ((status == 0) && (state != STATE_DONE_FILE)) { + switch (state) { + case STATE_START_DWNLD: + status = scram_start_dwnld(ft1000dev, &handshake, + &state); + break; + + case STATE_BOOT_DWNLD: + pr_debug("STATE_BOOT_DWNLD\n"); + ft1000dev->bootmode = 1; + handshake = get_handshake(ft1000dev, HANDSHAKE_REQUEST); + if (handshake == HANDSHAKE_REQUEST) { + /* + * Get type associated with the request. + */ + request = get_request_type(ft1000dev); + switch (request) { + case REQUEST_RUN_ADDRESS: + pr_debug("REQUEST_RUN_ADDRESS\n"); + put_request_value(ft1000dev, + loader_code_address); + break; + case REQUEST_CODE_LENGTH: + pr_debug("REQUEST_CODE_LENGTH\n"); + put_request_value(ft1000dev, + loader_code_size); + break; + case REQUEST_DONE_BL: + pr_debug("REQUEST_DONE_BL\n"); + /* Reposition ptrs to beginning of code section */ + s_file = (u16 *) (boot_end); + c_file = (u8 *) (boot_end); + /* pr_debug("download:s_file = 0x%8x\n", (int)s_file); */ + /* pr_debug("FT1000:download:c_file = 0x%8x\n", (int)c_file); */ + state = STATE_CODE_DWNLD; + ft1000dev->fcodeldr = 1; + break; + case REQUEST_CODE_SEGMENT: + status = request_code_segment(ft1000dev, + &s_file, &c_file, + boot_end, + true); + break; + default: + pr_debug("Download error: Bad request type=%d in BOOT download state\n", + request); + status = -1; + break; + } + if (ft1000dev->usbboot) + put_handshake_usb(ft1000dev, + HANDSHAKE_RESPONSE); + else + put_handshake(ft1000dev, + HANDSHAKE_RESPONSE); + } else { + pr_debug("Download error: Handshake failed\n"); + status = -1; + } + + break; + + case STATE_CODE_DWNLD: + /* pr_debug("STATE_CODE_DWNLD\n"); */ + ft1000dev->bootmode = 0; + if (ft1000dev->usbboot) + handshake = + get_handshake_usb(ft1000dev, + HANDSHAKE_REQUEST); + else + handshake = + get_handshake(ft1000dev, HANDSHAKE_REQUEST); + if (handshake == HANDSHAKE_REQUEST) { + /* + * Get type associated with the request. + */ + if (ft1000dev->usbboot) + request = + get_request_type_usb(ft1000dev); + else + request = get_request_type(ft1000dev); + switch (request) { + case REQUEST_FILE_CHECKSUM: + pr_debug("image_chksum = 0x%8x\n", + image_chksum); + put_request_value(ft1000dev, + image_chksum); + break; + case REQUEST_RUN_ADDRESS: + pr_debug("REQUEST_RUN_ADDRESS\n"); + if (correct_version) { + pr_debug("run_address = 0x%8x\n", + (int)run_address); + put_request_value(ft1000dev, + run_address); + } else { + pr_debug("Download error: Got Run address request before image offset request\n"); + status = -1; + break; + } + break; + case REQUEST_CODE_LENGTH: + pr_debug("REQUEST_CODE_LENGTH\n"); + if (correct_version) { + pr_debug("run_size = 0x%8x\n", + (int)run_size); + put_request_value(ft1000dev, + run_size); + } else { + pr_debug("Download error: Got Size request before image offset request\n"); + status = -1; + break; + } + break; + case REQUEST_DONE_CL: + ft1000dev->usbboot = 3; + /* Reposition ptrs to beginning of provisioning section */ + s_file = + (u16 *) (pFileStart + + file_hdr->commands_offset); + c_file = + (u8 *) (pFileStart + + file_hdr->commands_offset); + state = STATE_DONE_DWNLD; + break; + case REQUEST_CODE_SEGMENT: + /* pr_debug("REQUEST_CODE_SEGMENT - CODELOADER\n"); */ + if (!correct_version) { + pr_debug("Download error: Got Code Segment request before image offset request\n"); + status = -1; + break; + } + + status = request_code_segment(ft1000dev, + &s_file, &c_file, + code_end, + false); + + break; + + case REQUEST_MAILBOX_DATA: + pr_debug("REQUEST_MAILBOX_DATA\n"); + /* Convert length from byte count to word count. Make sure we round up. */ + word_length = + (long)(pft1000info->DSPInfoBlklen + + 1) / 2; + put_request_value(ft1000dev, + word_length); + mailbox_data = + (struct drv_msg *)&(pft1000info-> + DSPInfoBlk[0]); + /* + * Position ASIC DPRAM auto-increment pointer. + */ + + data = (u16 *)&mailbox_data->data[0]; + dpram = (u16)DWNLD_MAG1_PS_HDR_LOC; + if (word_length & 0x1) + word_length++; + + word_length = word_length / 2; + + for (; word_length > 0; word_length--) { /* In words */ + + templong = *data++; + templong |= (*data++ << 16); + status = + fix_ft1000_write_dpram32 + (ft1000dev, dpram++, + (u8 *)&templong); + + } + break; + + case REQUEST_VERSION_INFO: + pr_debug("REQUEST_VERSION_INFO\n"); + word_length = + file_hdr->version_data_size; + put_request_value(ft1000dev, + word_length); + /* + * Position ASIC DPRAM auto-increment pointer. + */ + + s_file = + (u16 *) (pFileStart + + file_hdr-> + version_data_offset); + + dpram = (u16)DWNLD_MAG1_PS_HDR_LOC; + if (word_length & 0x1) + word_length++; + + word_length = word_length / 2; + + for (; word_length > 0; word_length--) { /* In words */ + + templong = ntohs(*s_file++); + temp = ntohs(*s_file++); + templong |= (temp << 16); + status = + fix_ft1000_write_dpram32 + (ft1000dev, dpram++, + (u8 *)&templong); + + } + break; + + case REQUEST_CODE_BY_VERSION: + pr_debug("REQUEST_CODE_BY_VERSION\n"); + correct_version = false; + requested_version = + get_request_value(ft1000dev); + + dsp_img_info = + (struct dsp_image_info *)(pFileStart + + + sizeof + (struct + dsp_file_hdr)); + + for (image = 0; + image < file_hdr->nDspImages; + image++) { + + if (dsp_img_info->version == + requested_version) { + correct_version = true; + pr_debug("correct_version is TRUE\n"); + s_file = + (u16 *) (pFileStart + + + dsp_img_info-> + begin_offset); + c_file = + (u8 *) (pFileStart + + dsp_img_info-> + begin_offset); + code_end = + (u8 *) (pFileStart + + dsp_img_info-> + end_offset); + run_address = + dsp_img_info-> + run_address; + run_size = + dsp_img_info-> + image_size; + image_chksum = + (u32)dsp_img_info-> + checksum; + break; + } + dsp_img_info++; + + } /* end of for */ + + if (!correct_version) { + /* + * Error, beyond boot code range. + */ + pr_debug("Download error: Bad Version Request = 0x%x.\n", + (int)requested_version); + status = -1; + break; + } + break; + + default: + pr_debug("Download error: Bad request type=%d in CODE download state.\n", + request); + status = -1; + break; + } + if (ft1000dev->usbboot) + put_handshake_usb(ft1000dev, + HANDSHAKE_RESPONSE); + else + put_handshake(ft1000dev, + HANDSHAKE_RESPONSE); + } else { + pr_debug("Download error: Handshake failed\n"); + status = -1; + } + + break; + + case STATE_DONE_DWNLD: + pr_debug("Code loader is done...\n"); + state = STATE_SECTION_PROV; + break; + + case STATE_SECTION_PROV: + pr_debug("STATE_SECTION_PROV\n"); + pseudo_header = (struct pseudo_hdr *)c_file; + + if (pseudo_header->checksum == + hdr_checksum(pseudo_header)) { + if (pseudo_header->portdest != + 0x80 /* Dsp OAM */) { + state = STATE_DONE_PROV; + break; + } + pseudo_header_len = ntohs(pseudo_header->length); /* Byte length for PROV records */ + + /* Get buffer for provisioning data */ + pbuffer = + kmalloc(pseudo_header_len + + sizeof(struct pseudo_hdr), + GFP_ATOMIC); + if (pbuffer) { + memcpy(pbuffer, c_file, + (u32) (pseudo_header_len + + sizeof(struct + pseudo_hdr))); + /* link provisioning data */ + pprov_record = + kmalloc(sizeof(struct prov_record), + GFP_ATOMIC); + if (pprov_record) { + pprov_record->pprov_data = + pbuffer; + list_add_tail(&pprov_record-> + list, + &pft1000info-> + prov_list); + /* Move to next entry if available */ + c_file = + (u8 *) ((unsigned long) + c_file + + (u32) ((pseudo_header_len + 1) & 0xFFFFFFFE) + sizeof(struct pseudo_hdr)); + if ((unsigned long)(c_file) - + (unsigned long)(pFileStart) + >= + (unsigned long)FileLength) { + state = STATE_DONE_FILE; + } + } else { + kfree(pbuffer); + status = -1; + } + } else { + status = -1; + } + } else { + /* Checksum did not compute */ + status = -1; + } + pr_debug("after STATE_SECTION_PROV, state = %d, status= %d\n", + state, status); + break; + + case STATE_DONE_PROV: + pr_debug("STATE_DONE_PROV\n"); + state = STATE_DONE_FILE; + break; + + default: + status = -1; + break; + } /* End Switch */ + + if (status != 0) + break; + +/**** + // Check if Card is present + status = Harley_Read_Register(&temp, FT1000_REG_SUP_IMASK); + if ( (status != NDIS_STATUS_SUCCESS) || (temp == 0x0000) ) { + break; + } + + status = Harley_Read_Register(&temp, FT1000_REG_ASIC_ID); + if ( (status != NDIS_STATUS_SUCCESS) || (temp == 0xffff) ) { + break; + } +****/ + + } /* End while */ + + pr_debug("Download exiting with status = 0x%8x\n", status); + ft1000_write_register(ft1000dev, FT1000_DB_DNLD_TX, + FT1000_REG_DOORBELL); + + return status; +} -- cgit 1.2.3-korg