/******************************************************************************
 *
 * Copyright(c) 2019 Realtek Corporation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of version 2 of the GNU General Public License as
 * published by the Free Software Foundation.
 *
 * 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.
 *
 ******************************************************************************/

#include "flash.h"
#include "../mac_ax/fwcmd.h"

#if MAC_AX_FW_REG_OFLD
u32 mac_flash_erase(struct mac_ax_adapter *adapter,
		    u32 addr,
		    u32 length,
		    u32 timeout)
{
	u32 ret = 0, pkt_len, local_timeout = 10000, no_timeout = 0;
	u32 data[2];

	struct h2c_info h2c_info = {0};

	if (timeout == 0)
		no_timeout = 1;
	else
		local_timeout = timeout;

	PLTFM_MUTEX_LOCK(&adapter->flash_info.lock);
	adapter->flash_info.erase_done = 0;
	adapter->flash_info.erasing = 1;
	adapter->flash_info.erase_addr = addr;
	PLTFM_MUTEX_UNLOCK(&adapter->flash_info.lock);

	pkt_len = LEN_FLASH_H2C_HDR;

	h2c_info.agg_en = 0;
	h2c_info.content_len = (u16)pkt_len;
	h2c_info.h2c_cat = FWCMD_H2C_CAT_MAC;
	h2c_info.h2c_class = FWCMD_H2C_CL_FLASH;
	h2c_info.h2c_func = FWCMD_H2C_FUNC_PLAT_FLASH_ERASE;
	h2c_info.rec_ack = 0;
	h2c_info.done_ack = 0;

	data[0] = cpu_to_le32(addr);
	data[1] = cpu_to_le32(length);

	ret = mac_h2c_common(adapter, &h2c_info, (u32 *)&data[0]);

	if (ret) {
		PLTFM_MUTEX_LOCK(&adapter->flash_info.lock);
		adapter->flash_info.erasing = 0;
		adapter->flash_info.erase_addr = 0;
		PLTFM_MUTEX_UNLOCK(&adapter->flash_info.lock);
		adapter->fw_info.h2c_seq--;
		return ret;
	}

	while (1) {
		PLTFM_MUTEX_LOCK(&adapter->flash_info.lock);
		if (adapter->flash_info.erase_done == 1) {
			adapter->flash_info.erase_done = 0;
			adapter->flash_info.erasing = 0;
			adapter->flash_info.erase_addr = 0;
			PLTFM_MUTEX_UNLOCK(&adapter->flash_info.lock);
			break;
		}
		PLTFM_MUTEX_UNLOCK(&adapter->flash_info.lock);

		//Sleep(50);
		PLTFM_DELAY_MS(1);
		if (no_timeout == 0) {
			local_timeout--;
			if (local_timeout == 0) {
				ret = MACFLASHFAIL;
				PLTFM_MUTEX_LOCK(&adapter->flash_info.lock);
				adapter->flash_info.erasing = 0;
				adapter->flash_info.erase_addr = 0;
				PLTFM_MUTEX_UNLOCK(&adapter->flash_info.lock);
				adapter->fw_info.h2c_seq--;
				return ret;
			}
		}
	}

	PLTFM_MUTEX_LOCK(&adapter->flash_info.lock);
	adapter->flash_info.erasing = 0;
	adapter->flash_info.erase_addr = 0;
	PLTFM_MUTEX_UNLOCK(&adapter->flash_info.lock);
	return MACSUCCESS;
}

u32 mac_flash_read(struct mac_ax_adapter *adapter,
		   u32 addr,
		   u32 length,
		   u8 *buffer,
		   u32 timeout)
{
	u32 ret = 0, pkt_len, local_timeout = 10000, no_timeout = 0;
	u32 data[2];

	struct h2c_info h2c_info = {0};

	if (length > FLASH_H2C_SIZE)
		return MACFLASHFAIL;

	if (timeout == 0)
		no_timeout = 1;
	else
		local_timeout = timeout;

	if ((addr % 4) || (length % 4)) {
		PLTFM_MSG_ERR("Address/length not 4 byte aligned, addr : 0x%x, length : 0x%x\n"
			, addr, length);
		return MACFLASHFAIL;
	}

	// mutex
	PLTFM_MUTEX_LOCK(&adapter->flash_info.lock);
	adapter->flash_info.read_done = 0;
	adapter->flash_info.reading = 1;
	adapter->flash_info.buf_addr = buffer;
	adapter->flash_info.read_addr = addr;
	PLTFM_MUTEX_UNLOCK(&adapter->flash_info.lock);

	pkt_len = LEN_FLASH_H2C_HDR;

	h2c_info.agg_en = 0;
	h2c_info.content_len = (u16)pkt_len;
	h2c_info.h2c_cat = FWCMD_H2C_CAT_MAC;
	h2c_info.h2c_class = FWCMD_H2C_CL_FLASH;
	h2c_info.h2c_func = FWCMD_H2C_FUNC_PLAT_FLASH_READ;
	h2c_info.rec_ack = 0;
	h2c_info.done_ack = 0;

	data[0] = cpu_to_le32(addr);
	data[1] = cpu_to_le32(length);

	ret = mac_h2c_common(adapter, &h2c_info, (u32 *)&data[0]);

	if (ret) {
		PLTFM_MUTEX_LOCK(&adapter->flash_info.lock);
		adapter->flash_info.reading = 0;
		adapter->flash_info.buf_addr = NULL;
		adapter->flash_info.read_addr = 0;
		adapter->flash_info.read_done = 0;
		PLTFM_MUTEX_UNLOCK(&adapter->flash_info.lock);
		adapter->fw_info.h2c_seq--;
		return ret;
	}

	while (1) {
		PLTFM_MUTEX_LOCK(&adapter->flash_info.lock);
		//PLTFM_MSG_TRACE("polling enter critical\n");
		if (adapter->flash_info.read_done == 1) {
			//PLTFM_MSG_TRACE("read DONE\n");
			adapter->flash_info.reading = 0;
			adapter->flash_info.buf_addr = NULL;
			adapter->flash_info.read_addr = 0;
			adapter->flash_info.read_done = 0;
			PLTFM_MUTEX_UNLOCK(&adapter->flash_info.lock);
			break;
		}
		//PLTFM_MSG_TRACE("polling exit critical\n");
		PLTFM_MUTEX_UNLOCK(&adapter->flash_info.lock);
		//Sleep(1);
		PLTFM_DELAY_MS(1);
		if (no_timeout == 0) {
			local_timeout--;
			if (local_timeout == 0) {
				ret = MACFLASHFAIL;
				PLTFM_MUTEX_LOCK(&adapter->flash_info.lock);
				adapter->flash_info.reading = 0;
				adapter->flash_info.buf_addr = NULL;
				adapter->flash_info.read_addr = 0;
				adapter->flash_info.read_done = 0;
				PLTFM_MUTEX_UNLOCK(&adapter->flash_info.lock);
				adapter->fw_info.h2c_seq--;
				return ret;
			}
		}
	}

	// end mutex
	//adapter->flash_info.read_done == 0;
	PLTFM_MUTEX_LOCK(&adapter->flash_info.lock);
	adapter->flash_info.reading = 0;
	adapter->flash_info.buf_addr = NULL;
	adapter->flash_info.read_addr = 0;
	PLTFM_MUTEX_UNLOCK(&adapter->flash_info.lock);
	return MACSUCCESS;
}

u32 mac_flash_write(struct mac_ax_adapter *adapter,
		    u32 addr,
		    u32 length,
		    u8 *buffer,
		    u32 timeout)
{
	u8 *buf;
	u32 ret = 0, residue_len, pkt_len, local_timeout = 5000, no_timeout = 0, i;
	u32 data[2];
	u32 waddr, wlength;
	u32 *pbuf;
	u32 *psource_data;

	struct h2c_info h2c_info = {0};

	if (timeout == 0)
		no_timeout = 1;
	else
		local_timeout = timeout;

	residue_len = length;
	waddr = addr;
	wlength = length;

	if ((addr % 4) || (length % 4)) {
		PLTFM_MSG_ERR("Address/length not 4 byte aligned, addr : 0x%x, length : 0x%x\n"
			, addr, length);
		return MACFLASHFAIL;
	}

	while (residue_len) {
		PLTFM_MUTEX_LOCK(&adapter->flash_info.lock);
		adapter->flash_info.write_done = 0;
		adapter->flash_info.writing = 1;
		adapter->flash_info.write_addr = waddr;
		PLTFM_MUTEX_UNLOCK(&adapter->flash_info.lock);

		if (residue_len >= FLASH_H2C_SIZE)
			pkt_len = FLASH_H2C_SIZE;
		else
			pkt_len = residue_len;

		h2c_info.agg_en = 0;
		h2c_info.content_len = (u16)(pkt_len + LEN_FLASH_H2C_HDR);
		h2c_info.h2c_cat = FWCMD_H2C_CAT_MAC;
		h2c_info.h2c_class = FWCMD_H2C_CL_FLASH;
		h2c_info.h2c_func = FWCMD_H2C_FUNC_PLAT_FLASH_WRITE;
		h2c_info.rec_ack = 0;
		h2c_info.done_ack = 0;

		buf = (u8 *)PLTFM_MALLOC(h2c_info.content_len);
		if (!buf) {
			adapter->fw_info.h2c_seq--;
			return MACBUFALLOC;
		}

		data[0] = cpu_to_le32(waddr);
		data[1] = cpu_to_le32(pkt_len);
		PLTFM_MEMCPY(buf, (u8 *)data, LEN_FLASH_H2C_HDR);

		//copy data
		pbuf = (u32 *)(buf + LEN_FLASH_H2C_HDR);
		psource_data = (u32 *)buffer;
		for (i = 0; i < (pkt_len / sizeof(u32)); i++) {
			*pbuf = cpu_to_le32(*psource_data);
			pbuf++;
			psource_data++;
		}

		ret = mac_h2c_common(adapter, &h2c_info, (u32 *)buf);

		if (ret) {
			PLTFM_MUTEX_LOCK(&adapter->flash_info.lock);
			adapter->flash_info.writing = 0;
			adapter->flash_info.write_addr = 0;
			PLTFM_MUTEX_UNLOCK(&adapter->flash_info.lock);
			adapter->fw_info.h2c_seq--;
			PLTFM_FREE(buf, h2c_info.content_len);
			return ret;
		}

		PLTFM_MSG_ERR("Write H2C, addr = 0x%x, length = %d\n", waddr, pkt_len);

		// delay for flash write
		//Sleep(1000);
		while (1) {
			PLTFM_MUTEX_LOCK(&adapter->flash_info.lock);
			if (adapter->flash_info.write_done == 1) {
				adapter->flash_info.writing = 0;
				adapter->flash_info.write_addr = 0;
				adapter->flash_info.write_done = 0;
				PLTFM_MSG_TRACE("write DONE\n");
				PLTFM_MUTEX_UNLOCK(&adapter->flash_info.lock);
				break;
			}
			PLTFM_MUTEX_UNLOCK(&adapter->flash_info.lock);
			//Sleep(1);
			PLTFM_DELAY_MS(1);
			if (no_timeout == 0) {
				local_timeout--;
				if (local_timeout == 0) {
					ret = MACFLASHFAIL;
					PLTFM_MUTEX_LOCK(&adapter->flash_info.lock);
					adapter->flash_info.writing = 0;
					adapter->flash_info.write_addr = 0;
					PLTFM_MSG_TRACE("write timeout\n");
					PLTFM_MUTEX_UNLOCK(&adapter->flash_info.lock);
					adapter->fw_info.h2c_seq--;
					PLTFM_FREE(buf, h2c_info.content_len);
					return ret;
				}
			}
		}

		PLTFM_FREE(buf, h2c_info.content_len);
		residue_len -= pkt_len;
		buffer += pkt_len;
		waddr += pkt_len;
	}

	PLTFM_MUTEX_LOCK(&adapter->flash_info.lock);
	adapter->flash_info.writing = 0;
	adapter->flash_info.write_addr = 0;
	PLTFM_MUTEX_UNLOCK(&adapter->flash_info.lock);
	return MACSUCCESS;
}

#else
u32 mac_flash_erase(struct mac_ax_adapter *adapter,
		    u32 addr,
		    u32 length,
		    u32 timeout)
{
	u32 ret = 0, pkt_len, local_timeout = 10000, no_timeout = 0;
	u32 data[2];

	struct h2c_info h2c_info = {0};

	if (timeout == 0)
		no_timeout = 1;
	else
		local_timeout = timeout;

	PLTFM_MUTEX_LOCK(&adapter->flash_info.lock);
	adapter->flash_info.erase_done = 0;
	adapter->flash_info.erasing = 1;
	adapter->flash_info.erase_addr = addr;
	PLTFM_MUTEX_UNLOCK(&adapter->flash_info.lock);

	pkt_len = LEN_FLASH_H2C_HDR;

	h2c_info.agg_en = 0;
	h2c_info.content_len = (u16)pkt_len;
	h2c_info.h2c_cat = FWCMD_H2C_CAT_MAC;
	h2c_info.h2c_class = FWCMD_H2C_CL_FLASH;
	h2c_info.h2c_func = FWCMD_H2C_FUNC_PLAT_FLASH_ERASE;
	h2c_info.rec_ack = 0;
	h2c_info.done_ack = 0;

	data[0] = cpu_to_le32(addr);
	data[1] = cpu_to_le32(length);

	ret = mac_h2c_common(adapter, &h2c_info, (u32 *)&data[0]);

	if (ret) {
		PLTFM_MUTEX_LOCK(&adapter->flash_info.lock);
		adapter->flash_info.erasing = 0;
		adapter->flash_info.erase_addr = 0;
		PLTFM_MUTEX_UNLOCK(&adapter->flash_info.lock);
		adapter->fw_info.h2c_seq--;
		return ret;
	}

	while (1) {
		PLTFM_MUTEX_LOCK(&adapter->flash_info.lock);
		if (adapter->flash_info.erase_done == 1) {
			adapter->flash_info.erase_done = 0;
			adapter->flash_info.erasing = 0;
			adapter->flash_info.erase_addr = 0;
			PLTFM_MUTEX_UNLOCK(&adapter->flash_info.lock);
			break;
		}
		PLTFM_MUTEX_UNLOCK(&adapter->flash_info.lock);

		//Sleep(50);
		PLTFM_DELAY_MS(1);
		if (no_timeout == 0) {
			local_timeout--;
			if (local_timeout == 0) {
				ret = MACFLASHFAIL;
				PLTFM_MUTEX_LOCK(&adapter->flash_info.lock);
				adapter->flash_info.erasing = 0;
				adapter->flash_info.erase_addr = 0;
				PLTFM_MUTEX_UNLOCK(&adapter->flash_info.lock);
				adapter->fw_info.h2c_seq--;
				return ret;
			}
		}
	}

	PLTFM_MUTEX_LOCK(&adapter->flash_info.lock);
	adapter->flash_info.erasing = 0;
	adapter->flash_info.erase_addr = 0;
	PLTFM_MUTEX_UNLOCK(&adapter->flash_info.lock);
	return MACSUCCESS;
}

u32 mac_flash_read(struct mac_ax_adapter *adapter,
		   u32 addr,
		   u32 length,
		   u8 *buffer,
		   u32 timeout)
{
	u32 ret = 0, pkt_len, local_timeout = 10000, no_timeout = 0;
	u32 data[2];

	struct h2c_info h2c_info = {0};

	if (length > FLASH_H2C_SIZE)
		return MACFLASHFAIL;

	if (timeout == 0)
		no_timeout = 1;
	else
		local_timeout = timeout;

	if ((addr % 4) || (length % 4)) {
		PLTFM_MSG_ERR("Address/length not 4 byte aligned, addr : 0x%x, length : 0x%x\n"
			, addr, length);
		return MACFLASHFAIL;
	}

	// mutex
	PLTFM_MUTEX_LOCK(&adapter->flash_info.lock);
	adapter->flash_info.read_done = 0;
	adapter->flash_info.reading = 1;
	adapter->flash_info.buf_addr = buffer;
	adapter->flash_info.read_addr = addr;
	PLTFM_MUTEX_UNLOCK(&adapter->flash_info.lock);

	pkt_len = LEN_FLASH_H2C_HDR;

	h2c_info.agg_en = 0;
	h2c_info.content_len = (u16)pkt_len;
	h2c_info.h2c_cat = FWCMD_H2C_CAT_MAC;
	h2c_info.h2c_class = FWCMD_H2C_CL_FLASH;
	h2c_info.h2c_func = FWCMD_H2C_FUNC_PLAT_FLASH_READ;
	h2c_info.rec_ack = 0;
	h2c_info.done_ack = 0;

	data[0] = cpu_to_le32(addr);
	data[1] = cpu_to_le32(length);

	ret = mac_h2c_common(adapter, &h2c_info, (u32 *)&data[0]);

	if (ret) {
		PLTFM_MUTEX_LOCK(&adapter->flash_info.lock);
		adapter->flash_info.reading = 0;
		adapter->flash_info.buf_addr = NULL;
		adapter->flash_info.read_addr = 0;
		adapter->flash_info.read_done = 0;
		PLTFM_MUTEX_UNLOCK(&adapter->flash_info.lock);
		adapter->fw_info.h2c_seq--;
		return ret;
	}

	while (1) {
		PLTFM_MUTEX_LOCK(&adapter->flash_info.lock);
		//PLTFM_MSG_TRACE("polling enter critical\n");
		if (adapter->flash_info.read_done == 1) {
			//PLTFM_MSG_TRACE("read DONE\n");
			adapter->flash_info.reading = 0;
			adapter->flash_info.buf_addr = NULL;
			adapter->flash_info.read_addr = 0;
			adapter->flash_info.read_done = 0;
			PLTFM_MUTEX_UNLOCK(&adapter->flash_info.lock);
			break;
		}
		//PLTFM_MSG_TRACE("polling exit critical\n");
		PLTFM_MUTEX_UNLOCK(&adapter->flash_info.lock);
		//Sleep(1);
		PLTFM_DELAY_MS(1);
		if (no_timeout == 0) {
			local_timeout--;
			if (local_timeout == 0) {
				ret = MACFLASHFAIL;
				PLTFM_MUTEX_LOCK(&adapter->flash_info.lock);
				adapter->flash_info.reading = 0;
				adapter->flash_info.buf_addr = NULL;
				adapter->flash_info.read_addr = 0;
				adapter->flash_info.read_done = 0;
				PLTFM_MUTEX_UNLOCK(&adapter->flash_info.lock);
				adapter->fw_info.h2c_seq--;
				return ret;
			}
		}
	}

	// end mutex
	//adapter->flash_info.read_done == 0;
	PLTFM_MUTEX_LOCK(&adapter->flash_info.lock);
	adapter->flash_info.reading = 0;
	adapter->flash_info.buf_addr = NULL;
	adapter->flash_info.read_addr = 0;
	PLTFM_MUTEX_UNLOCK(&adapter->flash_info.lock);
	return MACSUCCESS;
}

u32 mac_flash_write(struct mac_ax_adapter *adapter,
		    u32 addr,
		    u32 length,
		    u8 *buffer,
		    u32 timeout)
{
	u8 *buf;
	u32 ret = 0, residue_len, pkt_len, local_timeout = 5000, no_timeout = 0, i;
	u32 data[2];
	u32 waddr, wlength;
	u32 *pbuf;
	u32 *psource_data;

	struct h2c_info h2c_info = {0};

	if (timeout == 0)
		no_timeout = 1;
	else
		local_timeout = timeout;

	residue_len = length;
	waddr = addr;
	wlength = length;

	if ((addr % 4) || (length % 4)) {
		PLTFM_MSG_ERR("Address/length not 4 byte aligned, addr : 0x%x, length : 0x%x\n"
			, addr, length);
		return MACFLASHFAIL;
	}

	while (residue_len) {
		PLTFM_MUTEX_LOCK(&adapter->flash_info.lock);
		adapter->flash_info.write_done = 0;
		adapter->flash_info.writing = 1;
		adapter->flash_info.write_addr = waddr;
		PLTFM_MUTEX_UNLOCK(&adapter->flash_info.lock);

		if (residue_len >= FLASH_H2C_SIZE)
			pkt_len = FLASH_H2C_SIZE;
		else
			pkt_len = residue_len;

		h2c_info.agg_en = 0;
		h2c_info.content_len = (u16)(pkt_len + LEN_FLASH_H2C_HDR);
		h2c_info.h2c_cat = FWCMD_H2C_CAT_MAC;
		h2c_info.h2c_class = FWCMD_H2C_CL_FLASH;
		h2c_info.h2c_func = FWCMD_H2C_FUNC_PLAT_FLASH_WRITE;
		h2c_info.rec_ack = 0;
		h2c_info.done_ack = 0;

		buf = (u8 *)PLTFM_MALLOC(h2c_info.content_len);
		if (!buf) {
			adapter->fw_info.h2c_seq--;
			return MACBUFALLOC;
		}

		data[0] = cpu_to_le32(waddr);
		data[1] = cpu_to_le32(pkt_len);
		PLTFM_MEMCPY(buf, (u8 *)data, LEN_FLASH_H2C_HDR);

		//copy data
		pbuf = (u32 *)(buf + LEN_FLASH_H2C_HDR);
		psource_data = (u32 *)buffer;
		for (i = 0; i < (pkt_len / sizeof(u32)); i++) {
			*pbuf = cpu_to_le32(*psource_data);
			pbuf++;
			psource_data++;
		}

		ret = mac_h2c_common(adapter, &h2c_info, (u32 *)buf);

		if (ret) {
			PLTFM_MUTEX_LOCK(&adapter->flash_info.lock);
			adapter->flash_info.writing = 0;
			adapter->flash_info.write_addr = 0;
			PLTFM_MUTEX_UNLOCK(&adapter->flash_info.lock);
			adapter->fw_info.h2c_seq--;
			PLTFM_FREE(buf, h2c_info.content_len);
			return ret;
		}

		PLTFM_MSG_ERR("Write H2C, addr = 0x%x, length = %d\n", waddr, pkt_len);

		// delay for flash write
		//Sleep(1000);
		while (1) {
			PLTFM_MUTEX_LOCK(&adapter->flash_info.lock);
			if (adapter->flash_info.write_done == 1) {
				adapter->flash_info.writing = 0;
				adapter->flash_info.write_addr = 0;
				adapter->flash_info.write_done = 0;
				PLTFM_MSG_TRACE("write DONE\n");
				PLTFM_MUTEX_UNLOCK(&adapter->flash_info.lock);
				break;
			}
			PLTFM_MUTEX_UNLOCK(&adapter->flash_info.lock);
			//Sleep(1);
			PLTFM_DELAY_MS(1);
			if (no_timeout == 0) {
				local_timeout--;
				if (local_timeout == 0) {
					ret = MACFLASHFAIL;
					PLTFM_MUTEX_LOCK(&adapter->flash_info.lock);
					adapter->flash_info.writing = 0;
					adapter->flash_info.write_addr = 0;
					PLTFM_MSG_TRACE("write timeout\n");
					PLTFM_MUTEX_UNLOCK(&adapter->flash_info.lock);
					adapter->fw_info.h2c_seq--;
					PLTFM_FREE(buf, h2c_info.content_len);
					return ret;
				}
			}
		}

		PLTFM_FREE(buf, h2c_info.content_len);
		residue_len -= pkt_len;
		buffer += pkt_len;
		waddr += pkt_len;
	}

	PLTFM_MUTEX_LOCK(&adapter->flash_info.lock);
	adapter->flash_info.writing = 0;
	adapter->flash_info.write_addr = 0;
	PLTFM_MUTEX_UNLOCK(&adapter->flash_info.lock);
	return MACSUCCESS;
}

#endif

u32 c2h_sys_flash_pkt(struct mac_ax_adapter *adapter, u8 *buf, u32 len,
		      struct rtw_c2h_info *info)
{
	u32 hdr0, i;
	u32 func, length, addr;
	u32 *pbuf;
	u32 *psource_data;

	PLTFM_MSG_TRACE("%s\n", __func__);
	hdr0 = ((struct fwcmd_hdr *)buf)->hdr0;
	hdr0 = le32_to_cpu(hdr0);

	//set info
	info->c2h_cat = GET_FIELD(hdr0, C2H_HDR_CAT);
	info->c2h_class = GET_FIELD(hdr0, C2H_HDR_CLASS);
	info->c2h_func = GET_FIELD(hdr0, C2H_HDR_FUNC);
	//info->done_ack = 0;
	//info->rec_ack = 0;
	info->content = buf  + FWCMD_HDR_LEN;
	//info->h2c_return = info->c2h_data[1];

	func = GET_FIELD(hdr0, C2H_HDR_FUNC);

	if (func == FWCMD_H2C_FUNC_PLAT_FLASH_READ) {
		addr = *((u32 *)info->content);
		addr = le32_to_cpu(addr);
		length = *((u32 *)(info->content + LEN_FLASH_C2H_HDR_ADDR));
		length = le32_to_cpu(length);
		PLTFM_MSG_TRACE("addr = 0x%x, length = 0x%x\n", addr, length);
		PLTFM_MSG_TRACE("adapter->flash_info.read_addr = 0x%x\n",
				adapter->flash_info.read_addr);
		//PLTFM_MSG_TRACE("adapter->flash_info.buf_addr = 0x%llx\n",
				//(u64)adapter->flash_info.buf_addr);

		PLTFM_MUTEX_LOCK(&adapter->flash_info.lock);
		if (addr == adapter->flash_info.read_addr && adapter->flash_info.reading == 1) {
			// lost data if timeout happened
			//PLTFM_MSG_TRACE("ready to read\n");
			if (adapter->flash_info.buf_addr && length <= MAX_READ_SIZE) {
				PLTFM_MSG_TRACE("memcpy to buf\n");
				//PLTFM_MEMCPY(adapter->flash_info.buf_addr,
				//		 info->content + LEN_FLASH_C2H_HDR, length);
				pbuf = (u32 *)adapter->flash_info.buf_addr;
				psource_data = (u32 *)(info->content + LEN_FLASH_C2H_HDR);
				for (i = 0; i < length / sizeof(u32); i++) {
					*pbuf = le32_to_cpu(*psource_data);
					pbuf++;
					psource_data++;
				}
				//PLTFM_MSG_TRACE("memcpy to buf end\n");
			}
		}
		//PLTFM_MSG_TRACE("set reading = 0\n");
		adapter->flash_info.reading = 0;
		adapter->flash_info.read_done = 1;
		//PLTFM_MSG_TRACE("set reading = 0 end\n");
		PLTFM_MUTEX_UNLOCK(&adapter->flash_info.lock);
		//PLTFM_MSG_TRACE("exit critical\n");
	} else if (func == FWCMD_H2C_FUNC_PLAT_FLASH_WRITE) {
		addr = *((u32 *)info->content);
		addr = le32_to_cpu(addr);
		length = *((u32 *)(info->content + LEN_FLASH_C2H_HDR_ADDR));
		length = le32_to_cpu(length);
		PLTFM_MSG_TRACE("write addr = 0x%x\n", *((u32 *)info->content));
		PLTFM_MSG_TRACE("adapter->flash_info.write_addr = 0x%x\n",
				adapter->flash_info.write_addr);
		PLTFM_MSG_TRACE("write length = 0x%x\n", length);

		PLTFM_MUTEX_LOCK(&adapter->flash_info.lock);
		if (addr == adapter->flash_info.write_addr && adapter->flash_info.writing == 1) {
			adapter->flash_info.writing = 0;
			adapter->flash_info.write_done = 1;
		}
		PLTFM_MUTEX_UNLOCK(&adapter->flash_info.lock);
	} else if (func == FWCMD_H2C_FUNC_PLAT_FLASH_ERASE) {
		addr = *((u32 *)info->content);
		addr = le32_to_cpu(addr);
		length = *((u32 *)(info->content + LEN_FLASH_C2H_HDR_ADDR));
		length = le32_to_cpu(length);
		PLTFM_MSG_TRACE("erase addr = 0x%x\n", *((u32 *)info->content));
		PLTFM_MSG_TRACE("adapter->flash_info.erase_addr = 0x%x\n",
				adapter->flash_info.erase_addr);
		PLTFM_MSG_TRACE("erase length = 0x%x\n", length);

		PLTFM_MUTEX_LOCK(&adapter->flash_info.lock);
		if (addr == adapter->flash_info.erase_addr && adapter->flash_info.erasing == 1) {
			adapter->flash_info.erasing = 0;
			adapter->flash_info.erase_done = 1;
		}
		PLTFM_MUTEX_UNLOCK(&adapter->flash_info.lock);
	}

	return MACSUCCESS;
}

