diff options
Diffstat (limited to 'drivers/staging/r8188eu/core/rtw_fw.c')
-rw-r--r-- | drivers/staging/r8188eu/core/rtw_fw.c | 163 |
1 files changed, 74 insertions, 89 deletions
diff --git a/drivers/staging/r8188eu/core/rtw_fw.c b/drivers/staging/r8188eu/core/rtw_fw.c index 625d186c3647..0451e5177644 100644 --- a/drivers/staging/r8188eu/core/rtw_fw.c +++ b/drivers/staging/r8188eu/core/rtw_fw.c @@ -4,51 +4,43 @@ #include <linux/firmware.h> #include "../include/rtw_fw.h" -#define MAX_REG_BOLCK_SIZE 196 +#define MAX_REG_BLOCK_SIZE 196 #define FW_8188E_START_ADDRESS 0x1000 #define MAX_PAGE_SIZE 4096 #define IS_FW_HEADER_EXIST(_fwhdr) \ - ((le16_to_cpu(_fwhdr->Signature) & 0xFFF0) == 0x92C0 || \ - (le16_to_cpu(_fwhdr->Signature) & 0xFFF0) == 0x88C0 || \ - (le16_to_cpu(_fwhdr->Signature) & 0xFFF0) == 0x2300 || \ - (le16_to_cpu(_fwhdr->Signature) & 0xFFF0) == 0x88E0) - -/* This structure must be careful with byte-ordering */ + ((le16_to_cpu(_fwhdr->signature) & 0xFFF0) == 0x92C0 || \ + (le16_to_cpu(_fwhdr->signature) & 0xFFF0) == 0x88C0 || \ + (le16_to_cpu(_fwhdr->signature) & 0xFFF0) == 0x2300 || \ + (le16_to_cpu(_fwhdr->signature) & 0xFFF0) == 0x88E0) struct rt_firmware_hdr { - /* 8-byte alinment required */ - /* LONG WORD 0 ---- */ - __le16 Signature; /* 92C0: test chip; 92C, - * 88C0: test chip; 88C1: MP A-cut; - * 92C1: MP A-cut */ - u8 Category; /* AP/NIC and USB/PCI */ - u8 Function; /* Reserved for different FW function - * indcation, for further use when - * driver needs to download different - * FW for different conditions */ - __le16 Version; /* FW Version */ - u8 Subversion; /* FW Subversion, default 0x00 */ - u16 Rsvd1; - - /* LONG WORD 1 ---- */ - u8 Month; /* Release time Month field */ - u8 Date; /* Release time Date field */ - u8 Hour; /* Release time Hour field */ - u8 Minute; /* Release time Minute field */ - __le16 RamCodeSize; /* The size of RAM code */ - u8 Foundry; - u8 Rsvd2; - - /* LONG WORD 2 ---- */ - __le32 SvnIdx; /* The SVN entry index */ - u32 Rsvd3; - - /* LONG WORD 3 ---- */ - u32 Rsvd4; - u32 Rsvd5; + __le16 signature; /* 92C0: test chip; 92C, + * 88C0: test chip; 88C1: MP A-cut; + * 92C1: MP A-cut */ + u8 category; /* AP/NIC and USB/PCI */ + u8 function; /* Reserved for different FW function + * indcation, for further use when + * driver needs to download different + * FW for different conditions */ + __le16 version; /* FW Version */ + u8 subversion; /* FW Subversion, default 0x00 */ + u8 rsvd1; + u8 month; /* Release time Month field */ + u8 date; /* Release time Date field */ + u8 hour; /* Release time Hour field */ + u8 minute; /* Release time Minute field */ + __le16 ramcodesize; /* The size of RAM code */ + u8 foundry; + u8 rsvd2; + __le32 svnidx; /* The SVN entry index */ + __le32 rsvd3; + __le32 rsvd4; + __le32 rsvd5; }; +static_assert(sizeof(struct rt_firmware_hdr) == 32); + static void fw_download_enable(struct adapter *padapter, bool enable) { u8 tmp; @@ -71,53 +63,55 @@ static void fw_download_enable(struct adapter *padapter, bool enable) } } -static int block_write(struct adapter *padapter, void *buffer, u32 buffSize) +static int block_write(struct adapter *padapter, u8 *buffer, u32 size) { int ret = _SUCCESS; - u32 blockSize_p1 = 4; /* (Default) Phase #1 : PCI muse use 4-byte write to download FW */ - u32 blockSize_p2 = 8; /* Phase #2 : Use 8-byte, if Phase#1 use big size to write FW. */ - u32 blockSize_p3 = 1; /* Phase #3 : Use 1-byte, the remnant of FW image. */ - u32 blockCount_p1 = 0, blockCount_p2 = 0, blockCount_p3 = 0; - u32 remainSize_p1 = 0, remainSize_p2 = 0; - u8 *bufferPtr = (u8 *)buffer; - u32 i = 0, offset = 0; - - blockSize_p1 = MAX_REG_BOLCK_SIZE; - - /* 3 Phase #1 */ - blockCount_p1 = buffSize / blockSize_p1; - remainSize_p1 = buffSize % blockSize_p1; - - for (i = 0; i < blockCount_p1; i++) { - ret = rtw_writeN(padapter, (FW_8188E_START_ADDRESS + i * blockSize_p1), blockSize_p1, (bufferPtr + i * blockSize_p1)); + u32 blocks, block_size, remain; + u32 i, offset, addr; + u8 *data; + + block_size = MAX_REG_BLOCK_SIZE; + + blocks = size / block_size; + remain = size % block_size; + + for (i = 0; i < blocks; i++) { + addr = FW_8188E_START_ADDRESS + i * block_size; + data = buffer + i * block_size; + + ret = rtw_writeN(padapter, addr, block_size, data); if (ret == _FAIL) goto exit; } - /* 3 Phase #2 */ - if (remainSize_p1) { - offset = blockCount_p1 * blockSize_p1; + if (remain) { + offset = blocks * block_size; + block_size = 8; - blockCount_p2 = remainSize_p1 / blockSize_p2; - remainSize_p2 = remainSize_p1 % blockSize_p2; + blocks = remain / block_size; + remain = remain % block_size; - for (i = 0; i < blockCount_p2; i++) { - ret = rtw_writeN(padapter, (FW_8188E_START_ADDRESS + offset + i * blockSize_p2), blockSize_p2, (bufferPtr + offset + i * blockSize_p2)); + for (i = 0; i < blocks; i++) { + addr = FW_8188E_START_ADDRESS + offset + i * block_size; + data = buffer + offset + i * block_size; + ret = rtw_writeN(padapter, addr, block_size, data); if (ret == _FAIL) goto exit; } } - /* 3 Phase #3 */ - if (remainSize_p2) { - offset = (blockCount_p1 * blockSize_p1) + (blockCount_p2 * blockSize_p2); + if (remain) { + offset += blocks * block_size; - blockCount_p3 = remainSize_p2 / blockSize_p3; + /* block size 1 */ + blocks = remain; - for (i = 0; i < blockCount_p3; i++) { - ret = rtw_write8(padapter, (FW_8188E_START_ADDRESS + offset + i), *(bufferPtr + offset + i)); + for (i = 0; i < blocks; i++) { + addr = FW_8188E_START_ADDRESS + offset + i; + data = buffer + offset + i; + ret = rtw_write8(padapter, addr, *data); if (ret == _FAIL) goto exit; } @@ -127,7 +121,7 @@ exit: return ret; } -static int page_write(struct adapter *padapter, u32 page, void *buffer, u32 size) +static int page_write(struct adapter *padapter, u32 page, u8 *buffer, u32 size) { u8 value8; u8 u8Page = (u8)(page & 0x07); @@ -138,21 +132,20 @@ static int page_write(struct adapter *padapter, u32 page, void *buffer, u32 size return block_write(padapter, buffer, size); } -static int write_fw(struct adapter *padapter, void *buffer, u32 size) +static int write_fw(struct adapter *padapter, u8 *buffer, u32 size) { /* Since we need dynamic decide method of dwonload fw, so we call this function to get chip version. */ /* We can remove _ReadChipVersion from ReadpadapterInfo8192C later. */ int ret = _SUCCESS; u32 pageNums, remainSize; u32 page, offset; - u8 *bufferPtr = (u8 *)buffer; pageNums = size / MAX_PAGE_SIZE; remainSize = size % MAX_PAGE_SIZE; for (page = 0; page < pageNums; page++) { offset = page * MAX_PAGE_SIZE; - ret = page_write(padapter, page, bufferPtr + offset, MAX_PAGE_SIZE); + ret = page_write(padapter, page, buffer + offset, MAX_PAGE_SIZE); if (ret == _FAIL) goto exit; @@ -160,7 +153,7 @@ static int write_fw(struct adapter *padapter, void *buffer, u32 size) if (remainSize) { offset = pageNums * MAX_PAGE_SIZE; page = pageNums; - ret = page_write(padapter, page, bufferPtr + offset, remainSize); + ret = page_write(padapter, page, buffer + offset, remainSize); if (ret == _FAIL) goto exit; @@ -247,14 +240,12 @@ int rtl8188e_firmware_download(struct adapter *padapter) { int ret = _SUCCESS; u8 write_fw_retry = 0; - u32 fwdl_start_time; + unsigned long fwdl_timeout; struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); struct device *device = dvobj_to_dev(dvobj); struct rt_firmware_hdr *fwhdr = NULL; - u16 fw_version, fw_subversion, fw_signature; u8 *fw_data; u32 fw_size; - static int log_version; if (!dvobj->firmware.data) ret = load_firmware(&dvobj->firmware, device); @@ -265,21 +256,15 @@ int rtl8188e_firmware_download(struct adapter *padapter) fw_data = dvobj->firmware.data; fw_size = dvobj->firmware.size; - /* To Check Fw header. Added by tynli. 2009.12.04. */ fwhdr = (struct rt_firmware_hdr *)dvobj->firmware.data; - fw_version = le16_to_cpu(fwhdr->Version); - fw_subversion = fwhdr->Subversion; - fw_signature = le16_to_cpu(fwhdr->Signature); - - if (!log_version++) - pr_info("%sFirmware Version %d, SubVersion %d, Signature 0x%x\n", - DRIVER_PREFIX, fw_version, fw_subversion, fw_signature); - if (IS_FW_HEADER_EXIST(fwhdr)) { - /* Shift 32 bytes for FW header */ - fw_data = fw_data + 32; - fw_size = fw_size - 32; + pr_info_once("R8188EU: Firmware Version %d, SubVersion %d, Signature 0x%x\n", + le16_to_cpu(fwhdr->version), fwhdr->subversion, + le16_to_cpu(fwhdr->signature)); + + fw_data = fw_data + sizeof(struct rt_firmware_hdr); + fw_size = fw_size - sizeof(struct rt_firmware_hdr); } /* Suggested by Filen. If 8051 is running in RAM code, driver should inform Fw to reset by itself, */ @@ -290,7 +275,7 @@ int rtl8188e_firmware_download(struct adapter *padapter) } fw_download_enable(padapter, true); - fwdl_start_time = jiffies; + fwdl_timeout = jiffies + msecs_to_jiffies(500); while (1) { /* reset the FWDL chksum */ rtw_write8(padapter, REG_MCUFWDL, rtw_read8(padapter, REG_MCUFWDL) | FWDL_CHKSUM_RPT); @@ -298,7 +283,7 @@ int rtl8188e_firmware_download(struct adapter *padapter) ret = write_fw(padapter, fw_data, fw_size); if (ret == _SUCCESS || - (rtw_get_passing_time_ms(fwdl_start_time) > 500 && write_fw_retry++ >= 3)) + (time_after(jiffies, fwdl_timeout) && write_fw_retry++ >= 3)) break; } fw_download_enable(padapter, false); |