···11+22+menuconfig SPECTRA33+ tristate "Denali Spectra Flash Translation Layer"44+ depends on BLOCK55+ default n66+ ---help---77+ Enable the FTL pseudo-filesystem used with the NAND Flash88+ controller on Intel Moorestown Platform to pretend to be a disk99+1010+choice1111+ prompt "Compile for"1212+ depends on SPECTRA1313+ default SPECTRA_MRST_HW1414+1515+config SPECTRA_MRST_HW1616+ bool "Moorestown hardware mode"1717+ help1818+ Driver communicates with the Moorestown hardware's register interface.1919+ in DMA mode.2020+2121+config SPECTRA_MTD2222+ bool "Linux MTD mode"2323+ depends on MTD2424+ help2525+ Driver communicates with the kernel MTD subsystem instead of its own2626+ built-in hardware driver.2727+2828+config SPECTRA_EMU2929+ bool "RAM emulator testing"3030+ help3131+ Driver emulates Flash on a RAM buffer and / or disk file. Useful to test the behavior of FTL layer.3232+3333+endchoice3434+3535+config SPECTRA_MRST_HW_DMA3636+ bool3737+ default n3838+ depends on SPECTRA_MRST_HW3939+ help4040+ Use DMA for native hardware interface.
···11+This is a driver for NAND controller of Intel Moorestown platform.22+33+This driver is a standalone linux block device driver, it acts as if it's a normal hard disk.44+It includes three layer:55+ block layer interface - file ffsport.c66+ Flash Translation Layer (FTL) - file flash.c (implement the NAND flash Translation Layer, includs address mapping, garbage collection, wear-leveling and so on)77+ Low level layer - file lld_nand.c/lld_cdma.c/lld_emu.c (which implements actual controller hardware registers access)88+99+This driver can be build as modules or build-in.1010+1111+Dependency:1212+This driver has dependency on IA Firmware of Intel Moorestown platform.1313+It need the IA Firmware to create the block table for the first time.1414+And to validate this driver code without IA Firmware, you can change the1515+macro AUTO_FORMAT_FLASH from 0 to 1 in file spectraswconfig.h. Thus the1616+driver will erase the whole nand flash and create a new block table.1717+1818+TODO:1919+ - Enable Command DMA feature support2020+ - lower the memory footprint2121+ - Remove most of the unnecessary global variables2222+ - Change all the upcase variable / functions name to lowercase2323+ - Some other misc bugs2424+2525+Please send patches to:2626+ Greg Kroah-Hartman <gregkh@suse.de>2727+2828+And Cc to: Gao Yunpeng <yunpeng.gao@intel.com>2929+
+58
drivers/staging/spectra/ffsdefs.h
···11+/*22+ * NAND Flash Controller Device Driver33+ * Copyright (c) 2009, Intel Corporation and its suppliers.44+ *55+ * This program is free software; you can redistribute it and/or modify it66+ * under the terms and conditions of the GNU General Public License,77+ * version 2, as published by the Free Software Foundation.88+ *99+ * This program is distributed in the hope it will be useful, but WITHOUT1010+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or1111+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for1212+ * more details.1313+ *1414+ * You should have received a copy of the GNU General Public License along with1515+ * this program; if not, write to the Free Software Foundation, Inc.,1616+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.1717+ *1818+ */1919+2020+#ifndef _FFSDEFS_2121+#define _FFSDEFS_2222+2323+#define CLEAR 0 /*use this to clear a field instead of "fail"*/2424+#define SET 1 /*use this to set a field instead of "pass"*/2525+#define FAIL 1 /*failed flag*/2626+#define PASS 0 /*success flag*/2727+#define ERR -1 /*error flag*/2828+2929+#define ERASE_CMD 103030+#define WRITE_MAIN_CMD 113131+#define READ_MAIN_CMD 123232+#define WRITE_SPARE_CMD 133333+#define READ_SPARE_CMD 143434+#define WRITE_MAIN_SPARE_CMD 153535+#define READ_MAIN_SPARE_CMD 163636+#define MEMCOPY_CMD 173737+#define DUMMY_CMD 993838+3939+#define EVENT_PASS 0x004040+#define EVENT_CORRECTABLE_DATA_ERROR_FIXED 0x014141+#define EVENT_UNCORRECTABLE_DATA_ERROR 0x024242+#define EVENT_TIME_OUT 0x034343+#define EVENT_PROGRAM_FAILURE 0x044444+#define EVENT_ERASE_FAILURE 0x054545+#define EVENT_MEMCOPY_FAILURE 0x064646+#define EVENT_FAIL 0x074747+4848+#define EVENT_NONE 0x224949+#define EVENT_DMA_CMD_COMP 0x775050+#define EVENT_ECC_TRANSACTION_DONE 0x885151+#define EVENT_DMA_CMD_FAIL 0x995252+5353+#define CMD_PASS 05454+#define CMD_FAIL 15555+#define CMD_ABORT 25656+#define CMD_NOT_DONE 35757+5858+#endif /* _FFSDEFS_ */
+827
drivers/staging/spectra/ffsport.c
···11+/*22+ * NAND Flash Controller Device Driver33+ * Copyright (c) 2009, Intel Corporation and its suppliers.44+ *55+ * This program is free software; you can redistribute it and/or modify it66+ * under the terms and conditions of the GNU General Public License,77+ * version 2, as published by the Free Software Foundation.88+ *99+ * This program is distributed in the hope it will be useful, but WITHOUT1010+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or1111+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for1212+ * more details.1313+ *1414+ * You should have received a copy of the GNU General Public License along with1515+ * this program; if not, write to the Free Software Foundation, Inc.,1616+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.1717+ *1818+ */1919+2020+#include "ffsport.h"2121+#include "flash.h"2222+#include <linux/interrupt.h>2323+#include <linux/delay.h>2424+#include <linux/blkdev.h>2525+#include <linux/wait.h>2626+#include <linux/mutex.h>2727+#include <linux/kthread.h>2828+#include <linux/log2.h>2929+#include <linux/init.h>3030+3131+/**** Helper functions used for Div, Remainder operation on u64 ****/3232+3333+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&3434+* Function: GLOB_Calc_Used_Bits3535+* Inputs: Power of 2 number3636+* Outputs: Number of Used Bits3737+* 0, if the argument is 03838+* Description: Calculate the number of bits used by a given power of 2 number3939+* Number can be upto 32 bit4040+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/4141+int GLOB_Calc_Used_Bits(u32 n)4242+{4343+ int tot_bits = 0;4444+4545+ if (n >= 1 << 16) {4646+ n >>= 16;4747+ tot_bits += 16;4848+ }4949+5050+ if (n >= 1 << 8) {5151+ n >>= 8;5252+ tot_bits += 8;5353+ }5454+5555+ if (n >= 1 << 4) {5656+ n >>= 4;5757+ tot_bits += 4;5858+ }5959+6060+ if (n >= 1 << 2) {6161+ n >>= 2;6262+ tot_bits += 2;6363+ }6464+6565+ if (n >= 1 << 1)6666+ tot_bits += 1;6767+6868+ return ((n == 0) ? (0) : tot_bits);6969+}7070+7171+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&7272+* Function: GLOB_u64_Div7373+* Inputs: Number of u647474+* A power of 2 number as Division7575+* Outputs: Quotient of the Divisor operation7676+* Description: It divides the address by divisor by using bit shift operation7777+* (essentially without explicitely using "/").7878+* Divisor is a power of 2 number and Divided is of u647979+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/8080+u64 GLOB_u64_Div(u64 addr, u32 divisor)8181+{8282+ return (u64)(addr >> GLOB_Calc_Used_Bits(divisor));8383+}8484+8585+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&8686+* Function: GLOB_u64_Remainder8787+* Inputs: Number of u648888+* Divisor Type (1 -PageAddress, 2- BlockAddress)8989+* Outputs: Remainder of the Division operation9090+* Description: It calculates the remainder of a number (of u64) by9191+* divisor(power of 2 number ) by using bit shifting and multiply9292+* operation(essentially without explicitely using "/").9393+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/9494+u64 GLOB_u64_Remainder(u64 addr, u32 divisor_type)9595+{9696+ u64 result = 0;9797+9898+ if (divisor_type == 1) { /* Remainder -- Page */9999+ result = (addr >> DeviceInfo.nBitsInPageDataSize);100100+ result = result * DeviceInfo.wPageDataSize;101101+ } else if (divisor_type == 2) { /* Remainder -- Block */102102+ result = (addr >> DeviceInfo.nBitsInBlockDataSize);103103+ result = result * DeviceInfo.wBlockDataSize;104104+ }105105+106106+ result = addr - result;107107+108108+ return result;109109+}110110+111111+#define NUM_DEVICES 1112112+#define PARTITIONS 8113113+114114+#define GLOB_SBD_NAME "nd"115115+#define GLOB_SBD_IRQ_NUM (29)116116+#define GLOB_VERSION "driver version 20091110"117117+118118+#define GLOB_SBD_IOCTL_GC (0x7701)119119+#define GLOB_SBD_IOCTL_WL (0x7702)120120+#define GLOB_SBD_IOCTL_FORMAT (0x7703)121121+#define GLOB_SBD_IOCTL_ERASE_FLASH (0x7704)122122+#define GLOB_SBD_IOCTL_FLUSH_CACHE (0x7705)123123+#define GLOB_SBD_IOCTL_COPY_BLK_TABLE (0x7706)124124+#define GLOB_SBD_IOCTL_COPY_WEAR_LEVELING_TABLE (0x7707)125125+#define GLOB_SBD_IOCTL_GET_NAND_INFO (0x7708)126126+#define GLOB_SBD_IOCTL_WRITE_DATA (0x7709)127127+#define GLOB_SBD_IOCTL_READ_DATA (0x770A)128128+129129+static int reserved_mb = 0;130130+module_param(reserved_mb, int, 0);131131+MODULE_PARM_DESC(reserved_mb, "Reserved space for OS image, in MiB (default 25 MiB)");132132+133133+int nand_debug_level;134134+module_param(nand_debug_level, int, 0644);135135+MODULE_PARM_DESC(nand_debug_level, "debug level value: 1-3");136136+137137+MODULE_LICENSE("GPL");138138+139139+struct spectra_nand_dev {140140+ struct pci_dev *dev;141141+ u64 size;142142+ u16 users;143143+ spinlock_t qlock;144144+ void __iomem *ioaddr; /* Mapped address */145145+ struct request_queue *queue;146146+ struct task_struct *thread;147147+ struct gendisk *gd;148148+ u8 *tmp_buf;149149+};150150+151151+152152+static int GLOB_SBD_majornum;153153+154154+static char *GLOB_version = GLOB_VERSION;155155+156156+static struct spectra_nand_dev nand_device[NUM_DEVICES];157157+158158+static struct mutex spectra_lock;159159+160160+static int res_blks_os = 1;161161+162162+struct spectra_indentfy_dev_tag IdentifyDeviceData;163163+164164+static int force_flush_cache(void)165165+{166166+ nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n",167167+ __FILE__, __LINE__, __func__);168168+169169+ if (ERR == GLOB_FTL_Flush_Cache()) {170170+ printk(KERN_ERR "Fail to Flush FTL Cache!\n");171171+ return -EFAULT;172172+ }173173+#if CMD_DMA174174+ if (glob_ftl_execute_cmds())175175+ return -EIO;176176+ else177177+ return 0;178178+#endif179179+ return 0;180180+}181181+182182+struct ioctl_rw_page_info {183183+ u8 *data;184184+ unsigned int page;185185+};186186+187187+static int ioctl_read_page_data(unsigned long arg)188188+{189189+ u8 *buf;190190+ struct ioctl_rw_page_info info;191191+ int result = PASS;192192+193193+ if (copy_from_user(&info, (void __user *)arg, sizeof(info)))194194+ return -EFAULT;195195+196196+ buf = kmalloc(IdentifyDeviceData.PageDataSize, GFP_ATOMIC);197197+ if (!buf) {198198+ printk(KERN_ERR "ioctl_read_page_data: "199199+ "failed to allocate memory\n");200200+ return -ENOMEM;201201+ }202202+203203+ mutex_lock(&spectra_lock);204204+ result = GLOB_FTL_Page_Read(buf,205205+ (u64)info.page * IdentifyDeviceData.PageDataSize);206206+ mutex_unlock(&spectra_lock);207207+208208+ if (copy_to_user((void __user *)info.data, buf,209209+ IdentifyDeviceData.PageDataSize)) {210210+ printk(KERN_ERR "ioctl_read_page_data: "211211+ "failed to copy user data\n");212212+ kfree(buf);213213+ return -EFAULT;214214+ }215215+216216+ kfree(buf);217217+ return result;218218+}219219+220220+static int ioctl_write_page_data(unsigned long arg)221221+{222222+ u8 *buf;223223+ struct ioctl_rw_page_info info;224224+ int result = PASS;225225+226226+ if (copy_from_user(&info, (void __user *)arg, sizeof(info)))227227+ return -EFAULT;228228+229229+ buf = kmalloc(IdentifyDeviceData.PageDataSize, GFP_ATOMIC);230230+ if (!buf) {231231+ printk(KERN_ERR "ioctl_write_page_data: "232232+ "failed to allocate memory\n");233233+ return -ENOMEM;234234+ }235235+236236+ if (copy_from_user(buf, (void __user *)info.data,237237+ IdentifyDeviceData.PageDataSize)) {238238+ printk(KERN_ERR "ioctl_write_page_data: "239239+ "failed to copy user data\n");240240+ kfree(buf);241241+ return -EFAULT;242242+ }243243+244244+ mutex_lock(&spectra_lock);245245+ result = GLOB_FTL_Page_Write(buf,246246+ (u64)info.page * IdentifyDeviceData.PageDataSize);247247+ mutex_unlock(&spectra_lock);248248+249249+ kfree(buf);250250+ return result;251251+}252252+253253+/* Return how many blocks should be reserved for bad block replacement */254254+static int get_res_blk_num_bad_blk(void)255255+{256256+ return IdentifyDeviceData.wDataBlockNum / 10;257257+}258258+259259+/* Return how many blocks should be reserved for OS image */260260+static int get_res_blk_num_os(void)261261+{262262+ u32 res_blks, blk_size;263263+264264+ blk_size = IdentifyDeviceData.PageDataSize *265265+ IdentifyDeviceData.PagesPerBlock;266266+267267+ res_blks = (reserved_mb * 1024 * 1024) / blk_size;268268+269269+ if ((res_blks < 1) || (res_blks >= IdentifyDeviceData.wDataBlockNum))270270+ res_blks = 1; /* Reserved 1 block for block table */271271+272272+ return res_blks;273273+}274274+275275+static void SBD_prepare_flush(struct request_queue *q, struct request *rq)276276+{277277+ rq->cmd_type = REQ_TYPE_LINUX_BLOCK;278278+ /* rq->timeout = 5 * HZ; */279279+ rq->cmd[0] = REQ_LB_OP_FLUSH;280280+}281281+282282+/* Transfer a full request. */283283+static int do_transfer(struct spectra_nand_dev *tr, struct request *req)284284+{285285+ u64 start_addr, addr;286286+ u32 logical_start_sect, hd_start_sect;287287+ u32 nsect, hd_sects;288288+ u32 rsect, tsect = 0;289289+ char *buf;290290+ u32 ratio = IdentifyDeviceData.PageDataSize >> 9;291291+292292+ start_addr = (u64)(blk_rq_pos(req)) << 9;293293+ /* Add a big enough offset to prevent the OS Image from294294+ * being accessed or damaged by file system */295295+ start_addr += IdentifyDeviceData.PageDataSize *296296+ IdentifyDeviceData.PagesPerBlock *297297+ res_blks_os;298298+299299+ if (req->cmd_type == REQ_TYPE_LINUX_BLOCK &&300300+ req->cmd[0] == REQ_LB_OP_FLUSH) {301301+ if (force_flush_cache()) /* Fail to flush cache */302302+ return -EIO;303303+ else304304+ return 0;305305+ }306306+307307+ if (!blk_fs_request(req))308308+ return -EIO;309309+310310+ if (blk_rq_pos(req) + blk_rq_cur_sectors(req) > get_capacity(tr->gd)) {311311+ printk(KERN_ERR "Spectra error: request over the NAND "312312+ "capacity!sector %d, current_nr_sectors %d, "313313+ "while capacity is %d\n",314314+ (int)blk_rq_pos(req),315315+ blk_rq_cur_sectors(req),316316+ (int)get_capacity(tr->gd));317317+ return -EIO;318318+ }319319+320320+ logical_start_sect = start_addr >> 9;321321+ hd_start_sect = logical_start_sect / ratio;322322+ rsect = logical_start_sect - hd_start_sect * ratio;323323+324324+ addr = (u64)hd_start_sect * ratio * 512;325325+ buf = req->buffer;326326+ nsect = blk_rq_cur_sectors(req);327327+328328+ if (rsect)329329+ tsect = (ratio - rsect) < nsect ? (ratio - rsect) : nsect;330330+331331+ switch (rq_data_dir(req)) {332332+ case READ:333333+ /* Read the first NAND page */334334+ if (rsect) {335335+ if (GLOB_FTL_Page_Read(tr->tmp_buf, addr)) {336336+ printk(KERN_ERR "Error in %s, Line %d\n",337337+ __FILE__, __LINE__);338338+ return -EIO;339339+ }340340+ memcpy(buf, tr->tmp_buf + (rsect << 9), tsect << 9);341341+ addr += IdentifyDeviceData.PageDataSize;342342+ buf += tsect << 9;343343+ nsect -= tsect;344344+ }345345+346346+ /* Read the other NAND pages */347347+ for (hd_sects = nsect / ratio; hd_sects > 0; hd_sects--) {348348+ if (GLOB_FTL_Page_Read(buf, addr)) {349349+ printk(KERN_ERR "Error in %s, Line %d\n",350350+ __FILE__, __LINE__);351351+ return -EIO;352352+ }353353+ addr += IdentifyDeviceData.PageDataSize;354354+ buf += IdentifyDeviceData.PageDataSize;355355+ }356356+357357+ /* Read the last NAND pages */358358+ if (nsect % ratio) {359359+ if (GLOB_FTL_Page_Read(tr->tmp_buf, addr)) {360360+ printk(KERN_ERR "Error in %s, Line %d\n",361361+ __FILE__, __LINE__);362362+ return -EIO;363363+ }364364+ memcpy(buf, tr->tmp_buf, (nsect % ratio) << 9);365365+ }366366+#if CMD_DMA367367+ if (glob_ftl_execute_cmds())368368+ return -EIO;369369+ else370370+ return 0;371371+#endif372372+ return 0;373373+374374+ case WRITE:375375+ /* Write the first NAND page */376376+ if (rsect) {377377+ if (GLOB_FTL_Page_Read(tr->tmp_buf, addr)) {378378+ printk(KERN_ERR "Error in %s, Line %d\n",379379+ __FILE__, __LINE__);380380+ return -EIO;381381+ }382382+ memcpy(tr->tmp_buf + (rsect << 9), buf, tsect << 9);383383+ if (GLOB_FTL_Page_Write(tr->tmp_buf, addr)) {384384+ printk(KERN_ERR "Error in %s, Line %d\n",385385+ __FILE__, __LINE__);386386+ return -EIO;387387+ }388388+ addr += IdentifyDeviceData.PageDataSize;389389+ buf += tsect << 9;390390+ nsect -= tsect;391391+ }392392+393393+ /* Write the other NAND pages */394394+ for (hd_sects = nsect / ratio; hd_sects > 0; hd_sects--) {395395+ if (GLOB_FTL_Page_Write(buf, addr)) {396396+ printk(KERN_ERR "Error in %s, Line %d\n",397397+ __FILE__, __LINE__);398398+ return -EIO;399399+ }400400+ addr += IdentifyDeviceData.PageDataSize;401401+ buf += IdentifyDeviceData.PageDataSize;402402+ }403403+404404+ /* Write the last NAND pages */405405+ if (nsect % ratio) {406406+ if (GLOB_FTL_Page_Read(tr->tmp_buf, addr)) {407407+ printk(KERN_ERR "Error in %s, Line %d\n",408408+ __FILE__, __LINE__);409409+ return -EIO;410410+ }411411+ memcpy(tr->tmp_buf, buf, (nsect % ratio) << 9);412412+ if (GLOB_FTL_Page_Write(tr->tmp_buf, addr)) {413413+ printk(KERN_ERR "Error in %s, Line %d\n",414414+ __FILE__, __LINE__);415415+ return -EIO;416416+ }417417+ }418418+#if CMD_DMA419419+ if (glob_ftl_execute_cmds())420420+ return -EIO;421421+ else422422+ return 0;423423+#endif424424+ return 0;425425+426426+ default:427427+ printk(KERN_NOTICE "Unknown request %u\n", rq_data_dir(req));428428+ return -EIO;429429+ }430430+}431431+432432+/* This function is copied from drivers/mtd/mtd_blkdevs.c */433433+static int spectra_trans_thread(void *arg)434434+{435435+ struct spectra_nand_dev *tr = arg;436436+ struct request_queue *rq = tr->queue;437437+ struct request *req = NULL;438438+439439+ /* we might get involved when memory gets low, so use PF_MEMALLOC */440440+ current->flags |= PF_MEMALLOC;441441+442442+ spin_lock_irq(rq->queue_lock);443443+ while (!kthread_should_stop()) {444444+ int res;445445+446446+ if (!req) {447447+ req = blk_fetch_request(rq);448448+ if (!req) {449449+ set_current_state(TASK_INTERRUPTIBLE);450450+ spin_unlock_irq(rq->queue_lock);451451+ schedule();452452+ spin_lock_irq(rq->queue_lock);453453+ continue;454454+ }455455+ }456456+457457+ spin_unlock_irq(rq->queue_lock);458458+459459+ mutex_lock(&spectra_lock);460460+ res = do_transfer(tr, req);461461+ mutex_unlock(&spectra_lock);462462+463463+ spin_lock_irq(rq->queue_lock);464464+465465+ if (!__blk_end_request_cur(req, res))466466+ req = NULL;467467+ }468468+469469+ if (req)470470+ __blk_end_request_all(req, -EIO);471471+472472+ spin_unlock_irq(rq->queue_lock);473473+474474+ return 0;475475+}476476+477477+478478+/* Request function that "handles clustering". */479479+static void GLOB_SBD_request(struct request_queue *rq)480480+{481481+ struct spectra_nand_dev *pdev = rq->queuedata;482482+ wake_up_process(pdev->thread);483483+}484484+485485+static int GLOB_SBD_open(struct block_device *bdev, fmode_t mode)486486+487487+{488488+ nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n",489489+ __FILE__, __LINE__, __func__);490490+ return 0;491491+}492492+493493+static int GLOB_SBD_release(struct gendisk *disk, fmode_t mode)494494+{495495+ int ret;496496+497497+ nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n",498498+ __FILE__, __LINE__, __func__);499499+500500+ mutex_lock(&spectra_lock);501501+ ret = force_flush_cache();502502+ mutex_unlock(&spectra_lock);503503+504504+ return 0;505505+}506506+507507+static int GLOB_SBD_getgeo(struct block_device *bdev, struct hd_geometry *geo)508508+{509509+ geo->heads = 4;510510+ geo->sectors = 16;511511+ geo->cylinders = get_capacity(bdev->bd_disk) / (4 * 16);512512+513513+ nand_dbg_print(NAND_DBG_DEBUG,514514+ "heads: %d, sectors: %d, cylinders: %d\n",515515+ geo->heads, geo->sectors, geo->cylinders);516516+517517+ return 0;518518+}519519+520520+int GLOB_SBD_ioctl(struct block_device *bdev, fmode_t mode,521521+ unsigned int cmd, unsigned long arg)522522+{523523+ int ret;524524+525525+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",526526+ __FILE__, __LINE__, __func__);527527+528528+ switch (cmd) {529529+ case GLOB_SBD_IOCTL_GC:530530+ nand_dbg_print(NAND_DBG_DEBUG,531531+ "Spectra IOCTL: Garbage Collection "532532+ "being performed\n");533533+ if (PASS != GLOB_FTL_Garbage_Collection())534534+ return -EFAULT;535535+ return 0;536536+537537+ case GLOB_SBD_IOCTL_WL:538538+ nand_dbg_print(NAND_DBG_DEBUG,539539+ "Spectra IOCTL: Static Wear Leveling "540540+ "being performed\n");541541+ if (PASS != GLOB_FTL_Wear_Leveling())542542+ return -EFAULT;543543+ return 0;544544+545545+ case GLOB_SBD_IOCTL_FORMAT:546546+ nand_dbg_print(NAND_DBG_DEBUG, "Spectra IOCTL: Flash format "547547+ "being performed\n");548548+ if (PASS != GLOB_FTL_Flash_Format())549549+ return -EFAULT;550550+ return 0;551551+552552+ case GLOB_SBD_IOCTL_FLUSH_CACHE:553553+ nand_dbg_print(NAND_DBG_DEBUG, "Spectra IOCTL: Cache flush "554554+ "being performed\n");555555+ mutex_lock(&spectra_lock);556556+ ret = force_flush_cache();557557+ mutex_unlock(&spectra_lock);558558+ return ret;559559+560560+ case GLOB_SBD_IOCTL_COPY_BLK_TABLE:561561+ nand_dbg_print(NAND_DBG_DEBUG, "Spectra IOCTL: "562562+ "Copy block table\n");563563+ if (copy_to_user((void __user *)arg,564564+ get_blk_table_start_addr(),565565+ get_blk_table_len()))566566+ return -EFAULT;567567+ return 0;568568+569569+ case GLOB_SBD_IOCTL_COPY_WEAR_LEVELING_TABLE:570570+ nand_dbg_print(NAND_DBG_DEBUG, "Spectra IOCTL: "571571+ "Copy wear leveling table\n");572572+ if (copy_to_user((void __user *)arg,573573+ get_wear_leveling_table_start_addr(),574574+ get_wear_leveling_table_len()))575575+ return -EFAULT;576576+ return 0;577577+578578+ case GLOB_SBD_IOCTL_GET_NAND_INFO:579579+ nand_dbg_print(NAND_DBG_DEBUG, "Spectra IOCTL: "580580+ "Get NAND info\n");581581+ if (copy_to_user((void __user *)arg, &IdentifyDeviceData,582582+ sizeof(IdentifyDeviceData)))583583+ return -EFAULT;584584+ return 0;585585+586586+ case GLOB_SBD_IOCTL_WRITE_DATA:587587+ nand_dbg_print(NAND_DBG_DEBUG, "Spectra IOCTL: "588588+ "Write one page data\n");589589+ return ioctl_write_page_data(arg);590590+591591+ case GLOB_SBD_IOCTL_READ_DATA:592592+ nand_dbg_print(NAND_DBG_DEBUG, "Spectra IOCTL: "593593+ "Read one page data\n");594594+ return ioctl_read_page_data(arg);595595+ }596596+597597+ return -ENOTTY;598598+}599599+600600+static struct block_device_operations GLOB_SBD_ops = {601601+ .owner = THIS_MODULE,602602+ .open = GLOB_SBD_open,603603+ .release = GLOB_SBD_release,604604+ .locked_ioctl = GLOB_SBD_ioctl,605605+ .getgeo = GLOB_SBD_getgeo,606606+};607607+608608+static int SBD_setup_device(struct spectra_nand_dev *dev, int which)609609+{610610+ int res_blks;611611+ u32 sects;612612+613613+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",614614+ __FILE__, __LINE__, __func__);615615+616616+ memset(dev, 0, sizeof(struct spectra_nand_dev));617617+618618+ nand_dbg_print(NAND_DBG_WARN, "Reserved %d blocks "619619+ "for OS image, %d blocks for bad block replacement.\n",620620+ get_res_blk_num_os(),621621+ get_res_blk_num_bad_blk());622622+623623+ res_blks = get_res_blk_num_bad_blk() + get_res_blk_num_os();624624+625625+ dev->size = (u64)IdentifyDeviceData.PageDataSize *626626+ IdentifyDeviceData.PagesPerBlock *627627+ (IdentifyDeviceData.wDataBlockNum - res_blks);628628+629629+ res_blks_os = get_res_blk_num_os();630630+631631+ spin_lock_init(&dev->qlock);632632+633633+ dev->tmp_buf = kmalloc(IdentifyDeviceData.PageDataSize, GFP_ATOMIC);634634+ if (!dev->tmp_buf) {635635+ printk(KERN_ERR "Failed to kmalloc memory in %s Line %d, exit.\n",636636+ __FILE__, __LINE__);637637+ goto out_vfree;638638+ }639639+640640+ dev->queue = blk_init_queue(GLOB_SBD_request, &dev->qlock);641641+ if (dev->queue == NULL) {642642+ printk(KERN_ERR643643+ "Spectra: Request queue could not be initialized."644644+ " Aborting\n ");645645+ goto out_vfree;646646+ }647647+ dev->queue->queuedata = dev;648648+649649+ /* As Linux block layer doens't support >4KB hardware sector, */650650+ /* Here we force report 512 byte hardware sector size to Kernel */651651+ blk_queue_logical_block_size(dev->queue, 512);652652+653653+ blk_queue_ordered(dev->queue, QUEUE_ORDERED_DRAIN_FLUSH,654654+ SBD_prepare_flush);655655+656656+ dev->thread = kthread_run(spectra_trans_thread, dev, "nand_thd");657657+ if (IS_ERR(dev->thread)) {658658+ blk_cleanup_queue(dev->queue);659659+ unregister_blkdev(GLOB_SBD_majornum, GLOB_SBD_NAME);660660+ return PTR_ERR(dev->thread);661661+ }662662+663663+ dev->gd = alloc_disk(PARTITIONS);664664+ if (!dev->gd) {665665+ printk(KERN_ERR666666+ "Spectra: Could not allocate disk. Aborting \n ");667667+ goto out_vfree;668668+ }669669+ dev->gd->major = GLOB_SBD_majornum;670670+ dev->gd->first_minor = which * PARTITIONS;671671+ dev->gd->fops = &GLOB_SBD_ops;672672+ dev->gd->queue = dev->queue;673673+ dev->gd->private_data = dev;674674+ snprintf(dev->gd->disk_name, 32, "%s%c", GLOB_SBD_NAME, which + 'a');675675+676676+ sects = dev->size >> 9;677677+ nand_dbg_print(NAND_DBG_WARN, "Capacity sects: %d\n", sects);678678+ set_capacity(dev->gd, sects);679679+680680+ add_disk(dev->gd);681681+682682+ return 0;683683+out_vfree:684684+ return -ENOMEM;685685+}686686+687687+/*688688+static ssize_t show_nand_block_num(struct device *dev,689689+ struct device_attribute *attr, char *buf)690690+{691691+ return snprintf(buf, PAGE_SIZE, "%d\n",692692+ (int)IdentifyDeviceData.wDataBlockNum);693693+}694694+695695+static ssize_t show_nand_pages_per_block(struct device *dev,696696+ struct device_attribute *attr, char *buf)697697+{698698+ return snprintf(buf, PAGE_SIZE, "%d\n",699699+ (int)IdentifyDeviceData.PagesPerBlock);700700+}701701+702702+static ssize_t show_nand_page_size(struct device *dev,703703+ struct device_attribute *attr, char *buf)704704+{705705+ return snprintf(buf, PAGE_SIZE, "%d\n",706706+ (int)IdentifyDeviceData.PageDataSize);707707+}708708+709709+static DEVICE_ATTR(nand_block_num, 0444, show_nand_block_num, NULL);710710+static DEVICE_ATTR(nand_pages_per_block, 0444, show_nand_pages_per_block, NULL);711711+static DEVICE_ATTR(nand_page_size, 0444, show_nand_page_size, NULL);712712+713713+static void create_sysfs_entry(struct device *dev)714714+{715715+ if (device_create_file(dev, &dev_attr_nand_block_num))716716+ printk(KERN_ERR "Spectra: "717717+ "failed to create sysfs entry nand_block_num.\n");718718+ if (device_create_file(dev, &dev_attr_nand_pages_per_block))719719+ printk(KERN_ERR "Spectra: "720720+ "failed to create sysfs entry nand_pages_per_block.\n");721721+ if (device_create_file(dev, &dev_attr_nand_page_size))722722+ printk(KERN_ERR "Spectra: "723723+ "failed to create sysfs entry nand_page_size.\n");724724+}725725+*/726726+727727+static int GLOB_SBD_init(void)728728+{729729+ int i;730730+731731+ /* Set debug output level (0~3) here. 3 is most verbose */732732+ printk(KERN_ALERT "Spectra: %s\n", GLOB_version);733733+734734+ mutex_init(&spectra_lock);735735+736736+ GLOB_SBD_majornum = register_blkdev(0, GLOB_SBD_NAME);737737+ if (GLOB_SBD_majornum <= 0) {738738+ printk(KERN_ERR "Unable to get the major %d for Spectra",739739+ GLOB_SBD_majornum);740740+ return -EBUSY;741741+ }742742+743743+ if (PASS != GLOB_FTL_Flash_Init()) {744744+ printk(KERN_ERR "Spectra: Unable to Initialize Flash Device. "745745+ "Aborting\n");746746+ goto out_flash_register;747747+ }748748+749749+ /* create_sysfs_entry(&dev->dev); */750750+751751+ if (PASS != GLOB_FTL_IdentifyDevice(&IdentifyDeviceData)) {752752+ printk(KERN_ERR "Spectra: Unable to Read Flash Device. "753753+ "Aborting\n");754754+ goto out_flash_register;755755+ } else {756756+ nand_dbg_print(NAND_DBG_WARN, "In GLOB_SBD_init: "757757+ "Num blocks=%d, pagesperblock=%d, "758758+ "pagedatasize=%d, ECCBytesPerSector=%d\n",759759+ (int)IdentifyDeviceData.NumBlocks,760760+ (int)IdentifyDeviceData.PagesPerBlock,761761+ (int)IdentifyDeviceData.PageDataSize,762762+ (int)IdentifyDeviceData.wECCBytesPerSector);763763+ }764764+765765+ printk(KERN_ALERT "Spectra: searching block table, please wait ...\n");766766+ if (GLOB_FTL_Init() != PASS) {767767+ printk(KERN_ERR "Spectra: Unable to Initialize FTL Layer. "768768+ "Aborting\n");769769+ goto out_ftl_flash_register;770770+ }771771+ printk(KERN_ALERT "Spectra: block table has been found.\n");772772+773773+ for (i = 0; i < NUM_DEVICES; i++)774774+ if (SBD_setup_device(&nand_device[i], i) == -ENOMEM)775775+ goto out_ftl_flash_register;776776+777777+ nand_dbg_print(NAND_DBG_DEBUG,778778+ "Spectra: module loaded with major number %d\n",779779+ GLOB_SBD_majornum);780780+781781+ return 0;782782+783783+out_ftl_flash_register:784784+ GLOB_FTL_Cache_Release();785785+out_flash_register:786786+ GLOB_FTL_Flash_Release();787787+ unregister_blkdev(GLOB_SBD_majornum, GLOB_SBD_NAME);788788+ printk(KERN_ERR "Spectra: Module load failed.\n");789789+790790+ return -ENOMEM;791791+}792792+793793+static void __exit GLOB_SBD_exit(void)794794+{795795+ int i;796796+797797+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",798798+ __FILE__, __LINE__, __func__);799799+800800+ for (i = 0; i < NUM_DEVICES; i++) {801801+ struct spectra_nand_dev *dev = &nand_device[i];802802+ if (dev->gd) {803803+ del_gendisk(dev->gd);804804+ put_disk(dev->gd);805805+ }806806+ if (dev->queue)807807+ blk_cleanup_queue(dev->queue);808808+ kfree(dev->tmp_buf);809809+ }810810+811811+ unregister_blkdev(GLOB_SBD_majornum, GLOB_SBD_NAME);812812+813813+ mutex_lock(&spectra_lock);814814+ force_flush_cache();815815+ mutex_unlock(&spectra_lock);816816+817817+ GLOB_FTL_Cache_Release();818818+819819+ GLOB_FTL_Flash_Release();820820+821821+ nand_dbg_print(NAND_DBG_DEBUG,822822+ "Spectra FTL module (major number %d) unloaded.\n",823823+ GLOB_SBD_majornum);824824+}825825+826826+module_init(GLOB_SBD_init);827827+module_exit(GLOB_SBD_exit);
+84
drivers/staging/spectra/ffsport.h
···11+/*22+ * NAND Flash Controller Device Driver33+ * Copyright (c) 2009, Intel Corporation and its suppliers.44+ *55+ * This program is free software; you can redistribute it and/or modify it66+ * under the terms and conditions of the GNU General Public License,77+ * version 2, as published by the Free Software Foundation.88+ *99+ * This program is distributed in the hope it will be useful, but WITHOUT1010+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or1111+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for1212+ * more details.1313+ *1414+ * You should have received a copy of the GNU General Public License along with1515+ * this program; if not, write to the Free Software Foundation, Inc.,1616+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.1717+ *1818+ */1919+2020+#ifndef _FFSPORT_2121+#define _FFSPORT_2222+2323+#include "ffsdefs.h"2424+2525+#if defined __GNUC__2626+#define PACKED2727+#define PACKED_GNU __attribute__ ((packed))2828+#define UNALIGNED2929+#endif3030+3131+#include <linux/semaphore.h>3232+#include <linux/string.h> /* for strcpy(), stricmp(), etc */3333+#include <linux/mm.h> /* for kmalloc(), kfree() */3434+#include <linux/vmalloc.h>3535+#include <linux/module.h>3636+#include <linux/moduleparam.h>3737+#include <linux/init.h>3838+3939+#include <linux/kernel.h> /* printk() */4040+#include <linux/fs.h> /* everything... */4141+#include <linux/errno.h> /* error codes */4242+#include <linux/types.h> /* size_t */4343+#include <linux/genhd.h>4444+#include <linux/blkdev.h>4545+#include <linux/hdreg.h>4646+#include <linux/pci.h>4747+#include "flash.h"4848+4949+#define VERBOSE 15050+5151+#define NAND_DBG_WARN 15252+#define NAND_DBG_DEBUG 25353+#define NAND_DBG_TRACE 35454+5555+extern int nand_debug_level;5656+5757+#ifdef VERBOSE5858+#define nand_dbg_print(level, args...) \5959+ do { \6060+ if (level <= nand_debug_level) \6161+ printk(KERN_ALERT args); \6262+ } while (0)6363+#else6464+#define nand_dbg_print(level, args...)6565+#endif6666+6767+#ifdef SUPPORT_BIG_ENDIAN6868+#define INVERTUINT16(w) ((u16)(((u16)(w)) << 8) | \6969+ (u16)((u16)(w) >> 8))7070+7171+#define INVERTUINT32(dw) (((u32)(dw) << 24) | \7272+ (((u32)(dw) << 8) & 0x00ff0000) | \7373+ (((u32)(dw) >> 8) & 0x0000ff00) | \7474+ ((u32)(dw) >> 24))7575+#else7676+#define INVERTUINT16(w) w7777+#define INVERTUINT32(dw) dw7878+#endif7979+8080+extern int GLOB_Calc_Used_Bits(u32 n);8181+extern u64 GLOB_u64_Div(u64 addr, u32 divisor);8282+extern u64 GLOB_u64_Remainder(u64 addr, u32 divisor_type);8383+8484+#endif /* _FFSPORT_ */
+4731
drivers/staging/spectra/flash.c
···11+/*22+ * NAND Flash Controller Device Driver33+ * Copyright (c) 2009, Intel Corporation and its suppliers.44+ *55+ * This program is free software; you can redistribute it and/or modify it66+ * under the terms and conditions of the GNU General Public License,77+ * version 2, as published by the Free Software Foundation.88+ *99+ * This program is distributed in the hope it will be useful, but WITHOUT1010+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or1111+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for1212+ * more details.1313+ *1414+ * You should have received a copy of the GNU General Public License along with1515+ * this program; if not, write to the Free Software Foundation, Inc.,1616+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.1717+ *1818+ */1919+2020+#include <linux/fs.h>2121+#include <linux/slab.h>2222+2323+#include "flash.h"2424+#include "ffsdefs.h"2525+#include "lld.h"2626+#include "lld_nand.h"2727+#if CMD_DMA2828+#include "lld_cdma.h"2929+#endif3030+3131+#define BLK_FROM_ADDR(addr) ((u32)(addr >> DeviceInfo.nBitsInBlockDataSize))3232+#define PAGE_FROM_ADDR(addr, Block) ((u16)((addr - (u64)Block * \3333+ DeviceInfo.wBlockDataSize) >> DeviceInfo.nBitsInPageDataSize))3434+3535+#define IS_SPARE_BLOCK(blk) (BAD_BLOCK != (pbt[blk] &\3636+ BAD_BLOCK) && SPARE_BLOCK == (pbt[blk] & SPARE_BLOCK))3737+3838+#define IS_DATA_BLOCK(blk) (0 == (pbt[blk] & BAD_BLOCK))3939+4040+#define IS_DISCARDED_BLOCK(blk) (BAD_BLOCK != (pbt[blk] &\4141+ BAD_BLOCK) && DISCARD_BLOCK == (pbt[blk] & DISCARD_BLOCK))4242+4343+#define IS_BAD_BLOCK(blk) (BAD_BLOCK == (pbt[blk] & BAD_BLOCK))4444+4545+#if DEBUG_BNDRY4646+void debug_boundary_lineno_error(int chnl, int limit, int no,4747+ int lineno, char *filename)4848+{4949+ if (chnl >= limit)5050+ printk(KERN_ERR "Boundary Check Fail value %d >= limit %d, "5151+ "at %s:%d. Other info:%d. Aborting...\n",5252+ chnl, limit, filename, lineno, no);5353+}5454+/* static int globalmemsize; */5555+#endif5656+5757+static u16 FTL_Cache_If_Hit(u64 dwPageAddr);5858+static int FTL_Cache_Read(u64 dwPageAddr);5959+static void FTL_Cache_Read_Page(u8 *pData, u64 dwPageAddr,6060+ u16 cache_blk);6161+static void FTL_Cache_Write_Page(u8 *pData, u64 dwPageAddr,6262+ u8 cache_blk, u16 flag);6363+static int FTL_Cache_Write(void);6464+static int FTL_Cache_Write_Back(u8 *pData, u64 blk_addr);6565+static void FTL_Calculate_LRU(void);6666+static u32 FTL_Get_Block_Index(u32 wBlockNum);6767+6868+static int FTL_Search_Block_Table_IN_Block(u32 BT_Block,6969+ u8 BT_Tag, u16 *Page);7070+static int FTL_Read_Block_Table(void);7171+static int FTL_Write_Block_Table(int wForce);7272+static int FTL_Write_Block_Table_Data(void);7373+static int FTL_Check_Block_Table(int wOldTable);7474+static int FTL_Static_Wear_Leveling(void);7575+static u32 FTL_Replace_Block_Table(void);7676+static int FTL_Write_IN_Progress_Block_Table_Page(void);7777+7878+static u32 FTL_Get_Page_Num(u64 length);7979+static u64 FTL_Get_Physical_Block_Addr(u64 blk_addr);8080+8181+static u32 FTL_Replace_OneBlock(u32 wBlockNum,8282+ u32 wReplaceNum);8383+static u32 FTL_Replace_LWBlock(u32 wBlockNum,8484+ int *pGarbageCollect);8585+static u32 FTL_Replace_MWBlock(void);8686+static int FTL_Replace_Block(u64 blk_addr);8787+static int FTL_Adjust_Relative_Erase_Count(u32 Index_of_MAX);8888+8989+static int FTL_Flash_Error_Handle(u8 *pData, u64 old_page_addr, u64 blk_addr);9090+9191+struct device_info_tag DeviceInfo;9292+struct flash_cache_tag Cache;9393+static struct spectra_l2_cache_info cache_l2;9494+9595+static u8 *cache_l2_page_buf;9696+static u8 *cache_l2_blk_buf;9797+9898+u8 *g_pBlockTable;9999+u8 *g_pWearCounter;100100+u16 *g_pReadCounter;101101+u32 *g_pBTBlocks;102102+static u16 g_wBlockTableOffset;103103+static u32 g_wBlockTableIndex;104104+static u8 g_cBlockTableStatus;105105+106106+static u8 *g_pTempBuf;107107+static u8 *flag_check_blk_table;108108+static u8 *tmp_buf_search_bt_in_block;109109+static u8 *spare_buf_search_bt_in_block;110110+static u8 *spare_buf_bt_search_bt_in_block;111111+static u8 *tmp_buf1_read_blk_table;112112+static u8 *tmp_buf2_read_blk_table;113113+static u8 *flags_static_wear_leveling;114114+static u8 *tmp_buf_write_blk_table_data;115115+static u8 *tmp_buf_read_disturbance;116116+117117+u8 *buf_read_page_main_spare;118118+u8 *buf_write_page_main_spare;119119+u8 *buf_read_page_spare;120120+u8 *buf_get_bad_block;121121+122122+#if (RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE && CMD_DMA)123123+struct flash_cache_delta_list_tag int_cache[MAX_CHANS + MAX_DESCS];124124+struct flash_cache_tag cache_start_copy;125125+#endif126126+127127+int g_wNumFreeBlocks;128128+u8 g_SBDCmdIndex;129129+130130+static u8 *g_pIPF;131131+static u8 bt_flag = FIRST_BT_ID;132132+static u8 bt_block_changed;133133+134134+static u16 cache_block_to_write;135135+static u8 last_erased = FIRST_BT_ID;136136+137137+static u8 GC_Called;138138+static u8 BT_GC_Called;139139+140140+#if CMD_DMA141141+#define COPY_BACK_BUF_NUM 10142142+143143+static u8 ftl_cmd_cnt; /* Init value is 0 */144144+u8 *g_pBTDelta;145145+u8 *g_pBTDelta_Free;146146+u8 *g_pBTStartingCopy;147147+u8 *g_pWearCounterCopy;148148+u16 *g_pReadCounterCopy;149149+u8 *g_pBlockTableCopies;150150+u8 *g_pNextBlockTable;151151+static u8 *cp_back_buf_copies[COPY_BACK_BUF_NUM];152152+static int cp_back_buf_idx;153153+154154+static u8 *g_temp_buf;155155+156156+#pragma pack(push, 1)157157+#pragma pack(1)158158+struct BTableChangesDelta {159159+ u8 ftl_cmd_cnt;160160+ u8 ValidFields;161161+ u16 g_wBlockTableOffset;162162+ u32 g_wBlockTableIndex;163163+ u32 BT_Index;164164+ u32 BT_Entry_Value;165165+ u32 WC_Index;166166+ u8 WC_Entry_Value;167167+ u32 RC_Index;168168+ u16 RC_Entry_Value;169169+};170170+171171+#pragma pack(pop)172172+173173+struct BTableChangesDelta *p_BTableChangesDelta;174174+#endif175175+176176+177177+#define MARK_BLOCK_AS_BAD(blocknode) (blocknode |= BAD_BLOCK)178178+#define MARK_BLK_AS_DISCARD(blk) (blk = (blk & ~SPARE_BLOCK) | DISCARD_BLOCK)179179+180180+#define FTL_Get_LBAPBA_Table_Mem_Size_Bytes() (DeviceInfo.wDataBlockNum *\181181+ sizeof(u32))182182+#define FTL_Get_WearCounter_Table_Mem_Size_Bytes() (DeviceInfo.wDataBlockNum *\183183+ sizeof(u8))184184+#define FTL_Get_ReadCounter_Table_Mem_Size_Bytes() (DeviceInfo.wDataBlockNum *\185185+ sizeof(u16))186186+#if SUPPORT_LARGE_BLOCKNUM187187+#define FTL_Get_LBAPBA_Table_Flash_Size_Bytes() (DeviceInfo.wDataBlockNum *\188188+ sizeof(u8) * 3)189189+#else190190+#define FTL_Get_LBAPBA_Table_Flash_Size_Bytes() (DeviceInfo.wDataBlockNum *\191191+ sizeof(u16))192192+#endif193193+#define FTL_Get_WearCounter_Table_Flash_Size_Bytes \194194+ FTL_Get_WearCounter_Table_Mem_Size_Bytes195195+#define FTL_Get_ReadCounter_Table_Flash_Size_Bytes \196196+ FTL_Get_ReadCounter_Table_Mem_Size_Bytes197197+198198+static u32 FTL_Get_Block_Table_Flash_Size_Bytes(void)199199+{200200+ u32 byte_num;201201+202202+ if (DeviceInfo.MLCDevice) {203203+ byte_num = FTL_Get_LBAPBA_Table_Flash_Size_Bytes() +204204+ DeviceInfo.wDataBlockNum * sizeof(u8) +205205+ DeviceInfo.wDataBlockNum * sizeof(u16);206206+ } else {207207+ byte_num = FTL_Get_LBAPBA_Table_Flash_Size_Bytes() +208208+ DeviceInfo.wDataBlockNum * sizeof(u8);209209+ }210210+211211+ byte_num += 4 * sizeof(u8);212212+213213+ return byte_num;214214+}215215+216216+static u16 FTL_Get_Block_Table_Flash_Size_Pages(void)217217+{218218+ return (u16)FTL_Get_Page_Num(FTL_Get_Block_Table_Flash_Size_Bytes());219219+}220220+221221+static int FTL_Copy_Block_Table_To_Flash(u8 *flashBuf, u32 sizeToTx,222222+ u32 sizeTxed)223223+{224224+ u32 wBytesCopied, blk_tbl_size, wBytes;225225+ u32 *pbt = (u32 *)g_pBlockTable;226226+227227+ blk_tbl_size = FTL_Get_LBAPBA_Table_Flash_Size_Bytes();228228+ for (wBytes = 0;229229+ (wBytes < sizeToTx) && ((wBytes + sizeTxed) < blk_tbl_size);230230+ wBytes++) {231231+#if SUPPORT_LARGE_BLOCKNUM232232+ flashBuf[wBytes] = (u8)(pbt[(wBytes + sizeTxed) / 3]233233+ >> (((wBytes + sizeTxed) % 3) ?234234+ ((((wBytes + sizeTxed) % 3) == 2) ? 0 : 8) : 16)) & 0xFF;235235+#else236236+ flashBuf[wBytes] = (u8)(pbt[(wBytes + sizeTxed) / 2]237237+ >> (((wBytes + sizeTxed) % 2) ? 0 : 8)) & 0xFF;238238+#endif239239+ }240240+241241+ sizeTxed = (sizeTxed > blk_tbl_size) ? (sizeTxed - blk_tbl_size) : 0;242242+ blk_tbl_size = FTL_Get_WearCounter_Table_Flash_Size_Bytes();243243+ wBytesCopied = wBytes;244244+ wBytes = ((blk_tbl_size - sizeTxed) > (sizeToTx - wBytesCopied)) ?245245+ (sizeToTx - wBytesCopied) : (blk_tbl_size - sizeTxed);246246+ memcpy(flashBuf + wBytesCopied, g_pWearCounter + sizeTxed, wBytes);247247+248248+ sizeTxed = (sizeTxed > blk_tbl_size) ? (sizeTxed - blk_tbl_size) : 0;249249+250250+ if (DeviceInfo.MLCDevice) {251251+ blk_tbl_size = FTL_Get_ReadCounter_Table_Flash_Size_Bytes();252252+ wBytesCopied += wBytes;253253+ for (wBytes = 0; ((wBytes + wBytesCopied) < sizeToTx) &&254254+ ((wBytes + sizeTxed) < blk_tbl_size); wBytes++)255255+ flashBuf[wBytes + wBytesCopied] =256256+ (g_pReadCounter[(wBytes + sizeTxed) / 2] >>257257+ (((wBytes + sizeTxed) % 2) ? 0 : 8)) & 0xFF;258258+ }259259+260260+ return wBytesCopied + wBytes;261261+}262262+263263+static int FTL_Copy_Block_Table_From_Flash(u8 *flashBuf,264264+ u32 sizeToTx, u32 sizeTxed)265265+{266266+ u32 wBytesCopied, blk_tbl_size, wBytes;267267+ u32 *pbt = (u32 *)g_pBlockTable;268268+269269+ blk_tbl_size = FTL_Get_LBAPBA_Table_Flash_Size_Bytes();270270+ for (wBytes = 0; (wBytes < sizeToTx) &&271271+ ((wBytes + sizeTxed) < blk_tbl_size); wBytes++) {272272+#if SUPPORT_LARGE_BLOCKNUM273273+ if (!((wBytes + sizeTxed) % 3))274274+ pbt[(wBytes + sizeTxed) / 3] = 0;275275+ pbt[(wBytes + sizeTxed) / 3] |=276276+ (flashBuf[wBytes] << (((wBytes + sizeTxed) % 3) ?277277+ ((((wBytes + sizeTxed) % 3) == 2) ? 0 : 8) : 16));278278+#else279279+ if (!((wBytes + sizeTxed) % 2))280280+ pbt[(wBytes + sizeTxed) / 2] = 0;281281+ pbt[(wBytes + sizeTxed) / 2] |=282282+ (flashBuf[wBytes] << (((wBytes + sizeTxed) % 2) ?283283+ 0 : 8));284284+#endif285285+ }286286+287287+ sizeTxed = (sizeTxed > blk_tbl_size) ? (sizeTxed - blk_tbl_size) : 0;288288+ blk_tbl_size = FTL_Get_WearCounter_Table_Flash_Size_Bytes();289289+ wBytesCopied = wBytes;290290+ wBytes = ((blk_tbl_size - sizeTxed) > (sizeToTx - wBytesCopied)) ?291291+ (sizeToTx - wBytesCopied) : (blk_tbl_size - sizeTxed);292292+ memcpy(g_pWearCounter + sizeTxed, flashBuf + wBytesCopied, wBytes);293293+ sizeTxed = (sizeTxed > blk_tbl_size) ? (sizeTxed - blk_tbl_size) : 0;294294+295295+ if (DeviceInfo.MLCDevice) {296296+ wBytesCopied += wBytes;297297+ blk_tbl_size = FTL_Get_ReadCounter_Table_Flash_Size_Bytes();298298+ for (wBytes = 0; ((wBytes + wBytesCopied) < sizeToTx) &&299299+ ((wBytes + sizeTxed) < blk_tbl_size); wBytes++) {300300+ if (((wBytes + sizeTxed) % 2))301301+ g_pReadCounter[(wBytes + sizeTxed) / 2] = 0;302302+ g_pReadCounter[(wBytes + sizeTxed) / 2] |=303303+ (flashBuf[wBytes] <<304304+ (((wBytes + sizeTxed) % 2) ? 0 : 8));305305+ }306306+ }307307+308308+ return wBytesCopied+wBytes;309309+}310310+311311+static int FTL_Insert_Block_Table_Signature(u8 *buf, u8 tag)312312+{313313+ int i;314314+315315+ for (i = 0; i < BTSIG_BYTES; i++)316316+ buf[BTSIG_OFFSET + i] =317317+ ((tag + (i * BTSIG_DELTA) - FIRST_BT_ID) %318318+ (1 + LAST_BT_ID-FIRST_BT_ID)) + FIRST_BT_ID;319319+320320+ return PASS;321321+}322322+323323+static int FTL_Extract_Block_Table_Tag(u8 *buf, u8 **tagarray)324324+{325325+ static u8 tag[BTSIG_BYTES >> 1];326326+ int i, j, k, tagi, tagtemp, status;327327+328328+ *tagarray = (u8 *)tag;329329+ tagi = 0;330330+331331+ for (i = 0; i < (BTSIG_BYTES - 1); i++) {332332+ for (j = i + 1; (j < BTSIG_BYTES) &&333333+ (tagi < (BTSIG_BYTES >> 1)); j++) {334334+ tagtemp = buf[BTSIG_OFFSET + j] -335335+ buf[BTSIG_OFFSET + i];336336+ if (tagtemp && !(tagtemp % BTSIG_DELTA)) {337337+ tagtemp = (buf[BTSIG_OFFSET + i] +338338+ (1 + LAST_BT_ID - FIRST_BT_ID) -339339+ (i * BTSIG_DELTA)) %340340+ (1 + LAST_BT_ID - FIRST_BT_ID);341341+ status = FAIL;342342+ for (k = 0; k < tagi; k++) {343343+ if (tagtemp == tag[k])344344+ status = PASS;345345+ }346346+347347+ if (status == FAIL) {348348+ tag[tagi++] = tagtemp;349349+ i = (j == (i + 1)) ? i + 1 : i;350350+ j = (j == (i + 1)) ? i + 1 : i;351351+ }352352+ }353353+ }354354+ }355355+356356+ return tagi;357357+}358358+359359+360360+static int FTL_Execute_SPL_Recovery(void)361361+{362362+ u32 j, block, blks;363363+ u32 *pbt = (u32 *)g_pBlockTable;364364+ int ret;365365+366366+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",367367+ __FILE__, __LINE__, __func__);368368+369369+ blks = DeviceInfo.wSpectraEndBlock - DeviceInfo.wSpectraStartBlock;370370+ for (j = 0; j <= blks; j++) {371371+ block = (pbt[j]);372372+ if (((block & BAD_BLOCK) != BAD_BLOCK) &&373373+ ((block & SPARE_BLOCK) == SPARE_BLOCK)) {374374+ ret = GLOB_LLD_Erase_Block(block & ~BAD_BLOCK);375375+ if (FAIL == ret) {376376+ nand_dbg_print(NAND_DBG_WARN,377377+ "NAND Program fail in %s, Line %d, "378378+ "Function: %s, new Bad Block %d "379379+ "generated!\n",380380+ __FILE__, __LINE__, __func__,381381+ (int)(block & ~BAD_BLOCK));382382+ MARK_BLOCK_AS_BAD(pbt[j]);383383+ }384384+ }385385+ }386386+387387+ return PASS;388388+}389389+390390+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&391391+* Function: GLOB_FTL_IdentifyDevice392392+* Inputs: pointer to identify data structure393393+* Outputs: PASS / FAIL394394+* Description: the identify data structure is filled in with395395+* information for the block driver.396396+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/397397+int GLOB_FTL_IdentifyDevice(struct spectra_indentfy_dev_tag *dev_data)398398+{399399+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",400400+ __FILE__, __LINE__, __func__);401401+402402+ dev_data->NumBlocks = DeviceInfo.wTotalBlocks;403403+ dev_data->PagesPerBlock = DeviceInfo.wPagesPerBlock;404404+ dev_data->PageDataSize = DeviceInfo.wPageDataSize;405405+ dev_data->wECCBytesPerSector = DeviceInfo.wECCBytesPerSector;406406+ dev_data->wDataBlockNum = DeviceInfo.wDataBlockNum;407407+408408+ return PASS;409409+}410410+411411+/* ..... */412412+static int allocate_memory(void)413413+{414414+ u32 block_table_size, page_size, block_size, mem_size;415415+ u32 total_bytes = 0;416416+ int i;417417+#if CMD_DMA418418+ int j;419419+#endif420420+421421+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",422422+ __FILE__, __LINE__, __func__);423423+424424+ page_size = DeviceInfo.wPageSize;425425+ block_size = DeviceInfo.wPagesPerBlock * DeviceInfo.wPageDataSize;426426+427427+ block_table_size = DeviceInfo.wDataBlockNum *428428+ (sizeof(u32) + sizeof(u8) + sizeof(u16));429429+ block_table_size += (DeviceInfo.wPageDataSize -430430+ (block_table_size % DeviceInfo.wPageDataSize)) %431431+ DeviceInfo.wPageDataSize;432432+433433+ /* Malloc memory for block tables */434434+ g_pBlockTable = kmalloc(block_table_size, GFP_ATOMIC);435435+ if (!g_pBlockTable)436436+ goto block_table_fail;437437+ memset(g_pBlockTable, 0, block_table_size);438438+ total_bytes += block_table_size;439439+440440+ g_pWearCounter = (u8 *)(g_pBlockTable +441441+ DeviceInfo.wDataBlockNum * sizeof(u32));442442+443443+ if (DeviceInfo.MLCDevice)444444+ g_pReadCounter = (u16 *)(g_pBlockTable +445445+ DeviceInfo.wDataBlockNum *446446+ (sizeof(u32) + sizeof(u8)));447447+448448+ /* Malloc memory and init for cache items */449449+ for (i = 0; i < CACHE_ITEM_NUM; i++) {450450+ Cache.array[i].address = NAND_CACHE_INIT_ADDR;451451+ Cache.array[i].use_cnt = 0;452452+ Cache.array[i].changed = CLEAR;453453+ Cache.array[i].buf = kmalloc(Cache.cache_item_size,454454+ GFP_ATOMIC);455455+ if (!Cache.array[i].buf)456456+ goto cache_item_fail;457457+ memset(Cache.array[i].buf, 0, Cache.cache_item_size);458458+ total_bytes += Cache.cache_item_size;459459+ }460460+461461+ /* Malloc memory for IPF */462462+ g_pIPF = kmalloc(page_size, GFP_ATOMIC);463463+ if (!g_pIPF)464464+ goto ipf_fail;465465+ memset(g_pIPF, 0, page_size);466466+ total_bytes += page_size;467467+468468+ /* Malloc memory for data merging during Level2 Cache flush */469469+ cache_l2_page_buf = kmalloc(page_size, GFP_ATOMIC);470470+ if (!cache_l2_page_buf)471471+ goto cache_l2_page_buf_fail;472472+ memset(cache_l2_page_buf, 0xff, page_size);473473+ total_bytes += page_size;474474+475475+ cache_l2_blk_buf = kmalloc(block_size, GFP_ATOMIC);476476+ if (!cache_l2_blk_buf)477477+ goto cache_l2_blk_buf_fail;478478+ memset(cache_l2_blk_buf, 0xff, block_size);479479+ total_bytes += block_size;480480+481481+ /* Malloc memory for temp buffer */482482+ g_pTempBuf = kmalloc(Cache.cache_item_size, GFP_ATOMIC);483483+ if (!g_pTempBuf)484484+ goto Temp_buf_fail;485485+ memset(g_pTempBuf, 0, Cache.cache_item_size);486486+ total_bytes += Cache.cache_item_size;487487+488488+ /* Malloc memory for block table blocks */489489+ mem_size = (1 + LAST_BT_ID - FIRST_BT_ID) * sizeof(u32);490490+ g_pBTBlocks = kmalloc(mem_size, GFP_ATOMIC);491491+ if (!g_pBTBlocks)492492+ goto bt_blocks_fail;493493+ memset(g_pBTBlocks, 0xff, mem_size);494494+ total_bytes += mem_size;495495+496496+ /* Malloc memory for function FTL_Check_Block_Table */497497+ flag_check_blk_table = kmalloc(DeviceInfo.wDataBlockNum, GFP_ATOMIC);498498+ if (!flag_check_blk_table)499499+ goto flag_check_blk_table_fail;500500+ total_bytes += DeviceInfo.wDataBlockNum;501501+502502+ /* Malloc memory for function FTL_Search_Block_Table_IN_Block */503503+ tmp_buf_search_bt_in_block = kmalloc(page_size, GFP_ATOMIC);504504+ if (!tmp_buf_search_bt_in_block)505505+ goto tmp_buf_search_bt_in_block_fail;506506+ memset(tmp_buf_search_bt_in_block, 0xff, page_size);507507+ total_bytes += page_size;508508+509509+ mem_size = DeviceInfo.wPageSize - DeviceInfo.wPageDataSize;510510+ spare_buf_search_bt_in_block = kmalloc(mem_size, GFP_ATOMIC);511511+ if (!spare_buf_search_bt_in_block)512512+ goto spare_buf_search_bt_in_block_fail;513513+ memset(spare_buf_search_bt_in_block, 0xff, mem_size);514514+ total_bytes += mem_size;515515+516516+ spare_buf_bt_search_bt_in_block = kmalloc(mem_size, GFP_ATOMIC);517517+ if (!spare_buf_bt_search_bt_in_block)518518+ goto spare_buf_bt_search_bt_in_block_fail;519519+ memset(spare_buf_bt_search_bt_in_block, 0xff, mem_size);520520+ total_bytes += mem_size;521521+522522+ /* Malloc memory for function FTL_Read_Block_Table */523523+ tmp_buf1_read_blk_table = kmalloc(page_size, GFP_ATOMIC);524524+ if (!tmp_buf1_read_blk_table)525525+ goto tmp_buf1_read_blk_table_fail;526526+ memset(tmp_buf1_read_blk_table, 0xff, page_size);527527+ total_bytes += page_size;528528+529529+ tmp_buf2_read_blk_table = kmalloc(page_size, GFP_ATOMIC);530530+ if (!tmp_buf2_read_blk_table)531531+ goto tmp_buf2_read_blk_table_fail;532532+ memset(tmp_buf2_read_blk_table, 0xff, page_size);533533+ total_bytes += page_size;534534+535535+ /* Malloc memory for function FTL_Static_Wear_Leveling */536536+ flags_static_wear_leveling = kmalloc(DeviceInfo.wDataBlockNum,537537+ GFP_ATOMIC);538538+ if (!flags_static_wear_leveling)539539+ goto flags_static_wear_leveling_fail;540540+ total_bytes += DeviceInfo.wDataBlockNum;541541+542542+ /* Malloc memory for function FTL_Write_Block_Table_Data */543543+ if (FTL_Get_Block_Table_Flash_Size_Pages() > 3)544544+ mem_size = FTL_Get_Block_Table_Flash_Size_Bytes() -545545+ 2 * DeviceInfo.wPageSize;546546+ else547547+ mem_size = DeviceInfo.wPageSize;548548+ tmp_buf_write_blk_table_data = kmalloc(mem_size, GFP_ATOMIC);549549+ if (!tmp_buf_write_blk_table_data)550550+ goto tmp_buf_write_blk_table_data_fail;551551+ memset(tmp_buf_write_blk_table_data, 0xff, mem_size);552552+ total_bytes += mem_size;553553+554554+ /* Malloc memory for function FTL_Read_Disturbance */555555+ tmp_buf_read_disturbance = kmalloc(block_size, GFP_ATOMIC);556556+ if (!tmp_buf_read_disturbance)557557+ goto tmp_buf_read_disturbance_fail;558558+ memset(tmp_buf_read_disturbance, 0xff, block_size);559559+ total_bytes += block_size;560560+561561+ /* Alloc mem for function NAND_Read_Page_Main_Spare of lld_nand.c */562562+ buf_read_page_main_spare = kmalloc(DeviceInfo.wPageSize, GFP_ATOMIC);563563+ if (!buf_read_page_main_spare)564564+ goto buf_read_page_main_spare_fail;565565+ total_bytes += DeviceInfo.wPageSize;566566+567567+ /* Alloc mem for function NAND_Write_Page_Main_Spare of lld_nand.c */568568+ buf_write_page_main_spare = kmalloc(DeviceInfo.wPageSize, GFP_ATOMIC);569569+ if (!buf_write_page_main_spare)570570+ goto buf_write_page_main_spare_fail;571571+ total_bytes += DeviceInfo.wPageSize;572572+573573+ /* Alloc mem for function NAND_Read_Page_Spare of lld_nand.c */574574+ buf_read_page_spare = kmalloc(DeviceInfo.wPageSpareSize, GFP_ATOMIC);575575+ if (!buf_read_page_spare)576576+ goto buf_read_page_spare_fail;577577+ memset(buf_read_page_spare, 0xff, DeviceInfo.wPageSpareSize);578578+ total_bytes += DeviceInfo.wPageSpareSize;579579+580580+ /* Alloc mem for function NAND_Get_Bad_Block of lld_nand.c */581581+ buf_get_bad_block = kmalloc(DeviceInfo.wPageSpareSize, GFP_ATOMIC);582582+ if (!buf_get_bad_block)583583+ goto buf_get_bad_block_fail;584584+ memset(buf_get_bad_block, 0xff, DeviceInfo.wPageSpareSize);585585+ total_bytes += DeviceInfo.wPageSpareSize;586586+587587+#if CMD_DMA588588+ g_temp_buf = kmalloc(block_size, GFP_ATOMIC);589589+ if (!g_temp_buf)590590+ goto temp_buf_fail;591591+ memset(g_temp_buf, 0xff, block_size);592592+ total_bytes += block_size;593593+594594+ /* Malloc memory for copy of block table used in CDMA mode */595595+ g_pBTStartingCopy = kmalloc(block_table_size, GFP_ATOMIC);596596+ if (!g_pBTStartingCopy)597597+ goto bt_starting_copy;598598+ memset(g_pBTStartingCopy, 0, block_table_size);599599+ total_bytes += block_table_size;600600+601601+ g_pWearCounterCopy = (u8 *)(g_pBTStartingCopy +602602+ DeviceInfo.wDataBlockNum * sizeof(u32));603603+604604+ if (DeviceInfo.MLCDevice)605605+ g_pReadCounterCopy = (u16 *)(g_pBTStartingCopy +606606+ DeviceInfo.wDataBlockNum *607607+ (sizeof(u32) + sizeof(u8)));608608+609609+ /* Malloc memory for block table copies */610610+ mem_size = 5 * DeviceInfo.wDataBlockNum * sizeof(u32) +611611+ 5 * DeviceInfo.wDataBlockNum * sizeof(u8);612612+ if (DeviceInfo.MLCDevice)613613+ mem_size += 5 * DeviceInfo.wDataBlockNum * sizeof(u16);614614+ g_pBlockTableCopies = kmalloc(mem_size, GFP_ATOMIC);615615+ if (!g_pBlockTableCopies)616616+ goto blk_table_copies_fail;617617+ memset(g_pBlockTableCopies, 0, mem_size);618618+ total_bytes += mem_size;619619+ g_pNextBlockTable = g_pBlockTableCopies;620620+621621+ /* Malloc memory for Block Table Delta */622622+ mem_size = MAX_DESCS * sizeof(struct BTableChangesDelta);623623+ g_pBTDelta = kmalloc(mem_size, GFP_ATOMIC);624624+ if (!g_pBTDelta)625625+ goto bt_delta_fail;626626+ memset(g_pBTDelta, 0, mem_size);627627+ total_bytes += mem_size;628628+ g_pBTDelta_Free = g_pBTDelta;629629+630630+ /* Malloc memory for Copy Back Buffers */631631+ for (j = 0; j < COPY_BACK_BUF_NUM; j++) {632632+ cp_back_buf_copies[j] = kmalloc(block_size, GFP_ATOMIC);633633+ if (!cp_back_buf_copies[j])634634+ goto cp_back_buf_copies_fail;635635+ memset(cp_back_buf_copies[j], 0, block_size);636636+ total_bytes += block_size;637637+ }638638+ cp_back_buf_idx = 0;639639+640640+ /* Malloc memory for pending commands list */641641+ mem_size = sizeof(struct pending_cmd) * MAX_DESCS;642642+ info.pcmds = kzalloc(mem_size, GFP_KERNEL);643643+ if (!info.pcmds)644644+ goto pending_cmds_buf_fail;645645+ total_bytes += mem_size;646646+647647+ /* Malloc memory for CDMA descripter table */648648+ mem_size = sizeof(struct cdma_descriptor) * MAX_DESCS;649649+ info.cdma_desc_buf = kzalloc(mem_size, GFP_KERNEL);650650+ if (!info.cdma_desc_buf)651651+ goto cdma_desc_buf_fail;652652+ total_bytes += mem_size;653653+654654+ /* Malloc memory for Memcpy descripter table */655655+ mem_size = sizeof(struct memcpy_descriptor) * MAX_DESCS;656656+ info.memcp_desc_buf = kzalloc(mem_size, GFP_KERNEL);657657+ if (!info.memcp_desc_buf)658658+ goto memcp_desc_buf_fail;659659+ total_bytes += mem_size;660660+#endif661661+662662+ nand_dbg_print(NAND_DBG_WARN,663663+ "Total memory allocated in FTL layer: %d\n", total_bytes);664664+665665+ return PASS;666666+667667+#if CMD_DMA668668+memcp_desc_buf_fail:669669+ kfree(info.cdma_desc_buf);670670+cdma_desc_buf_fail:671671+ kfree(info.pcmds);672672+pending_cmds_buf_fail:673673+cp_back_buf_copies_fail:674674+ j--;675675+ for (; j >= 0; j--)676676+ kfree(cp_back_buf_copies[j]);677677+ kfree(g_pBTDelta);678678+bt_delta_fail:679679+ kfree(g_pBlockTableCopies);680680+blk_table_copies_fail:681681+ kfree(g_pBTStartingCopy);682682+bt_starting_copy:683683+ kfree(g_temp_buf);684684+temp_buf_fail:685685+ kfree(buf_get_bad_block);686686+#endif687687+688688+buf_get_bad_block_fail:689689+ kfree(buf_read_page_spare);690690+buf_read_page_spare_fail:691691+ kfree(buf_write_page_main_spare);692692+buf_write_page_main_spare_fail:693693+ kfree(buf_read_page_main_spare);694694+buf_read_page_main_spare_fail:695695+ kfree(tmp_buf_read_disturbance);696696+tmp_buf_read_disturbance_fail:697697+ kfree(tmp_buf_write_blk_table_data);698698+tmp_buf_write_blk_table_data_fail:699699+ kfree(flags_static_wear_leveling);700700+flags_static_wear_leveling_fail:701701+ kfree(tmp_buf2_read_blk_table);702702+tmp_buf2_read_blk_table_fail:703703+ kfree(tmp_buf1_read_blk_table);704704+tmp_buf1_read_blk_table_fail:705705+ kfree(spare_buf_bt_search_bt_in_block);706706+spare_buf_bt_search_bt_in_block_fail:707707+ kfree(spare_buf_search_bt_in_block);708708+spare_buf_search_bt_in_block_fail:709709+ kfree(tmp_buf_search_bt_in_block);710710+tmp_buf_search_bt_in_block_fail:711711+ kfree(flag_check_blk_table);712712+flag_check_blk_table_fail:713713+ kfree(g_pBTBlocks);714714+bt_blocks_fail:715715+ kfree(g_pTempBuf);716716+Temp_buf_fail:717717+ kfree(cache_l2_blk_buf);718718+cache_l2_blk_buf_fail:719719+ kfree(cache_l2_page_buf);720720+cache_l2_page_buf_fail:721721+ kfree(g_pIPF);722722+ipf_fail:723723+cache_item_fail:724724+ i--;725725+ for (; i >= 0; i--)726726+ kfree(Cache.array[i].buf);727727+ kfree(g_pBlockTable);728728+block_table_fail:729729+ printk(KERN_ERR "Failed to kmalloc memory in %s Line %d.\n",730730+ __FILE__, __LINE__);731731+732732+ return -ENOMEM;733733+}734734+735735+/* .... */736736+static int free_memory(void)737737+{738738+ int i;739739+740740+#if CMD_DMA741741+ kfree(info.memcp_desc_buf);742742+ kfree(info.cdma_desc_buf);743743+ kfree(info.pcmds);744744+ for (i = COPY_BACK_BUF_NUM - 1; i >= 0; i--)745745+ kfree(cp_back_buf_copies[i]);746746+ kfree(g_pBTDelta);747747+ kfree(g_pBlockTableCopies);748748+ kfree(g_pBTStartingCopy);749749+ kfree(g_temp_buf);750750+ kfree(buf_get_bad_block);751751+#endif752752+ kfree(buf_read_page_spare);753753+ kfree(buf_write_page_main_spare);754754+ kfree(buf_read_page_main_spare);755755+ kfree(tmp_buf_read_disturbance);756756+ kfree(tmp_buf_write_blk_table_data);757757+ kfree(flags_static_wear_leveling);758758+ kfree(tmp_buf2_read_blk_table);759759+ kfree(tmp_buf1_read_blk_table);760760+ kfree(spare_buf_bt_search_bt_in_block);761761+ kfree(spare_buf_search_bt_in_block);762762+ kfree(tmp_buf_search_bt_in_block);763763+ kfree(flag_check_blk_table);764764+ kfree(g_pBTBlocks);765765+ kfree(g_pTempBuf);766766+ kfree(g_pIPF);767767+ for (i = CACHE_ITEM_NUM - 1; i >= 0; i--)768768+ kfree(Cache.array[i].buf);769769+ kfree(g_pBlockTable);770770+771771+ return 0;772772+}773773+774774+static void dump_cache_l2_table(void)775775+{776776+ struct list_head *p;777777+ struct spectra_l2_cache_list *pnd;778778+ int n, i;779779+780780+ n = 0;781781+ list_for_each(p, &cache_l2.table.list) {782782+ pnd = list_entry(p, struct spectra_l2_cache_list, list);783783+ nand_dbg_print(NAND_DBG_WARN, "dump_cache_l2_table node: %d, logical_blk_num: %d\n", n, pnd->logical_blk_num);784784+/*785785+ for (i = 0; i < DeviceInfo.wPagesPerBlock; i++) {786786+ if (pnd->pages_array[i] != MAX_U32_VALUE)787787+ nand_dbg_print(NAND_DBG_WARN, " pages_array[%d]: 0x%x\n", i, pnd->pages_array[i]);788788+ }789789+*/790790+ n++;791791+ }792792+}793793+794794+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&795795+* Function: GLOB_FTL_Init796796+* Inputs: none797797+* Outputs: PASS=0 / FAIL=1798798+* Description: allocates the memory for cache array,799799+* important data structures800800+* clears the cache array801801+* reads the block table from flash into array802802+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/803803+int GLOB_FTL_Init(void)804804+{805805+ int i;806806+807807+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",808808+ __FILE__, __LINE__, __func__);809809+810810+ Cache.pages_per_item = 1;811811+ Cache.cache_item_size = 1 * DeviceInfo.wPageDataSize;812812+813813+ if (allocate_memory() != PASS)814814+ return FAIL;815815+816816+#if CMD_DMA817817+#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE818818+ memcpy((void *)&cache_start_copy, (void *)&Cache,819819+ sizeof(struct flash_cache_tag));820820+ memset((void *)&int_cache, -1,821821+ sizeof(struct flash_cache_delta_list_tag) *822822+ (MAX_CHANS + MAX_DESCS));823823+#endif824824+ ftl_cmd_cnt = 0;825825+#endif826826+827827+ if (FTL_Read_Block_Table() != PASS)828828+ return FAIL;829829+830830+ /* Init the Level2 Cache data structure */831831+ for (i = 0; i < BLK_NUM_FOR_L2_CACHE; i++)832832+ cache_l2.blk_array[i] = MAX_U32_VALUE;833833+ cache_l2.cur_blk_idx = 0;834834+ cache_l2.cur_page_num = 0;835835+ INIT_LIST_HEAD(&cache_l2.table.list);836836+ cache_l2.table.logical_blk_num = MAX_U32_VALUE;837837+838838+ dump_cache_l2_table();839839+840840+ return 0;841841+}842842+843843+844844+#if CMD_DMA845845+#if 0846846+static void save_blk_table_changes(u16 idx)847847+{848848+ u8 ftl_cmd;849849+ u32 *pbt = (u32 *)g_pBTStartingCopy;850850+851851+#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE852852+ u16 id;853853+ u8 cache_blks;854854+855855+ id = idx - MAX_CHANS;856856+ if (int_cache[id].item != -1) {857857+ cache_blks = int_cache[id].item;858858+ cache_start_copy.array[cache_blks].address =859859+ int_cache[id].cache.address;860860+ cache_start_copy.array[cache_blks].changed =861861+ int_cache[id].cache.changed;862862+ }863863+#endif864864+865865+ ftl_cmd = p_BTableChangesDelta->ftl_cmd_cnt;866866+867867+ while (ftl_cmd <= PendingCMD[idx].Tag) {868868+ if (p_BTableChangesDelta->ValidFields == 0x01) {869869+ g_wBlockTableOffset =870870+ p_BTableChangesDelta->g_wBlockTableOffset;871871+ } else if (p_BTableChangesDelta->ValidFields == 0x0C) {872872+ pbt[p_BTableChangesDelta->BT_Index] =873873+ p_BTableChangesDelta->BT_Entry_Value;874874+ debug_boundary_error(((875875+ p_BTableChangesDelta->BT_Index)),876876+ DeviceInfo.wDataBlockNum, 0);877877+ } else if (p_BTableChangesDelta->ValidFields == 0x03) {878878+ g_wBlockTableOffset =879879+ p_BTableChangesDelta->g_wBlockTableOffset;880880+ g_wBlockTableIndex =881881+ p_BTableChangesDelta->g_wBlockTableIndex;882882+ } else if (p_BTableChangesDelta->ValidFields == 0x30) {883883+ g_pWearCounterCopy[p_BTableChangesDelta->WC_Index] =884884+ p_BTableChangesDelta->WC_Entry_Value;885885+ } else if ((DeviceInfo.MLCDevice) &&886886+ (p_BTableChangesDelta->ValidFields == 0xC0)) {887887+ g_pReadCounterCopy[p_BTableChangesDelta->RC_Index] =888888+ p_BTableChangesDelta->RC_Entry_Value;889889+ nand_dbg_print(NAND_DBG_DEBUG,890890+ "In event status setting read counter "891891+ "GLOB_ftl_cmd_cnt %u Count %u Index %u\n",892892+ ftl_cmd,893893+ p_BTableChangesDelta->RC_Entry_Value,894894+ (unsigned int)p_BTableChangesDelta->RC_Index);895895+ } else {896896+ nand_dbg_print(NAND_DBG_DEBUG,897897+ "This should never occur \n");898898+ }899899+ p_BTableChangesDelta += 1;900900+ ftl_cmd = p_BTableChangesDelta->ftl_cmd_cnt;901901+ }902902+}903903+904904+static void discard_cmds(u16 n)905905+{906906+ u32 *pbt = (u32 *)g_pBTStartingCopy;907907+ u8 ftl_cmd;908908+ unsigned long k;909909+#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE910910+ u8 cache_blks;911911+ u16 id;912912+#endif913913+914914+ if ((PendingCMD[n].CMD == WRITE_MAIN_CMD) ||915915+ (PendingCMD[n].CMD == WRITE_MAIN_SPARE_CMD)) {916916+ for (k = 0; k < DeviceInfo.wDataBlockNum; k++) {917917+ if (PendingCMD[n].Block == (pbt[k] & (~BAD_BLOCK)))918918+ MARK_BLK_AS_DISCARD(pbt[k]);919919+ }920920+ }921921+922922+ ftl_cmd = p_BTableChangesDelta->ftl_cmd_cnt;923923+ while (ftl_cmd <= PendingCMD[n].Tag) {924924+ p_BTableChangesDelta += 1;925925+ ftl_cmd = p_BTableChangesDelta->ftl_cmd_cnt;926926+ }927927+928928+#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE929929+ id = n - MAX_CHANS;930930+931931+ if (int_cache[id].item != -1) {932932+ cache_blks = int_cache[id].item;933933+ if (PendingCMD[n].CMD == MEMCOPY_CMD) {934934+ if ((cache_start_copy.array[cache_blks].buf <=935935+ PendingCMD[n].DataDestAddr) &&936936+ ((cache_start_copy.array[cache_blks].buf +937937+ Cache.cache_item_size) >938938+ PendingCMD[n].DataDestAddr)) {939939+ cache_start_copy.array[cache_blks].address =940940+ NAND_CACHE_INIT_ADDR;941941+ cache_start_copy.array[cache_blks].use_cnt =942942+ 0;943943+ cache_start_copy.array[cache_blks].changed =944944+ CLEAR;945945+ }946946+ } else {947947+ cache_start_copy.array[cache_blks].address =948948+ int_cache[id].cache.address;949949+ cache_start_copy.array[cache_blks].changed =950950+ int_cache[id].cache.changed;951951+ }952952+ }953953+#endif954954+}955955+956956+static void process_cmd_pass(int *first_failed_cmd, u16 idx)957957+{958958+ if (0 == *first_failed_cmd)959959+ save_blk_table_changes(idx);960960+ else961961+ discard_cmds(idx);962962+}963963+964964+static void process_cmd_fail_abort(int *first_failed_cmd,965965+ u16 idx, int event)966966+{967967+ u32 *pbt = (u32 *)g_pBTStartingCopy;968968+ u8 ftl_cmd;969969+ unsigned long i;970970+ int erase_fail, program_fail;971971+#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE972972+ u8 cache_blks;973973+ u16 id;974974+#endif975975+976976+ if (0 == *first_failed_cmd)977977+ *first_failed_cmd = PendingCMD[idx].SBDCmdIndex;978978+979979+ nand_dbg_print(NAND_DBG_DEBUG, "Uncorrectable error has occured "980980+ "while executing %u Command %u accesing Block %u\n",981981+ (unsigned int)p_BTableChangesDelta->ftl_cmd_cnt,982982+ PendingCMD[idx].CMD,983983+ (unsigned int)PendingCMD[idx].Block);984984+985985+ ftl_cmd = p_BTableChangesDelta->ftl_cmd_cnt;986986+ while (ftl_cmd <= PendingCMD[idx].Tag) {987987+ p_BTableChangesDelta += 1;988988+ ftl_cmd = p_BTableChangesDelta->ftl_cmd_cnt;989989+ }990990+991991+#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE992992+ id = idx - MAX_CHANS;993993+994994+ if (int_cache[id].item != -1) {995995+ cache_blks = int_cache[id].item;996996+ if ((PendingCMD[idx].CMD == WRITE_MAIN_CMD)) {997997+ cache_start_copy.array[cache_blks].address =998998+ int_cache[id].cache.address;999999+ cache_start_copy.array[cache_blks].changed = SET;10001000+ } else if ((PendingCMD[idx].CMD == READ_MAIN_CMD)) {10011001+ cache_start_copy.array[cache_blks].address =10021002+ NAND_CACHE_INIT_ADDR;10031003+ cache_start_copy.array[cache_blks].use_cnt = 0;10041004+ cache_start_copy.array[cache_blks].changed =10051005+ CLEAR;10061006+ } else if (PendingCMD[idx].CMD == ERASE_CMD) {10071007+ /* ? */10081008+ } else if (PendingCMD[idx].CMD == MEMCOPY_CMD) {10091009+ /* ? */10101010+ }10111011+ }10121012+#endif10131013+10141014+ erase_fail = (event == EVENT_ERASE_FAILURE) &&10151015+ (PendingCMD[idx].CMD == ERASE_CMD);10161016+10171017+ program_fail = (event == EVENT_PROGRAM_FAILURE) &&10181018+ ((PendingCMD[idx].CMD == WRITE_MAIN_CMD) ||10191019+ (PendingCMD[idx].CMD == WRITE_MAIN_SPARE_CMD));10201020+10211021+ if (erase_fail || program_fail) {10221022+ for (i = 0; i < DeviceInfo.wDataBlockNum; i++) {10231023+ if (PendingCMD[idx].Block ==10241024+ (pbt[i] & (~BAD_BLOCK)))10251025+ MARK_BLOCK_AS_BAD(pbt[i]);10261026+ }10271027+ }10281028+}10291029+10301030+static void process_cmd(int *first_failed_cmd, u16 idx, int event)10311031+{10321032+ u8 ftl_cmd;10331033+ int cmd_match = 0;10341034+10351035+ if (p_BTableChangesDelta->ftl_cmd_cnt == PendingCMD[idx].Tag)10361036+ cmd_match = 1;10371037+10381038+ if (PendingCMD[idx].Status == CMD_PASS) {10391039+ process_cmd_pass(first_failed_cmd, idx);10401040+ } else if ((PendingCMD[idx].Status == CMD_FAIL) ||10411041+ (PendingCMD[idx].Status == CMD_ABORT)) {10421042+ process_cmd_fail_abort(first_failed_cmd, idx, event);10431043+ } else if ((PendingCMD[idx].Status == CMD_NOT_DONE) &&10441044+ PendingCMD[idx].Tag) {10451045+ nand_dbg_print(NAND_DBG_DEBUG,10461046+ " Command no. %hu is not executed\n",10471047+ (unsigned int)PendingCMD[idx].Tag);10481048+ ftl_cmd = p_BTableChangesDelta->ftl_cmd_cnt;10491049+ while (ftl_cmd <= PendingCMD[idx].Tag) {10501050+ p_BTableChangesDelta += 1;10511051+ ftl_cmd = p_BTableChangesDelta->ftl_cmd_cnt;10521052+ }10531053+ }10541054+}10551055+#endif10561056+10571057+static void process_cmd(int *first_failed_cmd, u16 idx, int event)10581058+{10591059+ printk(KERN_ERR "temporary workaround function. "10601060+ "Should not be called! \n");10611061+}10621062+10631063+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&10641064+* Function: GLOB_FTL_Event_Status10651065+* Inputs: none10661066+* Outputs: Event Code10671067+* Description: It is called by SBD after hardware interrupt signalling10681068+* completion of commands chain10691069+* It does following things10701070+* get event status from LLD10711071+* analyze command chain status10721072+* determine last command executed10731073+* analyze results10741074+* rebuild the block table in case of uncorrectable error10751075+* return event code10761076+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/10771077+int GLOB_FTL_Event_Status(int *first_failed_cmd)10781078+{10791079+ int event_code = PASS;10801080+ u16 i_P;10811081+10821082+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",10831083+ __FILE__, __LINE__, __func__);10841084+10851085+ *first_failed_cmd = 0;10861086+10871087+ event_code = GLOB_LLD_Event_Status();10881088+10891089+ switch (event_code) {10901090+ case EVENT_PASS:10911091+ nand_dbg_print(NAND_DBG_DEBUG, "Handling EVENT_PASS\n");10921092+ break;10931093+ case EVENT_UNCORRECTABLE_DATA_ERROR:10941094+ nand_dbg_print(NAND_DBG_DEBUG, "Handling Uncorrectable ECC!\n");10951095+ break;10961096+ case EVENT_PROGRAM_FAILURE:10971097+ case EVENT_ERASE_FAILURE:10981098+ nand_dbg_print(NAND_DBG_WARN, "Handling Ugly case. "10991099+ "Event code: 0x%x\n", event_code);11001100+ p_BTableChangesDelta =11011101+ (struct BTableChangesDelta *)g_pBTDelta;11021102+ for (i_P = MAX_CHANS; i_P < (ftl_cmd_cnt + MAX_CHANS);11031103+ i_P++)11041104+ process_cmd(first_failed_cmd, i_P, event_code);11051105+ memcpy(g_pBlockTable, g_pBTStartingCopy,11061106+ DeviceInfo.wDataBlockNum * sizeof(u32));11071107+ memcpy(g_pWearCounter, g_pWearCounterCopy,11081108+ DeviceInfo.wDataBlockNum * sizeof(u8));11091109+ if (DeviceInfo.MLCDevice)11101110+ memcpy(g_pReadCounter, g_pReadCounterCopy,11111111+ DeviceInfo.wDataBlockNum * sizeof(u16));11121112+11131113+#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE11141114+ memcpy((void *)&Cache, (void *)&cache_start_copy,11151115+ sizeof(struct flash_cache_tag));11161116+ memset((void *)&int_cache, -1,11171117+ sizeof(struct flash_cache_delta_list_tag) *11181118+ (MAX_DESCS + MAX_CHANS));11191119+#endif11201120+ break;11211121+ default:11221122+ nand_dbg_print(NAND_DBG_WARN,11231123+ "Handling unexpected event code - 0x%x\n",11241124+ event_code);11251125+ event_code = ERR;11261126+ break;11271127+ }11281128+11291129+ memcpy(g_pBTStartingCopy, g_pBlockTable,11301130+ DeviceInfo.wDataBlockNum * sizeof(u32));11311131+ memcpy(g_pWearCounterCopy, g_pWearCounter,11321132+ DeviceInfo.wDataBlockNum * sizeof(u8));11331133+ if (DeviceInfo.MLCDevice)11341134+ memcpy(g_pReadCounterCopy, g_pReadCounter,11351135+ DeviceInfo.wDataBlockNum * sizeof(u16));11361136+11371137+ g_pBTDelta_Free = g_pBTDelta;11381138+ ftl_cmd_cnt = 0;11391139+ g_pNextBlockTable = g_pBlockTableCopies;11401140+ cp_back_buf_idx = 0;11411141+11421142+#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE11431143+ memcpy((void *)&cache_start_copy, (void *)&Cache,11441144+ sizeof(struct flash_cache_tag));11451145+ memset((void *)&int_cache, -1,11461146+ sizeof(struct flash_cache_delta_list_tag) *11471147+ (MAX_DESCS + MAX_CHANS));11481148+#endif11491149+11501150+ return event_code;11511151+}11521152+11531153+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&11541154+* Function: glob_ftl_execute_cmds11551155+* Inputs: none11561156+* Outputs: none11571157+* Description: pass thru to LLD11581158+***************************************************************/11591159+u16 glob_ftl_execute_cmds(void)11601160+{11611161+ nand_dbg_print(NAND_DBG_TRACE,11621162+ "glob_ftl_execute_cmds: ftl_cmd_cnt %u\n",11631163+ (unsigned int)ftl_cmd_cnt);11641164+ g_SBDCmdIndex = 0;11651165+ return glob_lld_execute_cmds();11661166+}11671167+11681168+#endif11691169+11701170+#if !CMD_DMA11711171+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&11721172+* Function: GLOB_FTL_Read Immediate11731173+* Inputs: pointer to data11741174+* address of data11751175+* Outputs: PASS / FAIL11761176+* Description: Reads one page of data into RAM directly from flash without11771177+* using or disturbing cache.It is assumed this function is called11781178+* with CMD-DMA disabled.11791179+*****************************************************************/11801180+int GLOB_FTL_Read_Immediate(u8 *read_data, u64 addr)11811181+{11821182+ int wResult = FAIL;11831183+ u32 Block;11841184+ u16 Page;11851185+ u32 phy_blk;11861186+ u32 *pbt = (u32 *)g_pBlockTable;11871187+11881188+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",11891189+ __FILE__, __LINE__, __func__);11901190+11911191+ Block = BLK_FROM_ADDR(addr);11921192+ Page = PAGE_FROM_ADDR(addr, Block);11931193+11941194+ if (!IS_SPARE_BLOCK(Block))11951195+ return FAIL;11961196+11971197+ phy_blk = pbt[Block];11981198+ wResult = GLOB_LLD_Read_Page_Main(read_data, phy_blk, Page, 1);11991199+12001200+ if (DeviceInfo.MLCDevice) {12011201+ g_pReadCounter[phy_blk - DeviceInfo.wSpectraStartBlock]++;12021202+ if (g_pReadCounter[phy_blk - DeviceInfo.wSpectraStartBlock]12031203+ >= MAX_READ_COUNTER)12041204+ FTL_Read_Disturbance(phy_blk);12051205+ if (g_cBlockTableStatus != IN_PROGRESS_BLOCK_TABLE) {12061206+ g_cBlockTableStatus = IN_PROGRESS_BLOCK_TABLE;12071207+ FTL_Write_IN_Progress_Block_Table_Page();12081208+ }12091209+ }12101210+12111211+ return wResult;12121212+}12131213+#endif12141214+12151215+#ifdef SUPPORT_BIG_ENDIAN12161216+/*********************************************************************12171217+* Function: FTL_Invert_Block_Table12181218+* Inputs: none12191219+* Outputs: none12201220+* Description: Re-format the block table in ram based on BIG_ENDIAN and12211221+* LARGE_BLOCKNUM if necessary12221222+**********************************************************************/12231223+static void FTL_Invert_Block_Table(void)12241224+{12251225+ u32 i;12261226+ u32 *pbt = (u32 *)g_pBlockTable;12271227+12281228+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",12291229+ __FILE__, __LINE__, __func__);12301230+12311231+#ifdef SUPPORT_LARGE_BLOCKNUM12321232+ for (i = 0; i < DeviceInfo.wDataBlockNum; i++) {12331233+ pbt[i] = INVERTUINT32(pbt[i]);12341234+ g_pWearCounter[i] = INVERTUINT32(g_pWearCounter[i]);12351235+ }12361236+#else12371237+ for (i = 0; i < DeviceInfo.wDataBlockNum; i++) {12381238+ pbt[i] = INVERTUINT16(pbt[i]);12391239+ g_pWearCounter[i] = INVERTUINT16(g_pWearCounter[i]);12401240+ }12411241+#endif12421242+}12431243+#endif12441244+12451245+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&12461246+* Function: GLOB_FTL_Flash_Init12471247+* Inputs: none12481248+* Outputs: PASS=0 / FAIL=0x01 (based on read ID)12491249+* Description: The flash controller is initialized12501250+* The flash device is reset12511251+* Perform a flash READ ID command to confirm that a12521252+* valid device is attached and active.12531253+* The DeviceInfo structure gets filled in12541254+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/12551255+int GLOB_FTL_Flash_Init(void)12561256+{12571257+ int status = FAIL;12581258+12591259+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",12601260+ __FILE__, __LINE__, __func__);12611261+12621262+ g_SBDCmdIndex = 0;12631263+12641264+ GLOB_LLD_Flash_Init();12651265+12661266+ status = GLOB_LLD_Read_Device_ID();12671267+12681268+ return status;12691269+}12701270+12711271+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&12721272+* Inputs: none12731273+* Outputs: PASS=0 / FAIL=0x01 (based on read ID)12741274+* Description: The flash controller is released12751275+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/12761276+int GLOB_FTL_Flash_Release(void)12771277+{12781278+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",12791279+ __FILE__, __LINE__, __func__);12801280+12811281+ return GLOB_LLD_Flash_Release();12821282+}12831283+12841284+12851285+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&12861286+* Function: GLOB_FTL_Cache_Release12871287+* Inputs: none12881288+* Outputs: none12891289+* Description: release all allocated memory in GLOB_FTL_Init12901290+* (allocated in GLOB_FTL_Init)12911291+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/12921292+void GLOB_FTL_Cache_Release(void)12931293+{12941294+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",12951295+ __FILE__, __LINE__, __func__);12961296+12971297+ free_memory();12981298+}12991299+13001300+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&13011301+* Function: FTL_Cache_If_Hit13021302+* Inputs: Page Address13031303+* Outputs: Block number/UNHIT BLOCK13041304+* Description: Determines if the addressed page is in cache13051305+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/13061306+static u16 FTL_Cache_If_Hit(u64 page_addr)13071307+{13081308+ u16 item;13091309+ u64 addr;13101310+ int i;13111311+13121312+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",13131313+ __FILE__, __LINE__, __func__);13141314+13151315+ item = UNHIT_CACHE_ITEM;13161316+ for (i = 0; i < CACHE_ITEM_NUM; i++) {13171317+ addr = Cache.array[i].address;13181318+ if ((page_addr >= addr) &&13191319+ (page_addr < (addr + Cache.cache_item_size))) {13201320+ item = i;13211321+ break;13221322+ }13231323+ }13241324+13251325+ return item;13261326+}13271327+13281328+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&13291329+* Function: FTL_Calculate_LRU13301330+* Inputs: None13311331+* Outputs: None13321332+* Description: Calculate the least recently block in a cache and record its13331333+* index in LRU field.13341334+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/13351335+static void FTL_Calculate_LRU(void)13361336+{13371337+ u16 i, bCurrentLRU, bTempCount;13381338+13391339+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",13401340+ __FILE__, __LINE__, __func__);13411341+13421342+ bCurrentLRU = 0;13431343+ bTempCount = MAX_WORD_VALUE;13441344+13451345+ for (i = 0; i < CACHE_ITEM_NUM; i++) {13461346+ if (Cache.array[i].use_cnt < bTempCount) {13471347+ bCurrentLRU = i;13481348+ bTempCount = Cache.array[i].use_cnt;13491349+ }13501350+ }13511351+13521352+ Cache.LRU = bCurrentLRU;13531353+}13541354+13551355+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&13561356+* Function: FTL_Cache_Read_Page13571357+* Inputs: pointer to read buffer, logical address and cache item number13581358+* Outputs: None13591359+* Description: Read the page from the cached block addressed by blocknumber13601360+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/13611361+static void FTL_Cache_Read_Page(u8 *data_buf, u64 logic_addr, u16 cache_item)13621362+{13631363+ u8 *start_addr;13641364+13651365+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",13661366+ __FILE__, __LINE__, __func__);13671367+13681368+ start_addr = Cache.array[cache_item].buf;13691369+ start_addr += (u32)(((logic_addr - Cache.array[cache_item].address) >>13701370+ DeviceInfo.nBitsInPageDataSize) * DeviceInfo.wPageDataSize);13711371+13721372+#if CMD_DMA13731373+ GLOB_LLD_MemCopy_CMD(data_buf, start_addr,13741374+ DeviceInfo.wPageDataSize, 0);13751375+ ftl_cmd_cnt++;13761376+#else13771377+ memcpy(data_buf, start_addr, DeviceInfo.wPageDataSize);13781378+#endif13791379+13801380+ if (Cache.array[cache_item].use_cnt < MAX_WORD_VALUE)13811381+ Cache.array[cache_item].use_cnt++;13821382+}13831383+13841384+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&13851385+* Function: FTL_Cache_Read_All13861386+* Inputs: pointer to read buffer,block address13871387+* Outputs: PASS=0 / FAIL =113881388+* Description: It reads pages in cache13891389+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/13901390+static int FTL_Cache_Read_All(u8 *pData, u64 phy_addr)13911391+{13921392+ int wResult = PASS;13931393+ u32 Block;13941394+ u32 lba;13951395+ u16 Page;13961396+ u16 PageCount;13971397+ u32 *pbt = (u32 *)g_pBlockTable;13981398+ u32 i;13991399+14001400+ Block = BLK_FROM_ADDR(phy_addr);14011401+ Page = PAGE_FROM_ADDR(phy_addr, Block);14021402+ PageCount = Cache.pages_per_item;14031403+14041404+ nand_dbg_print(NAND_DBG_DEBUG,14051405+ "%s, Line %d, Function: %s, Block: 0x%x\n",14061406+ __FILE__, __LINE__, __func__, Block);14071407+14081408+ lba = 0xffffffff;14091409+ for (i = 0; i < DeviceInfo.wDataBlockNum; i++) {14101410+ if ((pbt[i] & (~BAD_BLOCK)) == Block) {14111411+ lba = i;14121412+ if (IS_SPARE_BLOCK(i) || IS_BAD_BLOCK(i) ||14131413+ IS_DISCARDED_BLOCK(i)) {14141414+ /* Add by yunpeng -2008.12.3 */14151415+#if CMD_DMA14161416+ GLOB_LLD_MemCopy_CMD(pData, g_temp_buf,14171417+ PageCount * DeviceInfo.wPageDataSize, 0);14181418+ ftl_cmd_cnt++;14191419+#else14201420+ memset(pData, 0xFF,14211421+ PageCount * DeviceInfo.wPageDataSize);14221422+#endif14231423+ return wResult;14241424+ } else {14251425+ continue; /* break ?? */14261426+ }14271427+ }14281428+ }14291429+14301430+ if (0xffffffff == lba)14311431+ printk(KERN_ERR "FTL_Cache_Read_All: Block is not found in BT\n");14321432+14331433+#if CMD_DMA14341434+ wResult = GLOB_LLD_Read_Page_Main_cdma(pData, Block, Page,14351435+ PageCount, LLD_CMD_FLAG_MODE_CDMA);14361436+ if (DeviceInfo.MLCDevice) {14371437+ g_pReadCounter[Block - DeviceInfo.wSpectraStartBlock]++;14381438+ nand_dbg_print(NAND_DBG_DEBUG,14391439+ "Read Counter modified in ftl_cmd_cnt %u"14401440+ " Block %u Counter%u\n",14411441+ ftl_cmd_cnt, (unsigned int)Block,14421442+ g_pReadCounter[Block -14431443+ DeviceInfo.wSpectraStartBlock]);14441444+14451445+ p_BTableChangesDelta =14461446+ (struct BTableChangesDelta *)g_pBTDelta_Free;14471447+ g_pBTDelta_Free += sizeof(struct BTableChangesDelta);14481448+ p_BTableChangesDelta->ftl_cmd_cnt = ftl_cmd_cnt;14491449+ p_BTableChangesDelta->RC_Index =14501450+ Block - DeviceInfo.wSpectraStartBlock;14511451+ p_BTableChangesDelta->RC_Entry_Value =14521452+ g_pReadCounter[Block - DeviceInfo.wSpectraStartBlock];14531453+ p_BTableChangesDelta->ValidFields = 0xC0;14541454+14551455+ ftl_cmd_cnt++;14561456+14571457+ if (g_pReadCounter[Block - DeviceInfo.wSpectraStartBlock] >=14581458+ MAX_READ_COUNTER)14591459+ FTL_Read_Disturbance(Block);14601460+ if (g_cBlockTableStatus != IN_PROGRESS_BLOCK_TABLE) {14611461+ g_cBlockTableStatus = IN_PROGRESS_BLOCK_TABLE;14621462+ FTL_Write_IN_Progress_Block_Table_Page();14631463+ }14641464+ } else {14651465+ ftl_cmd_cnt++;14661466+ }14671467+#else14681468+ wResult = GLOB_LLD_Read_Page_Main(pData, Block, Page, PageCount);14691469+ if (wResult == FAIL)14701470+ return wResult;14711471+14721472+ if (DeviceInfo.MLCDevice) {14731473+ g_pReadCounter[Block - DeviceInfo.wSpectraStartBlock]++;14741474+ if (g_pReadCounter[Block - DeviceInfo.wSpectraStartBlock] >=14751475+ MAX_READ_COUNTER)14761476+ FTL_Read_Disturbance(Block);14771477+ if (g_cBlockTableStatus != IN_PROGRESS_BLOCK_TABLE) {14781478+ g_cBlockTableStatus = IN_PROGRESS_BLOCK_TABLE;14791479+ FTL_Write_IN_Progress_Block_Table_Page();14801480+ }14811481+ }14821482+#endif14831483+ return wResult;14841484+}14851485+14861486+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&14871487+* Function: FTL_Cache_Write_All14881488+* Inputs: pointer to cache in sys memory14891489+* address of free block in flash14901490+* Outputs: PASS=0 / FAIL=114911491+* Description: writes all the pages of the block in cache to flash14921492+*14931493+* NOTE:need to make sure this works ok when cache is limited14941494+* to a partial block. This is where copy-back would be14951495+* activated. This would require knowing which pages in the14961496+* cached block are clean/dirty.Right now we only know if14971497+* the whole block is clean/dirty.14981498+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/14991499+static int FTL_Cache_Write_All(u8 *pData, u64 blk_addr)15001500+{15011501+ u16 wResult = PASS;15021502+ u32 Block;15031503+ u16 Page;15041504+ u16 PageCount;15051505+15061506+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",15071507+ __FILE__, __LINE__, __func__);15081508+15091509+ nand_dbg_print(NAND_DBG_DEBUG, "This block %d going to be written "15101510+ "on %d\n", cache_block_to_write,15111511+ (u32)(blk_addr >> DeviceInfo.nBitsInBlockDataSize));15121512+15131513+ Block = BLK_FROM_ADDR(blk_addr);15141514+ Page = PAGE_FROM_ADDR(blk_addr, Block);15151515+ PageCount = Cache.pages_per_item;15161516+15171517+#if CMD_DMA15181518+ if (FAIL == GLOB_LLD_Write_Page_Main_cdma(pData,15191519+ Block, Page, PageCount)) {15201520+ nand_dbg_print(NAND_DBG_WARN,15211521+ "NAND Program fail in %s, Line %d, "15221522+ "Function: %s, new Bad Block %d generated! "15231523+ "Need Bad Block replacing.\n",15241524+ __FILE__, __LINE__, __func__, Block);15251525+ wResult = FAIL;15261526+ }15271527+ ftl_cmd_cnt++;15281528+#else15291529+ if (FAIL == GLOB_LLD_Write_Page_Main(pData, Block, Page, PageCount)) {15301530+ nand_dbg_print(NAND_DBG_WARN, "NAND Program fail in %s,"15311531+ " Line %d, Function %s, new Bad Block %d generated!"15321532+ "Need Bad Block replacing.\n",15331533+ __FILE__, __LINE__, __func__, Block);15341534+ wResult = FAIL;15351535+ }15361536+#endif15371537+ return wResult;15381538+}15391539+15401540+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&15411541+* Function: FTL_Cache_Update_Block15421542+* Inputs: pointer to buffer,page address,block address15431543+* Outputs: PASS=0 / FAIL=115441544+* Description: It updates the cache15451545+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/15461546+static int FTL_Cache_Update_Block(u8 *pData,15471547+ u64 old_page_addr, u64 blk_addr)15481548+{15491549+ int i, j;15501550+ u8 *buf = pData;15511551+ int wResult = PASS;15521552+ int wFoundInCache;15531553+ u64 page_addr;15541554+ u64 addr;15551555+ u64 old_blk_addr;15561556+ u16 page_offset;15571557+15581558+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",15591559+ __FILE__, __LINE__, __func__);15601560+15611561+ old_blk_addr = (u64)(old_page_addr >>15621562+ DeviceInfo.nBitsInBlockDataSize) * DeviceInfo.wBlockDataSize;15631563+ page_offset = (u16)(GLOB_u64_Remainder(old_page_addr, 2) >>15641564+ DeviceInfo.nBitsInPageDataSize);15651565+15661566+ for (i = 0; i < DeviceInfo.wPagesPerBlock; i += Cache.pages_per_item) {15671567+ page_addr = old_blk_addr + i * DeviceInfo.wPageDataSize;15681568+ if (i != page_offset) {15691569+ wFoundInCache = FAIL;15701570+ for (j = 0; j < CACHE_ITEM_NUM; j++) {15711571+ addr = Cache.array[j].address;15721572+ addr = FTL_Get_Physical_Block_Addr(addr) +15731573+ GLOB_u64_Remainder(addr, 2);15741574+ if ((addr >= page_addr) && addr <15751575+ (page_addr + Cache.cache_item_size)) {15761576+ wFoundInCache = PASS;15771577+ buf = Cache.array[j].buf;15781578+ Cache.array[j].changed = SET;15791579+#if CMD_DMA15801580+#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE15811581+ int_cache[ftl_cmd_cnt].item = j;15821582+ int_cache[ftl_cmd_cnt].cache.address =15831583+ Cache.array[j].address;15841584+ int_cache[ftl_cmd_cnt].cache.changed =15851585+ Cache.array[j].changed;15861586+#endif15871587+#endif15881588+ break;15891589+ }15901590+ }15911591+ if (FAIL == wFoundInCache) {15921592+ if (ERR == FTL_Cache_Read_All(g_pTempBuf,15931593+ page_addr)) {15941594+ wResult = FAIL;15951595+ break;15961596+ }15971597+ buf = g_pTempBuf;15981598+ }15991599+ } else {16001600+ buf = pData;16011601+ }16021602+16031603+ if (FAIL == FTL_Cache_Write_All(buf,16041604+ blk_addr + (page_addr - old_blk_addr))) {16051605+ wResult = FAIL;16061606+ break;16071607+ }16081608+ }16091609+16101610+ return wResult;16111611+}16121612+16131613+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&16141614+* Function: FTL_Copy_Block16151615+* Inputs: source block address16161616+* Destination block address16171617+* Outputs: PASS=0 / FAIL=116181618+* Description: used only for static wear leveling to move the block16191619+* containing static data to new blocks(more worn)16201620+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/16211621+int FTL_Copy_Block(u64 old_blk_addr, u64 blk_addr)16221622+{16231623+ int i, r1, r2, wResult = PASS;16241624+16251625+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",16261626+ __FILE__, __LINE__, __func__);16271627+16281628+ for (i = 0; i < DeviceInfo.wPagesPerBlock; i += Cache.pages_per_item) {16291629+ r1 = FTL_Cache_Read_All(g_pTempBuf, old_blk_addr +16301630+ i * DeviceInfo.wPageDataSize);16311631+ r2 = FTL_Cache_Write_All(g_pTempBuf, blk_addr +16321632+ i * DeviceInfo.wPageDataSize);16331633+ if ((ERR == r1) || (FAIL == r2)) {16341634+ wResult = FAIL;16351635+ break;16361636+ }16371637+ }16381638+16391639+ return wResult;16401640+}16411641+16421642+/* Search the block table to find out the least wear block and then return it */16431643+static u32 find_least_worn_blk_for_l2_cache(void)16441644+{16451645+ int i;16461646+ u32 *pbt = (u32 *)g_pBlockTable;16471647+ u8 least_wear_cnt = MAX_BYTE_VALUE;16481648+ u32 least_wear_blk_idx = MAX_U32_VALUE;16491649+ u32 phy_idx;16501650+16511651+ for (i = 0; i < DeviceInfo.wDataBlockNum; i++) {16521652+ if (IS_SPARE_BLOCK(i)) {16531653+ phy_idx = (u32)((~BAD_BLOCK) & pbt[i]);16541654+ if (phy_idx > DeviceInfo.wSpectraEndBlock)16551655+ printk(KERN_ERR "find_least_worn_blk_for_l2_cache: "16561656+ "Too big phy block num (%d)\n", phy_idx);16571657+ if (g_pWearCounter[phy_idx -DeviceInfo.wSpectraStartBlock] < least_wear_cnt) {16581658+ least_wear_cnt = g_pWearCounter[phy_idx - DeviceInfo.wSpectraStartBlock];16591659+ least_wear_blk_idx = i;16601660+ }16611661+ }16621662+ }16631663+16641664+ nand_dbg_print(NAND_DBG_WARN,16651665+ "find_least_worn_blk_for_l2_cache: "16661666+ "find block %d with least worn counter (%d)\n",16671667+ least_wear_blk_idx, least_wear_cnt);16681668+16691669+ return least_wear_blk_idx;16701670+}16711671+16721672+16731673+16741674+/* Get blocks for Level2 Cache */16751675+static int get_l2_cache_blks(void)16761676+{16771677+ int n;16781678+ u32 blk;16791679+ u32 *pbt = (u32 *)g_pBlockTable;16801680+16811681+ for (n = 0; n < BLK_NUM_FOR_L2_CACHE; n++) {16821682+ blk = find_least_worn_blk_for_l2_cache();16831683+ if (blk > DeviceInfo.wDataBlockNum) {16841684+ nand_dbg_print(NAND_DBG_WARN,16851685+ "find_least_worn_blk_for_l2_cache: "16861686+ "No enough free NAND blocks (n: %d) for L2 Cache!\n", n);16871687+ return FAIL;16881688+ }16891689+ /* Tag the free block as discard in block table */16901690+ pbt[blk] = (pbt[blk] & (~BAD_BLOCK)) | DISCARD_BLOCK;16911691+ /* Add the free block to the L2 Cache block array */16921692+ cache_l2.blk_array[n] = pbt[blk] & (~BAD_BLOCK);16931693+ }16941694+16951695+ return PASS;16961696+}16971697+16981698+static int erase_l2_cache_blocks(void)16991699+{17001700+ int i, ret = PASS;17011701+ u32 pblk, lblk;17021702+ u64 addr;17031703+ u32 *pbt = (u32 *)g_pBlockTable;17041704+17051705+ nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n",17061706+ __FILE__, __LINE__, __func__);17071707+17081708+ for (i = 0; i < BLK_NUM_FOR_L2_CACHE; i++) {17091709+ pblk = cache_l2.blk_array[i];17101710+17111711+ /* If the L2 cache block is invalid, then just skip it */17121712+ if (MAX_U32_VALUE == pblk)17131713+ continue;17141714+17151715+ BUG_ON(pblk > DeviceInfo.wSpectraEndBlock);17161716+17171717+ addr = (u64)pblk << DeviceInfo.nBitsInBlockDataSize;17181718+ if (PASS == GLOB_FTL_Block_Erase(addr)) {17191719+ /* Get logical block number of the erased block */17201720+ lblk = FTL_Get_Block_Index(pblk);17211721+ BUG_ON(BAD_BLOCK == lblk);17221722+ /* Tag it as free in the block table */17231723+ pbt[lblk] &= (u32)(~DISCARD_BLOCK);17241724+ pbt[lblk] |= (u32)(SPARE_BLOCK);17251725+ } else {17261726+ MARK_BLOCK_AS_BAD(pbt[lblk]);17271727+ ret = ERR;17281728+ }17291729+ }17301730+17311731+ return ret;17321732+}17331733+17341734+/*17351735+ * Merge the valid data page in the L2 cache blocks into NAND.17361736+*/17371737+static int flush_l2_cache(void)17381738+{17391739+ struct list_head *p;17401740+ struct spectra_l2_cache_list *pnd, *tmp_pnd;17411741+ u32 *pbt = (u32 *)g_pBlockTable;17421742+ u32 phy_blk, l2_blk;17431743+ u64 addr;17441744+ u16 l2_page;17451745+ int i, ret = PASS;17461746+17471747+ nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n",17481748+ __FILE__, __LINE__, __func__);17491749+17501750+ if (list_empty(&cache_l2.table.list)) /* No data to flush */17511751+ return ret;17521752+17531753+ //dump_cache_l2_table();17541754+17551755+ if (IN_PROGRESS_BLOCK_TABLE != g_cBlockTableStatus) {17561756+ g_cBlockTableStatus = IN_PROGRESS_BLOCK_TABLE;17571757+ FTL_Write_IN_Progress_Block_Table_Page();17581758+ }17591759+17601760+ list_for_each(p, &cache_l2.table.list) {17611761+ pnd = list_entry(p, struct spectra_l2_cache_list, list);17621762+ if (IS_SPARE_BLOCK(pnd->logical_blk_num) ||17631763+ IS_BAD_BLOCK(pnd->logical_blk_num) ||17641764+ IS_DISCARDED_BLOCK(pnd->logical_blk_num)) {17651765+ nand_dbg_print(NAND_DBG_WARN, "%s, Line %d\n", __FILE__, __LINE__);17661766+ memset(cache_l2_blk_buf, 0xff, DeviceInfo.wPagesPerBlock * DeviceInfo.wPageDataSize); 17671767+ } else {17681768+ nand_dbg_print(NAND_DBG_WARN, "%s, Line %d\n", __FILE__, __LINE__);17691769+ phy_blk = pbt[pnd->logical_blk_num] & (~BAD_BLOCK);17701770+ ret = GLOB_LLD_Read_Page_Main(cache_l2_blk_buf,17711771+ phy_blk, 0, DeviceInfo.wPagesPerBlock);17721772+ if (ret == FAIL) {17731773+ printk(KERN_ERR "Read NAND page fail in %s, Line %d\n", __FILE__, __LINE__);17741774+ }17751775+ }17761776+17771777+ for (i = 0; i < DeviceInfo.wPagesPerBlock; i++) {17781778+ if (pnd->pages_array[i] != MAX_U32_VALUE) {17791779+ l2_blk = cache_l2.blk_array[(pnd->pages_array[i] >> 16) & 0xffff];17801780+ l2_page = pnd->pages_array[i] & 0xffff;17811781+ ret = GLOB_LLD_Read_Page_Main(cache_l2_page_buf, l2_blk, l2_page, 1);17821782+ if (ret == FAIL) {17831783+ printk(KERN_ERR "Read NAND page fail in %s, Line %d\n", __FILE__, __LINE__);17841784+ }17851785+ memcpy(cache_l2_blk_buf + i * DeviceInfo.wPageDataSize, cache_l2_page_buf, DeviceInfo.wPageDataSize);17861786+ }17871787+ }17881788+17891789+ /* Find a free block and tag the original block as discarded */17901790+ addr = (u64)pnd->logical_blk_num << DeviceInfo.nBitsInBlockDataSize;17911791+ ret = FTL_Replace_Block(addr);17921792+ if (ret == FAIL) {17931793+ printk(KERN_ERR "FTL_Replace_Block fail in %s, Line %d\n", __FILE__, __LINE__);17941794+ }17951795+17961796+ /* Write back the updated data into NAND */17971797+ phy_blk = pbt[pnd->logical_blk_num] & (~BAD_BLOCK);17981798+ if (FAIL == GLOB_LLD_Write_Page_Main(cache_l2_blk_buf, phy_blk, 0, DeviceInfo.wPagesPerBlock)) {17991799+ nand_dbg_print(NAND_DBG_WARN,18001800+ "Program NAND block %d fail in %s, Line %d\n",18011801+ phy_blk, __FILE__, __LINE__);18021802+ /* This may not be really a bad block. So just tag it as discarded. */18031803+ /* Then it has a chance to be erased when garbage collection. */18041804+ /* If it is really bad, then the erase will fail and it will be marked */18051805+ /* as bad then. Otherwise it will be marked as free and can be used again */18061806+ MARK_BLK_AS_DISCARD(pbt[pnd->logical_blk_num]);18071807+ /* Find another free block and write it again */18081808+ FTL_Replace_Block(addr);18091809+ phy_blk = pbt[pnd->logical_blk_num] & (~BAD_BLOCK);18101810+ if (FAIL == GLOB_LLD_Write_Page_Main(cache_l2_blk_buf, phy_blk, 0, DeviceInfo.wPagesPerBlock)) {18111811+ printk(KERN_ERR "Failed to write back block %d when flush L2 cache."18121812+ "Some data will be lost!\n", phy_blk);18131813+ MARK_BLOCK_AS_BAD(pbt[pnd->logical_blk_num]);18141814+ }18151815+ } else {18161816+ /* tag the new free block as used block */18171817+ pbt[pnd->logical_blk_num] &= (~SPARE_BLOCK);18181818+ }18191819+ }18201820+18211821+ /* Destroy the L2 Cache table and free the memory of all nodes */18221822+ list_for_each_entry_safe(pnd, tmp_pnd, &cache_l2.table.list, list) {18231823+ list_del(&pnd->list);18241824+ kfree(pnd);18251825+ }18261826+18271827+ /* Erase discard L2 cache blocks */18281828+ if (erase_l2_cache_blocks() != PASS)18291829+ nand_dbg_print(NAND_DBG_WARN,18301830+ " Erase L2 cache blocks error in %s, Line %d\n",18311831+ __FILE__, __LINE__);18321832+18331833+ /* Init the Level2 Cache data structure */18341834+ for (i = 0; i < BLK_NUM_FOR_L2_CACHE; i++)18351835+ cache_l2.blk_array[i] = MAX_U32_VALUE;18361836+ cache_l2.cur_blk_idx = 0;18371837+ cache_l2.cur_page_num = 0;18381838+ INIT_LIST_HEAD(&cache_l2.table.list);18391839+ cache_l2.table.logical_blk_num = MAX_U32_VALUE;18401840+18411841+ return ret;18421842+}18431843+18441844+/*18451845+ * Write back a changed victim cache item to the Level2 Cache18461846+ * and update the L2 Cache table to map the change.18471847+ * If the L2 Cache is full, then start to do the L2 Cache flush.18481848+*/18491849+static int write_back_to_l2_cache(u8 *buf, u64 logical_addr)18501850+{18511851+ u32 logical_blk_num;18521852+ u16 logical_page_num;18531853+ struct list_head *p;18541854+ struct spectra_l2_cache_list *pnd, *pnd_new;18551855+ u32 node_size;18561856+ int i, found;18571857+18581858+ nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n",18591859+ __FILE__, __LINE__, __func__);18601860+18611861+ /*18621862+ * If Level2 Cache table is empty, then it means either:18631863+ * 1. This is the first time that the function called after FTL_init18641864+ * or18651865+ * 2. The Level2 Cache has just been flushed18661866+ *18671867+ * So, 'steal' some free blocks from NAND for L2 Cache using18681868+ * by just mask them as discard in the block table18691869+ */18701870+ if (list_empty(&cache_l2.table.list)) {18711871+ BUG_ON(cache_l2.cur_blk_idx != 0);18721872+ BUG_ON(cache_l2.cur_page_num!= 0);18731873+ BUG_ON(cache_l2.table.logical_blk_num != MAX_U32_VALUE);18741874+ if (FAIL == get_l2_cache_blks()) {18751875+ GLOB_FTL_Garbage_Collection();18761876+ if (FAIL == get_l2_cache_blks()) {18771877+ printk(KERN_ALERT "Fail to get L2 cache blks!\n");18781878+ return FAIL;18791879+ }18801880+ }18811881+ }18821882+18831883+ logical_blk_num = BLK_FROM_ADDR(logical_addr);18841884+ logical_page_num = PAGE_FROM_ADDR(logical_addr, logical_blk_num);18851885+ BUG_ON(logical_blk_num == MAX_U32_VALUE);18861886+18871887+ /* Write the cache item data into the current position of L2 Cache */18881888+#if CMD_DMA18891889+ /*18901890+ * TODO18911891+ */18921892+#else18931893+ if (FAIL == GLOB_LLD_Write_Page_Main(buf,18941894+ cache_l2.blk_array[cache_l2.cur_blk_idx],18951895+ cache_l2.cur_page_num, 1)) {18961896+ nand_dbg_print(NAND_DBG_WARN, "NAND Program fail in "18971897+ "%s, Line %d, new Bad Block %d generated!\n",18981898+ __FILE__, __LINE__,18991899+ cache_l2.blk_array[cache_l2.cur_blk_idx]);19001900+19011901+ /* TODO: tag the current block as bad and try again */19021902+19031903+ return FAIL;19041904+ }19051905+#endif19061906+19071907+ /* 19081908+ * Update the L2 Cache table.19091909+ *19101910+ * First seaching in the table to see whether the logical block19111911+ * has been mapped. If not, then kmalloc a new node for the19121912+ * logical block, fill data, and then insert it to the list.19131913+ * Otherwise, just update the mapped node directly.19141914+ */19151915+ found = 0;19161916+ list_for_each(p, &cache_l2.table.list) {19171917+ pnd = list_entry(p, struct spectra_l2_cache_list, list);19181918+ if (pnd->logical_blk_num == logical_blk_num) {19191919+ pnd->pages_array[logical_page_num] =19201920+ (cache_l2.cur_blk_idx << 16) |19211921+ cache_l2.cur_page_num;19221922+ found = 1;19231923+ break;19241924+ }19251925+ }19261926+ if (!found) { /* Create new node for the logical block here */19271927+19281928+ /* The logical pages to physical pages map array is19291929+ * located at the end of struct spectra_l2_cache_list.19301930+ */ 19311931+ node_size = sizeof(struct spectra_l2_cache_list) +19321932+ sizeof(u32) * DeviceInfo.wPagesPerBlock;19331933+ pnd_new = kmalloc(node_size, GFP_ATOMIC);19341934+ if (!pnd_new) {19351935+ printk(KERN_ERR "Failed to kmalloc in %s Line %d\n",19361936+ __FILE__, __LINE__);19371937+ /* 19381938+ * TODO: Need to flush all the L2 cache into NAND ASAP19391939+ * since no memory available here19401940+ */19411941+ }19421942+ pnd_new->logical_blk_num = logical_blk_num;19431943+ for (i = 0; i < DeviceInfo.wPagesPerBlock; i++)19441944+ pnd_new->pages_array[i] = MAX_U32_VALUE;19451945+ pnd_new->pages_array[logical_page_num] =19461946+ (cache_l2.cur_blk_idx << 16) | cache_l2.cur_page_num;19471947+ list_add(&pnd_new->list, &cache_l2.table.list);19481948+ }19491949+19501950+ /* Increasing the current position pointer of the L2 Cache */19511951+ cache_l2.cur_page_num++;19521952+ if (cache_l2.cur_page_num >= DeviceInfo.wPagesPerBlock) {19531953+ cache_l2.cur_blk_idx++;19541954+ if (cache_l2.cur_blk_idx >= BLK_NUM_FOR_L2_CACHE) {19551955+ /* The L2 Cache is full. Need to flush it now */19561956+ nand_dbg_print(NAND_DBG_WARN,19571957+ "L2 Cache is full, will start to flush it\n");19581958+ flush_l2_cache();19591959+ } else {19601960+ cache_l2.cur_page_num = 0;19611961+ }19621962+ }19631963+19641964+ return PASS;19651965+}19661966+19671967+/*19681968+ * Seach in the Level2 Cache table to find the cache item.19691969+ * If find, read the data from the NAND page of L2 Cache,19701970+ * Otherwise, return FAIL.19711971+ */19721972+static int search_l2_cache(u8 *buf, u64 logical_addr)19731973+{19741974+ u32 logical_blk_num;19751975+ u16 logical_page_num;19761976+ struct list_head *p;19771977+ struct spectra_l2_cache_list *pnd;19781978+ u32 tmp = MAX_U32_VALUE;19791979+ u32 phy_blk;19801980+ u16 phy_page;19811981+ int ret = FAIL;19821982+19831983+ logical_blk_num = BLK_FROM_ADDR(logical_addr);19841984+ logical_page_num = PAGE_FROM_ADDR(logical_addr, logical_blk_num);19851985+19861986+ list_for_each(p, &cache_l2.table.list) {19871987+ pnd = list_entry(p, struct spectra_l2_cache_list, list);19881988+ if (pnd->logical_blk_num == logical_blk_num) {19891989+ tmp = pnd->pages_array[logical_page_num];19901990+ break;19911991+ }19921992+ }19931993+19941994+ if (tmp != MAX_U32_VALUE) { /* Found valid map */19951995+ phy_blk = cache_l2.blk_array[(tmp >> 16) & 0xFFFF];19961996+ phy_page = tmp & 0xFFFF;19971997+#if CMD_DMA19981998+ /* TODO */19991999+#else20002000+ ret = GLOB_LLD_Read_Page_Main(buf, phy_blk, phy_page, 1);20012001+#endif20022002+ }20032003+20042004+ return ret;20052005+}20062006+20072007+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&20082008+* Function: FTL_Cache_Write_Back20092009+* Inputs: pointer to data cached in sys memory20102010+* address of free block in flash20112011+* Outputs: PASS=0 / FAIL=120122012+* Description: writes all the pages of Cache Block to flash20132013+*20142014+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/20152015+static int FTL_Cache_Write_Back(u8 *pData, u64 blk_addr)20162016+{20172017+ int i, j, iErase;20182018+ u64 old_page_addr, addr, phy_addr;20192019+ u32 *pbt = (u32 *)g_pBlockTable;20202020+ u32 lba;20212021+20222022+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",20232023+ __FILE__, __LINE__, __func__);20242024+20252025+ old_page_addr = FTL_Get_Physical_Block_Addr(blk_addr) +20262026+ GLOB_u64_Remainder(blk_addr, 2);20272027+20282028+ iErase = (FAIL == FTL_Replace_Block(blk_addr)) ? PASS : FAIL;20292029+20302030+ pbt[BLK_FROM_ADDR(blk_addr)] &= (~SPARE_BLOCK);20312031+20322032+#if CMD_DMA20332033+ p_BTableChangesDelta = (struct BTableChangesDelta *)g_pBTDelta_Free;20342034+ g_pBTDelta_Free += sizeof(struct BTableChangesDelta);20352035+20362036+ p_BTableChangesDelta->ftl_cmd_cnt = ftl_cmd_cnt;20372037+ p_BTableChangesDelta->BT_Index = (u32)(blk_addr >>20382038+ DeviceInfo.nBitsInBlockDataSize);20392039+ p_BTableChangesDelta->BT_Entry_Value =20402040+ pbt[(u32)(blk_addr >> DeviceInfo.nBitsInBlockDataSize)];20412041+ p_BTableChangesDelta->ValidFields = 0x0C;20422042+#endif20432043+20442044+ if (IN_PROGRESS_BLOCK_TABLE != g_cBlockTableStatus) {20452045+ g_cBlockTableStatus = IN_PROGRESS_BLOCK_TABLE;20462046+ FTL_Write_IN_Progress_Block_Table_Page();20472047+ }20482048+20492049+ for (i = 0; i < RETRY_TIMES; i++) {20502050+ if (PASS == iErase) {20512051+ phy_addr = FTL_Get_Physical_Block_Addr(blk_addr);20522052+ if (FAIL == GLOB_FTL_Block_Erase(phy_addr)) {20532053+ lba = BLK_FROM_ADDR(blk_addr);20542054+ MARK_BLOCK_AS_BAD(pbt[lba]);20552055+ i = RETRY_TIMES;20562056+ break;20572057+ }20582058+ }20592059+20602060+ for (j = 0; j < CACHE_ITEM_NUM; j++) {20612061+ addr = Cache.array[j].address;20622062+ if ((addr <= blk_addr) &&20632063+ ((addr + Cache.cache_item_size) > blk_addr))20642064+ cache_block_to_write = j;20652065+ }20662066+20672067+ phy_addr = FTL_Get_Physical_Block_Addr(blk_addr);20682068+ if (PASS == FTL_Cache_Update_Block(pData,20692069+ old_page_addr, phy_addr)) {20702070+ cache_block_to_write = UNHIT_CACHE_ITEM;20712071+ break;20722072+ } else {20732073+ iErase = PASS;20742074+ }20752075+ }20762076+20772077+ if (i >= RETRY_TIMES) {20782078+ if (ERR == FTL_Flash_Error_Handle(pData,20792079+ old_page_addr, blk_addr))20802080+ return ERR;20812081+ else20822082+ return FAIL;20832083+ }20842084+20852085+ return PASS;20862086+}20872087+20882088+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&20892089+* Function: FTL_Cache_Write_Page20902090+* Inputs: Pointer to buffer, page address, cache block number20912091+* Outputs: PASS=0 / FAIL=120922092+* Description: It writes the data in Cache Block20932093+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/20942094+static void FTL_Cache_Write_Page(u8 *pData, u64 page_addr,20952095+ u8 cache_blk, u16 flag)20962096+{20972097+ u8 *pDest;20982098+ u64 addr;20992099+21002100+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",21012101+ __FILE__, __LINE__, __func__);21022102+21032103+ addr = Cache.array[cache_blk].address;21042104+ pDest = Cache.array[cache_blk].buf;21052105+21062106+ pDest += (unsigned long)(page_addr - addr);21072107+ Cache.array[cache_blk].changed = SET;21082108+#if CMD_DMA21092109+#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE21102110+ int_cache[ftl_cmd_cnt].item = cache_blk;21112111+ int_cache[ftl_cmd_cnt].cache.address =21122112+ Cache.array[cache_blk].address;21132113+ int_cache[ftl_cmd_cnt].cache.changed =21142114+ Cache.array[cache_blk].changed;21152115+#endif21162116+ GLOB_LLD_MemCopy_CMD(pDest, pData, DeviceInfo.wPageDataSize, flag);21172117+ ftl_cmd_cnt++;21182118+#else21192119+ memcpy(pDest, pData, DeviceInfo.wPageDataSize);21202120+#endif21212121+ if (Cache.array[cache_blk].use_cnt < MAX_WORD_VALUE)21222122+ Cache.array[cache_blk].use_cnt++;21232123+}21242124+21252125+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&21262126+* Function: FTL_Cache_Write21272127+* Inputs: none21282128+* Outputs: PASS=0 / FAIL=121292129+* Description: It writes least frequently used Cache block to flash if it21302130+* has been changed21312131+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/21322132+static int FTL_Cache_Write(void)21332133+{21342134+ int i, bResult = PASS;21352135+ u16 bNO, least_count = 0xFFFF;21362136+21372137+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",21382138+ __FILE__, __LINE__, __func__);21392139+21402140+ FTL_Calculate_LRU();21412141+21422142+ bNO = Cache.LRU;21432143+ nand_dbg_print(NAND_DBG_DEBUG, "FTL_Cache_Write: "21442144+ "Least used cache block is %d\n", bNO);21452145+21462146+ if (Cache.array[bNO].changed != SET)21472147+ return bResult;21482148+21492149+ nand_dbg_print(NAND_DBG_DEBUG, "FTL_Cache_Write: Cache"21502150+ " Block %d containing logical block %d is dirty\n",21512151+ bNO,21522152+ (u32)(Cache.array[bNO].address >>21532153+ DeviceInfo.nBitsInBlockDataSize));21542154+#if CMD_DMA21552155+#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE21562156+ int_cache[ftl_cmd_cnt].item = bNO;21572157+ int_cache[ftl_cmd_cnt].cache.address =21582158+ Cache.array[bNO].address;21592159+ int_cache[ftl_cmd_cnt].cache.changed = CLEAR;21602160+#endif21612161+#endif21622162+ bResult = write_back_to_l2_cache(Cache.array[bNO].buf,21632163+ Cache.array[bNO].address);21642164+ if (bResult != ERR)21652165+ Cache.array[bNO].changed = CLEAR;21662166+21672167+ least_count = Cache.array[bNO].use_cnt;21682168+21692169+ for (i = 0; i < CACHE_ITEM_NUM; i++) {21702170+ if (i == bNO)21712171+ continue;21722172+ if (Cache.array[i].use_cnt > 0)21732173+ Cache.array[i].use_cnt -= least_count;21742174+ }21752175+21762176+ return bResult;21772177+}21782178+21792179+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&21802180+* Function: FTL_Cache_Read21812181+* Inputs: Page address21822182+* Outputs: PASS=0 / FAIL=121832183+* Description: It reads the block from device in Cache Block21842184+* Set the LRU count to 121852185+* Mark the Cache Block as clean21862186+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/21872187+static int FTL_Cache_Read(u64 logical_addr)21882188+{21892189+ u64 item_addr, phy_addr;21902190+ u16 num;21912191+ int ret;21922192+21932193+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",21942194+ __FILE__, __LINE__, __func__);21952195+21962196+ num = Cache.LRU; /* The LRU cache item will be overwritten */21972197+21982198+ item_addr = (u64)GLOB_u64_Div(logical_addr, Cache.cache_item_size) *21992199+ Cache.cache_item_size;22002200+ Cache.array[num].address = item_addr;22012201+ Cache.array[num].use_cnt = 1;22022202+ Cache.array[num].changed = CLEAR;22032203+22042204+#if CMD_DMA22052205+#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE22062206+ int_cache[ftl_cmd_cnt].item = num;22072207+ int_cache[ftl_cmd_cnt].cache.address =22082208+ Cache.array[num].address;22092209+ int_cache[ftl_cmd_cnt].cache.changed =22102210+ Cache.array[num].changed;22112211+#endif22122212+#endif22132213+ /*22142214+ * Search in L2 Cache. If hit, fill data into L1 Cache item buffer,22152215+ * Otherwise, read it from NAND22162216+ */22172217+ ret = search_l2_cache(Cache.array[num].buf, logical_addr);22182218+ if (PASS == ret) /* Hit in L2 Cache */22192219+ return ret;22202220+22212221+ /* Compute the physical start address of NAND device according to */22222222+ /* the logical start address of the cache item (LRU cache item) */22232223+ phy_addr = FTL_Get_Physical_Block_Addr(item_addr) +22242224+ GLOB_u64_Remainder(item_addr, 2);22252225+22262226+ return FTL_Cache_Read_All(Cache.array[num].buf, phy_addr);22272227+}22282228+22292229+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&22302230+* Function: FTL_Check_Block_Table22312231+* Inputs: ?22322232+* Outputs: PASS=0 / FAIL=122332233+* Description: It checks the correctness of each block table entry22342234+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/22352235+static int FTL_Check_Block_Table(int wOldTable)22362236+{22372237+ u32 i;22382238+ int wResult = PASS;22392239+ u32 blk_idx;22402240+ u32 *pbt = (u32 *)g_pBlockTable;22412241+ u8 *pFlag = flag_check_blk_table;22422242+22432243+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",22442244+ __FILE__, __LINE__, __func__);22452245+22462246+ if (NULL != pFlag) {22472247+ memset(pFlag, FAIL, DeviceInfo.wDataBlockNum);22482248+ for (i = 0; i < DeviceInfo.wDataBlockNum; i++) {22492249+ blk_idx = (u32)(pbt[i] & (~BAD_BLOCK));22502250+22512251+ /*22522252+ * 20081006/KBV - Changed to pFlag[i] reference22532253+ * to avoid buffer overflow22542254+ */22552255+22562256+ /*22572257+ * 2008-10-20 Yunpeng Note: This change avoid22582258+ * buffer overflow, but changed function of22592259+ * the code, so it should be re-write later22602260+ */22612261+ if ((blk_idx > DeviceInfo.wSpectraEndBlock) ||22622262+ PASS == pFlag[i]) {22632263+ wResult = FAIL;22642264+ break;22652265+ } else {22662266+ pFlag[i] = PASS;22672267+ }22682268+ }22692269+ }22702270+22712271+ return wResult;22722272+}22732273+22742274+22752275+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&22762276+* Function: FTL_Write_Block_Table22772277+* Inputs: flasg22782278+* Outputs: 0=Block Table was updated. No write done. 1=Block write needs to22792279+* happen. -1 Error22802280+* Description: It writes the block table22812281+* Block table always mapped to LBA 0 which inturn mapped22822282+* to any physical block22832283+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/22842284+static int FTL_Write_Block_Table(int wForce)22852285+{22862286+ u32 *pbt = (u32 *)g_pBlockTable;22872287+ int wSuccess = PASS;22882288+ u32 wTempBlockTableIndex;22892289+ u16 bt_pages, new_bt_offset;22902290+ u8 blockchangeoccured = 0;22912291+22922292+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",22932293+ __FILE__, __LINE__, __func__);22942294+22952295+ bt_pages = FTL_Get_Block_Table_Flash_Size_Pages();22962296+22972297+ if (IN_PROGRESS_BLOCK_TABLE != g_cBlockTableStatus)22982298+ return 0;22992299+23002300+ if (PASS == wForce) {23012301+ g_wBlockTableOffset =23022302+ (u16)(DeviceInfo.wPagesPerBlock - bt_pages);23032303+#if CMD_DMA23042304+ p_BTableChangesDelta =23052305+ (struct BTableChangesDelta *)g_pBTDelta_Free;23062306+ g_pBTDelta_Free += sizeof(struct BTableChangesDelta);23072307+23082308+ p_BTableChangesDelta->ftl_cmd_cnt = ftl_cmd_cnt;23092309+ p_BTableChangesDelta->g_wBlockTableOffset =23102310+ g_wBlockTableOffset;23112311+ p_BTableChangesDelta->ValidFields = 0x01;23122312+#endif23132313+ }23142314+23152315+ nand_dbg_print(NAND_DBG_DEBUG,23162316+ "Inside FTL_Write_Block_Table: block %d Page:%d\n",23172317+ g_wBlockTableIndex, g_wBlockTableOffset);23182318+23192319+ do {23202320+ new_bt_offset = g_wBlockTableOffset + bt_pages + 1;23212321+ if ((0 == (new_bt_offset % DeviceInfo.wPagesPerBlock)) ||23222322+ (new_bt_offset > DeviceInfo.wPagesPerBlock) ||23232323+ (FAIL == wSuccess)) {23242324+ wTempBlockTableIndex = FTL_Replace_Block_Table();23252325+ if (BAD_BLOCK == wTempBlockTableIndex)23262326+ return ERR;23272327+ if (!blockchangeoccured) {23282328+ bt_block_changed = 1;23292329+ blockchangeoccured = 1;23302330+ }23312331+23322332+ g_wBlockTableIndex = wTempBlockTableIndex;23332333+ g_wBlockTableOffset = 0;23342334+ pbt[BLOCK_TABLE_INDEX] = g_wBlockTableIndex;23352335+#if CMD_DMA23362336+ p_BTableChangesDelta =23372337+ (struct BTableChangesDelta *)g_pBTDelta_Free;23382338+ g_pBTDelta_Free += sizeof(struct BTableChangesDelta);23392339+23402340+ p_BTableChangesDelta->ftl_cmd_cnt =23412341+ ftl_cmd_cnt;23422342+ p_BTableChangesDelta->g_wBlockTableOffset =23432343+ g_wBlockTableOffset;23442344+ p_BTableChangesDelta->g_wBlockTableIndex =23452345+ g_wBlockTableIndex;23462346+ p_BTableChangesDelta->ValidFields = 0x03;23472347+23482348+ p_BTableChangesDelta =23492349+ (struct BTableChangesDelta *)g_pBTDelta_Free;23502350+ g_pBTDelta_Free +=23512351+ sizeof(struct BTableChangesDelta);23522352+23532353+ p_BTableChangesDelta->ftl_cmd_cnt =23542354+ ftl_cmd_cnt;23552355+ p_BTableChangesDelta->BT_Index =23562356+ BLOCK_TABLE_INDEX;23572357+ p_BTableChangesDelta->BT_Entry_Value =23582358+ pbt[BLOCK_TABLE_INDEX];23592359+ p_BTableChangesDelta->ValidFields = 0x0C;23602360+#endif23612361+ }23622362+23632363+ wSuccess = FTL_Write_Block_Table_Data();23642364+ if (FAIL == wSuccess)23652365+ MARK_BLOCK_AS_BAD(pbt[BLOCK_TABLE_INDEX]);23662366+ } while (FAIL == wSuccess);23672367+23682368+ g_cBlockTableStatus = CURRENT_BLOCK_TABLE;23692369+23702370+ return 1;23712371+}23722372+23732373+/******************************************************************23742374+* Function: GLOB_FTL_Flash_Format23752375+* Inputs: none23762376+* Outputs: PASS23772377+* Description: The block table stores bad block info, including MDF+23782378+* blocks gone bad over the ages. Therefore, if we have a23792379+* block table in place, then use it to scan for bad blocks23802380+* If not, then scan for MDF.23812381+* Now, a block table will only be found if spectra was already23822382+* being used. For a fresh flash, we'll go thru scanning for23832383+* MDF. If spectra was being used, then there is a chance that23842384+* the MDF has been corrupted. Spectra avoids writing to the23852385+* first 2 bytes of the spare area to all pages in a block. This23862386+* covers all known flash devices. However, since flash23872387+* manufacturers have no standard of where the MDF is stored,23882388+* this cannot guarantee that the MDF is protected for future23892389+* devices too. The initial scanning for the block table assures23902390+* this. It is ok even if the block table is outdated, as all23912391+* we're looking for are bad block markers.23922392+* Use this when mounting a file system or starting a23932393+* new flash.23942394+*23952395+*********************************************************************/23962396+static int FTL_Format_Flash(u8 valid_block_table)23972397+{23982398+ u32 i, j;23992399+ u32 *pbt = (u32 *)g_pBlockTable;24002400+ u32 tempNode;24012401+ int ret;24022402+24032403+#if CMD_DMA24042404+ u32 *pbtStartingCopy = (u32 *)g_pBTStartingCopy;24052405+ if (ftl_cmd_cnt)24062406+ return FAIL;24072407+#endif24082408+24092409+ if (FAIL == FTL_Check_Block_Table(FAIL))24102410+ valid_block_table = 0;24112411+24122412+ if (valid_block_table) {24132413+ u8 switched = 1;24142414+ u32 block, k;24152415+24162416+ k = DeviceInfo.wSpectraStartBlock;24172417+ while (switched && (k < DeviceInfo.wSpectraEndBlock)) {24182418+ switched = 0;24192419+ k++;24202420+ for (j = DeviceInfo.wSpectraStartBlock, i = 0;24212421+ j <= DeviceInfo.wSpectraEndBlock;24222422+ j++, i++) {24232423+ block = (pbt[i] & ~BAD_BLOCK) -24242424+ DeviceInfo.wSpectraStartBlock;24252425+ if (block != i) {24262426+ switched = 1;24272427+ tempNode = pbt[i];24282428+ pbt[i] = pbt[block];24292429+ pbt[block] = tempNode;24302430+ }24312431+ }24322432+ }24332433+ if ((k == DeviceInfo.wSpectraEndBlock) && switched)24342434+ valid_block_table = 0;24352435+ }24362436+24372437+ if (!valid_block_table) {24382438+ memset(g_pBlockTable, 0,24392439+ DeviceInfo.wDataBlockNum * sizeof(u32));24402440+ memset(g_pWearCounter, 0,24412441+ DeviceInfo.wDataBlockNum * sizeof(u8));24422442+ if (DeviceInfo.MLCDevice)24432443+ memset(g_pReadCounter, 0,24442444+ DeviceInfo.wDataBlockNum * sizeof(u16));24452445+#if CMD_DMA24462446+ memset(g_pBTStartingCopy, 0,24472447+ DeviceInfo.wDataBlockNum * sizeof(u32));24482448+ memset(g_pWearCounterCopy, 0,24492449+ DeviceInfo.wDataBlockNum * sizeof(u8));24502450+ if (DeviceInfo.MLCDevice)24512451+ memset(g_pReadCounterCopy, 0,24522452+ DeviceInfo.wDataBlockNum * sizeof(u16));24532453+#endif24542454+ for (j = DeviceInfo.wSpectraStartBlock, i = 0;24552455+ j <= DeviceInfo.wSpectraEndBlock;24562456+ j++, i++) {24572457+ if (GLOB_LLD_Get_Bad_Block((u32)j))24582458+ pbt[i] = (u32)(BAD_BLOCK | j);24592459+ }24602460+ }24612461+24622462+ nand_dbg_print(NAND_DBG_WARN, "Erasing all blocks in the NAND\n");24632463+24642464+ for (j = DeviceInfo.wSpectraStartBlock, i = 0;24652465+ j <= DeviceInfo.wSpectraEndBlock;24662466+ j++, i++) {24672467+ if ((pbt[i] & BAD_BLOCK) != BAD_BLOCK) {24682468+ ret = GLOB_LLD_Erase_Block(j);24692469+ if (FAIL == ret) {24702470+ pbt[i] = (u32)(j);24712471+ MARK_BLOCK_AS_BAD(pbt[i]);24722472+ nand_dbg_print(NAND_DBG_WARN,24732473+ "NAND Program fail in %s, Line %d, "24742474+ "Function: %s, new Bad Block %d generated!\n",24752475+ __FILE__, __LINE__, __func__, (int)j);24762476+ } else {24772477+ pbt[i] = (u32)(SPARE_BLOCK | j);24782478+ }24792479+ }24802480+#if CMD_DMA24812481+ pbtStartingCopy[i] = pbt[i];24822482+#endif24832483+ }24842484+24852485+ g_wBlockTableOffset = 0;24862486+ for (i = 0; (i <= (DeviceInfo.wSpectraEndBlock -24872487+ DeviceInfo.wSpectraStartBlock))24882488+ && ((pbt[i] & BAD_BLOCK) == BAD_BLOCK); i++)24892489+ ;24902490+ if (i > (DeviceInfo.wSpectraEndBlock - DeviceInfo.wSpectraStartBlock)) {24912491+ printk(KERN_ERR "All blocks bad!\n");24922492+ return FAIL;24932493+ } else {24942494+ g_wBlockTableIndex = pbt[i] & ~BAD_BLOCK;24952495+ if (i != BLOCK_TABLE_INDEX) {24962496+ tempNode = pbt[i];24972497+ pbt[i] = pbt[BLOCK_TABLE_INDEX];24982498+ pbt[BLOCK_TABLE_INDEX] = tempNode;24992499+ }25002500+ }25012501+ pbt[BLOCK_TABLE_INDEX] &= (~SPARE_BLOCK);25022502+25032503+#if CMD_DMA25042504+ pbtStartingCopy[BLOCK_TABLE_INDEX] &= (~SPARE_BLOCK);25052505+#endif25062506+25072507+ g_cBlockTableStatus = IN_PROGRESS_BLOCK_TABLE;25082508+ memset(g_pBTBlocks, 0xFF,25092509+ (1 + LAST_BT_ID - FIRST_BT_ID) * sizeof(u32));25102510+ g_pBTBlocks[FIRST_BT_ID-FIRST_BT_ID] = g_wBlockTableIndex;25112511+ FTL_Write_Block_Table(FAIL);25122512+25132513+ for (i = 0; i < CACHE_ITEM_NUM; i++) {25142514+ Cache.array[i].address = NAND_CACHE_INIT_ADDR;25152515+ Cache.array[i].use_cnt = 0;25162516+ Cache.array[i].changed = CLEAR;25172517+ }25182518+25192519+#if (RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE && CMD_DMA)25202520+ memcpy((void *)&cache_start_copy, (void *)&Cache,25212521+ sizeof(struct flash_cache_tag));25222522+#endif25232523+ return PASS;25242524+}25252525+25262526+static int force_format_nand(void)25272527+{25282528+ u32 i;25292529+25302530+ /* Force erase the whole unprotected physical partiton of NAND */25312531+ printk(KERN_ALERT "Start to force erase whole NAND device ...\n");25322532+ printk(KERN_ALERT "From phyical block %d to %d\n",25332533+ DeviceInfo.wSpectraStartBlock, DeviceInfo.wSpectraEndBlock);25342534+ for (i = DeviceInfo.wSpectraStartBlock; i <= DeviceInfo.wSpectraEndBlock; i++) {25352535+ if (GLOB_LLD_Erase_Block(i))25362536+ printk(KERN_ERR "Failed to force erase NAND block %d\n", i);25372537+ }25382538+ printk(KERN_ALERT "Force Erase ends. Please reboot the system ...\n");25392539+ while(1);25402540+25412541+ return PASS;25422542+}25432543+25442544+int GLOB_FTL_Flash_Format(void)25452545+{25462546+ //return FTL_Format_Flash(1);25472547+ return force_format_nand();25482548+25492549+}25502550+25512551+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&25522552+* Function: FTL_Search_Block_Table_IN_Block25532553+* Inputs: Block Number25542554+* Pointer to page25552555+* Outputs: PASS / FAIL25562556+* Page contatining the block table25572557+* Description: It searches the block table in the block25582558+* passed as an argument.25592559+*25602560+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/25612561+static int FTL_Search_Block_Table_IN_Block(u32 BT_Block,25622562+ u8 BT_Tag, u16 *Page)25632563+{25642564+ u16 i, j, k;25652565+ u16 Result = PASS;25662566+ u16 Last_IPF = 0;25672567+ u8 BT_Found = 0;25682568+ u8 *tagarray;25692569+ u8 *tempbuf = tmp_buf_search_bt_in_block;25702570+ u8 *pSpareBuf = spare_buf_search_bt_in_block;25712571+ u8 *pSpareBufBTLastPage = spare_buf_bt_search_bt_in_block;25722572+ u8 bt_flag_last_page = 0xFF;25732573+ u8 search_in_previous_pages = 0;25742574+ u16 bt_pages;25752575+25762576+ nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n",25772577+ __FILE__, __LINE__, __func__);25782578+25792579+ nand_dbg_print(NAND_DBG_DEBUG,25802580+ "Searching block table in %u block\n",25812581+ (unsigned int)BT_Block);25822582+25832583+ bt_pages = FTL_Get_Block_Table_Flash_Size_Pages();25842584+25852585+ for (i = bt_pages; i < DeviceInfo.wPagesPerBlock;25862586+ i += (bt_pages + 1)) {25872587+ nand_dbg_print(NAND_DBG_DEBUG,25882588+ "Searching last IPF: %d\n", i);25892589+ Result = GLOB_LLD_Read_Page_Main_Polling(tempbuf,25902590+ BT_Block, i, 1);25912591+25922592+ if (0 == memcmp(tempbuf, g_pIPF, DeviceInfo.wPageDataSize)) {25932593+ if ((i + bt_pages + 1) < DeviceInfo.wPagesPerBlock) {25942594+ continue;25952595+ } else {25962596+ search_in_previous_pages = 1;25972597+ Last_IPF = i;25982598+ }25992599+ }26002600+26012601+ if (!search_in_previous_pages) {26022602+ if (i != bt_pages) {26032603+ i -= (bt_pages + 1);26042604+ Last_IPF = i;26052605+ }26062606+ }26072607+26082608+ if (0 == Last_IPF)26092609+ break;26102610+26112611+ if (!search_in_previous_pages) {26122612+ i = i + 1;26132613+ nand_dbg_print(NAND_DBG_DEBUG,26142614+ "Reading the spare area of Block %u Page %u",26152615+ (unsigned int)BT_Block, i);26162616+ Result = GLOB_LLD_Read_Page_Spare(pSpareBuf,26172617+ BT_Block, i, 1);26182618+ nand_dbg_print(NAND_DBG_DEBUG,26192619+ "Reading the spare area of Block %u Page %u",26202620+ (unsigned int)BT_Block, i + bt_pages - 1);26212621+ Result = GLOB_LLD_Read_Page_Spare(pSpareBufBTLastPage,26222622+ BT_Block, i + bt_pages - 1, 1);26232623+26242624+ k = 0;26252625+ j = FTL_Extract_Block_Table_Tag(pSpareBuf, &tagarray);26262626+ if (j) {26272627+ for (; k < j; k++) {26282628+ if (tagarray[k] == BT_Tag)26292629+ break;26302630+ }26312631+ }26322632+26332633+ if (k < j)26342634+ bt_flag = tagarray[k];26352635+ else26362636+ Result = FAIL;26372637+26382638+ if (Result == PASS) {26392639+ k = 0;26402640+ j = FTL_Extract_Block_Table_Tag(26412641+ pSpareBufBTLastPage, &tagarray);26422642+ if (j) {26432643+ for (; k < j; k++) {26442644+ if (tagarray[k] == BT_Tag)26452645+ break;26462646+ }26472647+ }26482648+26492649+ if (k < j)26502650+ bt_flag_last_page = tagarray[k];26512651+ else26522652+ Result = FAIL;26532653+26542654+ if (Result == PASS) {26552655+ if (bt_flag == bt_flag_last_page) {26562656+ nand_dbg_print(NAND_DBG_DEBUG,26572657+ "Block table is found"26582658+ " in page after IPF "26592659+ "at block %d "26602660+ "page %d\n",26612661+ (int)BT_Block, i);26622662+ BT_Found = 1;26632663+ *Page = i;26642664+ g_cBlockTableStatus =26652665+ CURRENT_BLOCK_TABLE;26662666+ break;26672667+ } else {26682668+ Result = FAIL;26692669+ }26702670+ }26712671+ }26722672+ }26732673+26742674+ if (search_in_previous_pages)26752675+ i = i - bt_pages;26762676+ else26772677+ i = i - (bt_pages + 1);26782678+26792679+ Result = PASS;26802680+26812681+ nand_dbg_print(NAND_DBG_DEBUG,26822682+ "Reading the spare area of Block %d Page %d",26832683+ (int)BT_Block, i);26842684+26852685+ Result = GLOB_LLD_Read_Page_Spare(pSpareBuf, BT_Block, i, 1);26862686+ nand_dbg_print(NAND_DBG_DEBUG,26872687+ "Reading the spare area of Block %u Page %u",26882688+ (unsigned int)BT_Block, i + bt_pages - 1);26892689+26902690+ Result = GLOB_LLD_Read_Page_Spare(pSpareBufBTLastPage,26912691+ BT_Block, i + bt_pages - 1, 1);26922692+26932693+ k = 0;26942694+ j = FTL_Extract_Block_Table_Tag(pSpareBuf, &tagarray);26952695+ if (j) {26962696+ for (; k < j; k++) {26972697+ if (tagarray[k] == BT_Tag)26982698+ break;26992699+ }27002700+ }27012701+27022702+ if (k < j)27032703+ bt_flag = tagarray[k];27042704+ else27052705+ Result = FAIL;27062706+27072707+ if (Result == PASS) {27082708+ k = 0;27092709+ j = FTL_Extract_Block_Table_Tag(pSpareBufBTLastPage,27102710+ &tagarray);27112711+ if (j) {27122712+ for (; k < j; k++) {27132713+ if (tagarray[k] == BT_Tag)27142714+ break;27152715+ }27162716+ }27172717+27182718+ if (k < j) {27192719+ bt_flag_last_page = tagarray[k];27202720+ } else {27212721+ Result = FAIL;27222722+ break;27232723+ }27242724+27252725+ if (Result == PASS) {27262726+ if (bt_flag == bt_flag_last_page) {27272727+ nand_dbg_print(NAND_DBG_DEBUG,27282728+ "Block table is found "27292729+ "in page prior to IPF "27302730+ "at block %u page %d\n",27312731+ (unsigned int)BT_Block, i);27322732+ BT_Found = 1;27332733+ *Page = i;27342734+ g_cBlockTableStatus =27352735+ IN_PROGRESS_BLOCK_TABLE;27362736+ break;27372737+ } else {27382738+ Result = FAIL;27392739+ break;27402740+ }27412741+ }27422742+ }27432743+ }27442744+27452745+ if (Result == FAIL) {27462746+ if ((Last_IPF > bt_pages) && (i < Last_IPF) && (!BT_Found)) {27472747+ BT_Found = 1;27482748+ *Page = i - (bt_pages + 1);27492749+ }27502750+ if ((Last_IPF == bt_pages) && (i < Last_IPF) && (!BT_Found))27512751+ goto func_return;27522752+ }27532753+27542754+ if (Last_IPF == 0) {27552755+ i = 0;27562756+ Result = PASS;27572757+ nand_dbg_print(NAND_DBG_DEBUG, "Reading the spare area of "27582758+ "Block %u Page %u", (unsigned int)BT_Block, i);27592759+27602760+ Result = GLOB_LLD_Read_Page_Spare(pSpareBuf, BT_Block, i, 1);27612761+ nand_dbg_print(NAND_DBG_DEBUG,27622762+ "Reading the spare area of Block %u Page %u",27632763+ (unsigned int)BT_Block, i + bt_pages - 1);27642764+ Result = GLOB_LLD_Read_Page_Spare(pSpareBufBTLastPage,27652765+ BT_Block, i + bt_pages - 1, 1);27662766+27672767+ k = 0;27682768+ j = FTL_Extract_Block_Table_Tag(pSpareBuf, &tagarray);27692769+ if (j) {27702770+ for (; k < j; k++) {27712771+ if (tagarray[k] == BT_Tag)27722772+ break;27732773+ }27742774+ }27752775+27762776+ if (k < j)27772777+ bt_flag = tagarray[k];27782778+ else27792779+ Result = FAIL;27802780+27812781+ if (Result == PASS) {27822782+ k = 0;27832783+ j = FTL_Extract_Block_Table_Tag(pSpareBufBTLastPage,27842784+ &tagarray);27852785+ if (j) {27862786+ for (; k < j; k++) {27872787+ if (tagarray[k] == BT_Tag)27882788+ break;27892789+ }27902790+ }27912791+27922792+ if (k < j)27932793+ bt_flag_last_page = tagarray[k];27942794+ else27952795+ Result = FAIL;27962796+27972797+ if (Result == PASS) {27982798+ if (bt_flag == bt_flag_last_page) {27992799+ nand_dbg_print(NAND_DBG_DEBUG,28002800+ "Block table is found "28012801+ "in page after IPF at "28022802+ "block %u page %u\n",28032803+ (unsigned int)BT_Block,28042804+ (unsigned int)i);28052805+ BT_Found = 1;28062806+ *Page = i;28072807+ g_cBlockTableStatus =28082808+ CURRENT_BLOCK_TABLE;28092809+ goto func_return;28102810+ } else {28112811+ Result = FAIL;28122812+ }28132813+ }28142814+ }28152815+28162816+ if (Result == FAIL)28172817+ goto func_return;28182818+ }28192819+func_return:28202820+ return Result;28212821+}28222822+28232823+u8 *get_blk_table_start_addr(void)28242824+{28252825+ return g_pBlockTable;28262826+}28272827+28282828+unsigned long get_blk_table_len(void)28292829+{28302830+ return DeviceInfo.wDataBlockNum * sizeof(u32);28312831+}28322832+28332833+u8 *get_wear_leveling_table_start_addr(void)28342834+{28352835+ return g_pWearCounter;28362836+}28372837+28382838+unsigned long get_wear_leveling_table_len(void)28392839+{28402840+ return DeviceInfo.wDataBlockNum * sizeof(u8);28412841+}28422842+28432843+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&28442844+* Function: FTL_Read_Block_Table28452845+* Inputs: none28462846+* Outputs: PASS / FAIL28472847+* Description: read the flash spare area and find a block containing the28482848+* most recent block table(having largest block_table_counter).28492849+* Find the last written Block table in this block.28502850+* Check the correctness of Block Table28512851+* If CDMA is enabled, this function is called in28522852+* polling mode.28532853+* We don't need to store changes in Block table in this28542854+* function as it is called only at initialization28552855+*28562856+* Note: Currently this function is called at initialization28572857+* before any read/erase/write command issued to flash so,28582858+* there is no need to wait for CDMA list to complete as of now28592859+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/28602860+static int FTL_Read_Block_Table(void)28612861+{28622862+ u16 i = 0;28632863+ int k, j;28642864+ u8 *tempBuf, *tagarray;28652865+ int wResult = FAIL;28662866+ int status = FAIL;28672867+ u8 block_table_found = 0;28682868+ int search_result;28692869+ u32 Block;28702870+ u16 Page = 0;28712871+ u16 PageCount;28722872+ u16 bt_pages;28732873+ int wBytesCopied = 0, tempvar;28742874+28752875+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",28762876+ __FILE__, __LINE__, __func__);28772877+28782878+ tempBuf = tmp_buf1_read_blk_table;28792879+ bt_pages = FTL_Get_Block_Table_Flash_Size_Pages();28802880+28812881+ for (j = DeviceInfo.wSpectraStartBlock;28822882+ j <= (int)DeviceInfo.wSpectraEndBlock;28832883+ j++) {28842884+ status = GLOB_LLD_Read_Page_Spare(tempBuf, j, 0, 1);28852885+ k = 0;28862886+ i = FTL_Extract_Block_Table_Tag(tempBuf, &tagarray);28872887+ if (i) {28882888+ status = GLOB_LLD_Read_Page_Main_Polling(tempBuf,28892889+ j, 0, 1);28902890+ for (; k < i; k++) {28912891+ if (tagarray[k] == tempBuf[3])28922892+ break;28932893+ }28942894+ }28952895+28962896+ if (k < i)28972897+ k = tagarray[k];28982898+ else28992899+ continue;29002900+29012901+ nand_dbg_print(NAND_DBG_DEBUG,29022902+ "Block table is contained in Block %d %d\n",29032903+ (unsigned int)j, (unsigned int)k);29042904+29052905+ if (g_pBTBlocks[k-FIRST_BT_ID] == BTBLOCK_INVAL) {29062906+ g_pBTBlocks[k-FIRST_BT_ID] = j;29072907+ block_table_found = 1;29082908+ } else {29092909+ printk(KERN_ERR "FTL_Read_Block_Table -"29102910+ "This should never happens. "29112911+ "Two block table have same counter %u!\n", k);29122912+ }29132913+ }29142914+29152915+ if (block_table_found) {29162916+ if (g_pBTBlocks[FIRST_BT_ID - FIRST_BT_ID] != BTBLOCK_INVAL &&29172917+ g_pBTBlocks[LAST_BT_ID - FIRST_BT_ID] != BTBLOCK_INVAL) {29182918+ j = LAST_BT_ID;29192919+ while ((j > FIRST_BT_ID) &&29202920+ (g_pBTBlocks[j - FIRST_BT_ID] != BTBLOCK_INVAL))29212921+ j--;29222922+ if (j == FIRST_BT_ID) {29232923+ j = LAST_BT_ID;29242924+ last_erased = LAST_BT_ID;29252925+ } else {29262926+ last_erased = (u8)j + 1;29272927+ while ((j > FIRST_BT_ID) && (BTBLOCK_INVAL ==29282928+ g_pBTBlocks[j - FIRST_BT_ID]))29292929+ j--;29302930+ }29312931+ } else {29322932+ j = FIRST_BT_ID;29332933+ while (g_pBTBlocks[j - FIRST_BT_ID] == BTBLOCK_INVAL)29342934+ j++;29352935+ last_erased = (u8)j;29362936+ while ((j < LAST_BT_ID) && (BTBLOCK_INVAL !=29372937+ g_pBTBlocks[j - FIRST_BT_ID]))29382938+ j++;29392939+ if (g_pBTBlocks[j-FIRST_BT_ID] == BTBLOCK_INVAL)29402940+ j--;29412941+ }29422942+29432943+ if (last_erased > j)29442944+ j += (1 + LAST_BT_ID - FIRST_BT_ID);29452945+29462946+ for (; (j >= last_erased) && (FAIL == wResult); j--) {29472947+ i = (j - FIRST_BT_ID) %29482948+ (1 + LAST_BT_ID - FIRST_BT_ID);29492949+ search_result =29502950+ FTL_Search_Block_Table_IN_Block(g_pBTBlocks[i],29512951+ i + FIRST_BT_ID, &Page);29522952+ if (g_cBlockTableStatus == IN_PROGRESS_BLOCK_TABLE)29532953+ block_table_found = 0;29542954+29552955+ while ((search_result == PASS) && (FAIL == wResult)) {29562956+ nand_dbg_print(NAND_DBG_DEBUG,29572957+ "FTL_Read_Block_Table:"29582958+ "Block: %u Page: %u "29592959+ "contains block table\n",29602960+ (unsigned int)g_pBTBlocks[i],29612961+ (unsigned int)Page);29622962+29632963+ tempBuf = tmp_buf2_read_blk_table;29642964+29652965+ for (k = 0; k < bt_pages; k++) {29662966+ Block = g_pBTBlocks[i];29672967+ PageCount = 1;29682968+29692969+ status =29702970+ GLOB_LLD_Read_Page_Main_Polling(29712971+ tempBuf, Block, Page, PageCount);29722972+29732973+ tempvar = k ? 0 : 4;29742974+29752975+ wBytesCopied +=29762976+ FTL_Copy_Block_Table_From_Flash(29772977+ tempBuf + tempvar,29782978+ DeviceInfo.wPageDataSize - tempvar,29792979+ wBytesCopied);29802980+29812981+ Page++;29822982+ }29832983+29842984+ wResult = FTL_Check_Block_Table(FAIL);29852985+ if (FAIL == wResult) {29862986+ block_table_found = 0;29872987+ if (Page > bt_pages)29882988+ Page -= ((bt_pages<<1) + 1);29892989+ else29902990+ search_result = FAIL;29912991+ }29922992+ }29932993+ }29942994+ }29952995+29962996+ if (PASS == wResult) {29972997+ if (!block_table_found)29982998+ FTL_Execute_SPL_Recovery();29992999+30003000+ if (g_cBlockTableStatus == IN_PROGRESS_BLOCK_TABLE)30013001+ g_wBlockTableOffset = (u16)Page + 1;30023002+ else30033003+ g_wBlockTableOffset = (u16)Page - bt_pages;30043004+30053005+ g_wBlockTableIndex = (u32)g_pBTBlocks[i];30063006+30073007+#if CMD_DMA30083008+ if (DeviceInfo.MLCDevice)30093009+ memcpy(g_pBTStartingCopy, g_pBlockTable,30103010+ DeviceInfo.wDataBlockNum * sizeof(u32)30113011+ + DeviceInfo.wDataBlockNum * sizeof(u8)30123012+ + DeviceInfo.wDataBlockNum * sizeof(u16));30133013+ else30143014+ memcpy(g_pBTStartingCopy, g_pBlockTable,30153015+ DeviceInfo.wDataBlockNum * sizeof(u32)30163016+ + DeviceInfo.wDataBlockNum * sizeof(u8));30173017+#endif30183018+ }30193019+30203020+ if (FAIL == wResult)30213021+ printk(KERN_ERR "Yunpeng - "30223022+ "Can not find valid spectra block table!\n");30233023+30243024+#if AUTO_FORMAT_FLASH30253025+ if (FAIL == wResult) {30263026+ nand_dbg_print(NAND_DBG_DEBUG, "doing auto-format\n");30273027+ wResult = FTL_Format_Flash(0);30283028+ }30293029+#endif30303030+30313031+ return wResult;30323032+}30333033+30343034+30353035+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&30363036+* Function: FTL_Flash_Error_Handle30373037+* Inputs: Pointer to data30383038+* Page address30393039+* Block address30403040+* Outputs: PASS=0 / FAIL=130413041+* Description: It handles any error occured during Spectra operation30423042+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/30433043+static int FTL_Flash_Error_Handle(u8 *pData, u64 old_page_addr,30443044+ u64 blk_addr)30453045+{30463046+ u32 i;30473047+ int j;30483048+ u32 tmp_node, blk_node = BLK_FROM_ADDR(blk_addr);30493049+ u64 phy_addr;30503050+ int wErase = FAIL;30513051+ int wResult = FAIL;30523052+ u32 *pbt = (u32 *)g_pBlockTable;30533053+30543054+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",30553055+ __FILE__, __LINE__, __func__);30563056+30573057+ if (ERR == GLOB_FTL_Garbage_Collection())30583058+ return ERR;30593059+30603060+ do {30613061+ for (i = DeviceInfo.wSpectraEndBlock -30623062+ DeviceInfo.wSpectraStartBlock;30633063+ i > 0; i--) {30643064+ if (IS_SPARE_BLOCK(i)) {30653065+ tmp_node = (u32)(BAD_BLOCK |30663066+ pbt[blk_node]);30673067+ pbt[blk_node] = (u32)(pbt[i] &30683068+ (~SPARE_BLOCK));30693069+ pbt[i] = tmp_node;30703070+#if CMD_DMA30713071+ p_BTableChangesDelta =30723072+ (struct BTableChangesDelta *)30733073+ g_pBTDelta_Free;30743074+ g_pBTDelta_Free +=30753075+ sizeof(struct BTableChangesDelta);30763076+30773077+ p_BTableChangesDelta->ftl_cmd_cnt =30783078+ ftl_cmd_cnt;30793079+ p_BTableChangesDelta->BT_Index =30803080+ blk_node;30813081+ p_BTableChangesDelta->BT_Entry_Value =30823082+ pbt[blk_node];30833083+ p_BTableChangesDelta->ValidFields = 0x0C;30843084+30853085+ p_BTableChangesDelta =30863086+ (struct BTableChangesDelta *)30873087+ g_pBTDelta_Free;30883088+ g_pBTDelta_Free +=30893089+ sizeof(struct BTableChangesDelta);30903090+30913091+ p_BTableChangesDelta->ftl_cmd_cnt =30923092+ ftl_cmd_cnt;30933093+ p_BTableChangesDelta->BT_Index = i;30943094+ p_BTableChangesDelta->BT_Entry_Value = pbt[i];30953095+ p_BTableChangesDelta->ValidFields = 0x0C;30963096+#endif30973097+ wResult = PASS;30983098+ break;30993099+ }31003100+ }31013101+31023102+ if (FAIL == wResult) {31033103+ if (FAIL == GLOB_FTL_Garbage_Collection())31043104+ break;31053105+ else31063106+ continue;31073107+ }31083108+31093109+ if (IN_PROGRESS_BLOCK_TABLE != g_cBlockTableStatus) {31103110+ g_cBlockTableStatus = IN_PROGRESS_BLOCK_TABLE;31113111+ FTL_Write_IN_Progress_Block_Table_Page();31123112+ }31133113+31143114+ phy_addr = FTL_Get_Physical_Block_Addr(blk_addr);31153115+31163116+ for (j = 0; j < RETRY_TIMES; j++) {31173117+ if (PASS == wErase) {31183118+ if (FAIL == GLOB_FTL_Block_Erase(phy_addr)) {31193119+ MARK_BLOCK_AS_BAD(pbt[blk_node]);31203120+ break;31213121+ }31223122+ }31233123+ if (PASS == FTL_Cache_Update_Block(pData,31243124+ old_page_addr,31253125+ phy_addr)) {31263126+ wResult = PASS;31273127+ break;31283128+ } else {31293129+ wResult = FAIL;31303130+ wErase = PASS;31313131+ }31323132+ }31333133+ } while (FAIL == wResult);31343134+31353135+ FTL_Write_Block_Table(FAIL);31363136+31373137+ return wResult;31383138+}31393139+31403140+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&31413141+* Function: FTL_Get_Page_Num31423142+* Inputs: Size in bytes31433143+* Outputs: Size in pages31443144+* Description: It calculates the pages required for the length passed31453145+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/31463146+static u32 FTL_Get_Page_Num(u64 length)31473147+{31483148+ return (u32)((length >> DeviceInfo.nBitsInPageDataSize) +31493149+ (GLOB_u64_Remainder(length , 1) > 0 ? 1 : 0));31503150+}31513151+31523152+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&31533153+* Function: FTL_Get_Physical_Block_Addr31543154+* Inputs: Block Address (byte format)31553155+* Outputs: Physical address of the block.31563156+* Description: It translates LBA to PBA by returning address stored31573157+* at the LBA location in the block table31583158+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/31593159+static u64 FTL_Get_Physical_Block_Addr(u64 logical_addr)31603160+{31613161+ u32 *pbt;31623162+ u64 physical_addr;31633163+31643164+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",31653165+ __FILE__, __LINE__, __func__);31663166+31673167+ pbt = (u32 *)g_pBlockTable;31683168+ physical_addr = (u64) DeviceInfo.wBlockDataSize *31693169+ (pbt[BLK_FROM_ADDR(logical_addr)] & (~BAD_BLOCK));31703170+31713171+ return physical_addr;31723172+}31733173+31743174+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&31753175+* Function: FTL_Get_Block_Index31763176+* Inputs: Physical Block no.31773177+* Outputs: Logical block no. /BAD_BLOCK31783178+* Description: It returns the logical block no. for the PBA passed31793179+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/31803180+static u32 FTL_Get_Block_Index(u32 wBlockNum)31813181+{31823182+ u32 *pbt = (u32 *)g_pBlockTable;31833183+ u32 i;31843184+31853185+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",31863186+ __FILE__, __LINE__, __func__);31873187+31883188+ for (i = 0; i < DeviceInfo.wDataBlockNum; i++)31893189+ if (wBlockNum == (pbt[i] & (~BAD_BLOCK)))31903190+ return i;31913191+31923192+ return BAD_BLOCK;31933193+}31943194+31953195+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&31963196+* Function: GLOB_FTL_Wear_Leveling31973197+* Inputs: none31983198+* Outputs: PASS=031993199+* Description: This is static wear leveling (done by explicit call)32003200+* do complete static wear leveling32013201+* do complete garbage collection32023202+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/32033203+int GLOB_FTL_Wear_Leveling(void)32043204+{32053205+ nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n",32063206+ __FILE__, __LINE__, __func__);32073207+32083208+ FTL_Static_Wear_Leveling();32093209+ GLOB_FTL_Garbage_Collection();32103210+32113211+ return PASS;32123212+}32133213+32143214+static void find_least_most_worn(u8 *chg,32153215+ u32 *least_idx, u8 *least_cnt,32163216+ u32 *most_idx, u8 *most_cnt)32173217+{32183218+ u32 *pbt = (u32 *)g_pBlockTable;32193219+ u32 idx;32203220+ u8 cnt;32213221+ int i;32223222+32233223+ for (i = BLOCK_TABLE_INDEX + 1; i < DeviceInfo.wDataBlockNum; i++) {32243224+ if (IS_BAD_BLOCK(i) || PASS == chg[i])32253225+ continue;32263226+32273227+ idx = (u32) ((~BAD_BLOCK) & pbt[i]);32283228+ cnt = g_pWearCounter[idx - DeviceInfo.wSpectraStartBlock];32293229+32303230+ if (IS_SPARE_BLOCK(i)) {32313231+ if (cnt > *most_cnt) {32323232+ *most_cnt = cnt;32333233+ *most_idx = idx;32343234+ }32353235+ }32363236+32373237+ if (IS_DATA_BLOCK(i)) {32383238+ if (cnt < *least_cnt) {32393239+ *least_cnt = cnt;32403240+ *least_idx = idx;32413241+ }32423242+ }32433243+32443244+ if (PASS == chg[*most_idx] || PASS == chg[*least_idx]) {32453245+ debug_boundary_error(*most_idx,32463246+ DeviceInfo.wDataBlockNum, 0);32473247+ debug_boundary_error(*least_idx,32483248+ DeviceInfo.wDataBlockNum, 0);32493249+ continue;32503250+ }32513251+ }32523252+}32533253+32543254+static int move_blks_for_wear_leveling(u8 *chg,32553255+ u32 *least_idx, u32 *rep_blk_num, int *result)32563256+{32573257+ u32 *pbt = (u32 *)g_pBlockTable;32583258+ u32 rep_blk;32593259+ int j, ret_cp_blk, ret_erase;32603260+ int ret = PASS;32613261+32623262+ chg[*least_idx] = PASS;32633263+ debug_boundary_error(*least_idx, DeviceInfo.wDataBlockNum, 0);32643264+32653265+ rep_blk = FTL_Replace_MWBlock();32663266+ if (rep_blk != BAD_BLOCK) {32673267+ nand_dbg_print(NAND_DBG_DEBUG,32683268+ "More than two spare blocks exist so do it\n");32693269+ nand_dbg_print(NAND_DBG_DEBUG, "Block Replaced is %d\n",32703270+ rep_blk);32713271+32723272+ chg[rep_blk] = PASS;32733273+32743274+ if (IN_PROGRESS_BLOCK_TABLE != g_cBlockTableStatus) {32753275+ g_cBlockTableStatus = IN_PROGRESS_BLOCK_TABLE;32763276+ FTL_Write_IN_Progress_Block_Table_Page();32773277+ }32783278+32793279+ for (j = 0; j < RETRY_TIMES; j++) {32803280+ ret_cp_blk = FTL_Copy_Block((u64)(*least_idx) *32813281+ DeviceInfo.wBlockDataSize,32823282+ (u64)rep_blk * DeviceInfo.wBlockDataSize);32833283+ if (FAIL == ret_cp_blk) {32843284+ ret_erase = GLOB_FTL_Block_Erase((u64)rep_blk32853285+ * DeviceInfo.wBlockDataSize);32863286+ if (FAIL == ret_erase)32873287+ MARK_BLOCK_AS_BAD(pbt[rep_blk]);32883288+ } else {32893289+ nand_dbg_print(NAND_DBG_DEBUG,32903290+ "FTL_Copy_Block == OK\n");32913291+ break;32923292+ }32933293+ }32943294+32953295+ if (j < RETRY_TIMES) {32963296+ u32 tmp;32973297+ u32 old_idx = FTL_Get_Block_Index(*least_idx);32983298+ u32 rep_idx = FTL_Get_Block_Index(rep_blk);32993299+ tmp = (u32)(DISCARD_BLOCK | pbt[old_idx]);33003300+ pbt[old_idx] = (u32)((~SPARE_BLOCK) &33013301+ pbt[rep_idx]);33023302+ pbt[rep_idx] = tmp;33033303+#if CMD_DMA33043304+ p_BTableChangesDelta = (struct BTableChangesDelta *)33053305+ g_pBTDelta_Free;33063306+ g_pBTDelta_Free += sizeof(struct BTableChangesDelta);33073307+ p_BTableChangesDelta->ftl_cmd_cnt =33083308+ ftl_cmd_cnt;33093309+ p_BTableChangesDelta->BT_Index = old_idx;33103310+ p_BTableChangesDelta->BT_Entry_Value = pbt[old_idx];33113311+ p_BTableChangesDelta->ValidFields = 0x0C;33123312+33133313+ p_BTableChangesDelta = (struct BTableChangesDelta *)33143314+ g_pBTDelta_Free;33153315+ g_pBTDelta_Free += sizeof(struct BTableChangesDelta);33163316+33173317+ p_BTableChangesDelta->ftl_cmd_cnt =33183318+ ftl_cmd_cnt;33193319+ p_BTableChangesDelta->BT_Index = rep_idx;33203320+ p_BTableChangesDelta->BT_Entry_Value = pbt[rep_idx];33213321+ p_BTableChangesDelta->ValidFields = 0x0C;33223322+#endif33233323+ } else {33243324+ pbt[FTL_Get_Block_Index(rep_blk)] |= BAD_BLOCK;33253325+#if CMD_DMA33263326+ p_BTableChangesDelta = (struct BTableChangesDelta *)33273327+ g_pBTDelta_Free;33283328+ g_pBTDelta_Free += sizeof(struct BTableChangesDelta);33293329+33303330+ p_BTableChangesDelta->ftl_cmd_cnt =33313331+ ftl_cmd_cnt;33323332+ p_BTableChangesDelta->BT_Index =33333333+ FTL_Get_Block_Index(rep_blk);33343334+ p_BTableChangesDelta->BT_Entry_Value =33353335+ pbt[FTL_Get_Block_Index(rep_blk)];33363336+ p_BTableChangesDelta->ValidFields = 0x0C;33373337+#endif33383338+ *result = FAIL;33393339+ ret = FAIL;33403340+ }33413341+33423342+ if (((*rep_blk_num)++) > WEAR_LEVELING_BLOCK_NUM)33433343+ ret = FAIL;33443344+ } else {33453345+ printk(KERN_ERR "Less than 3 spare blocks exist so quit\n");33463346+ ret = FAIL;33473347+ }33483348+33493349+ return ret;33503350+}33513351+33523352+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&33533353+* Function: FTL_Static_Wear_Leveling33543354+* Inputs: none33553355+* Outputs: PASS=0 / FAIL=133563356+* Description: This is static wear leveling (done by explicit call)33573357+* search for most&least used33583358+* if difference < GATE:33593359+* update the block table with exhange33603360+* mark block table in flash as IN_PROGRESS33613361+* copy flash block33623362+* the caller should handle GC clean up after calling this function33633363+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/33643364+int FTL_Static_Wear_Leveling(void)33653365+{33663366+ u8 most_worn_cnt;33673367+ u8 least_worn_cnt;33683368+ u32 most_worn_idx;33693369+ u32 least_worn_idx;33703370+ int result = PASS;33713371+ int go_on = PASS;33723372+ u32 replaced_blks = 0;33733373+ u8 *chang_flag = flags_static_wear_leveling;33743374+33753375+ nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n",33763376+ __FILE__, __LINE__, __func__);33773377+33783378+ if (!chang_flag)33793379+ return FAIL;33803380+33813381+ memset(chang_flag, FAIL, DeviceInfo.wDataBlockNum);33823382+ while (go_on == PASS) {33833383+ nand_dbg_print(NAND_DBG_DEBUG,33843384+ "starting static wear leveling\n");33853385+ most_worn_cnt = 0;33863386+ least_worn_cnt = 0xFF;33873387+ least_worn_idx = BLOCK_TABLE_INDEX;33883388+ most_worn_idx = BLOCK_TABLE_INDEX;33893389+33903390+ find_least_most_worn(chang_flag, &least_worn_idx,33913391+ &least_worn_cnt, &most_worn_idx, &most_worn_cnt);33923392+33933393+ nand_dbg_print(NAND_DBG_DEBUG,33943394+ "Used and least worn is block %u, whos count is %u\n",33953395+ (unsigned int)least_worn_idx,33963396+ (unsigned int)least_worn_cnt);33973397+33983398+ nand_dbg_print(NAND_DBG_DEBUG,33993399+ "Free and most worn is block %u, whos count is %u\n",34003400+ (unsigned int)most_worn_idx,34013401+ (unsigned int)most_worn_cnt);34023402+34033403+ if ((most_worn_cnt > least_worn_cnt) &&34043404+ (most_worn_cnt - least_worn_cnt > WEAR_LEVELING_GATE))34053405+ go_on = move_blks_for_wear_leveling(chang_flag,34063406+ &least_worn_idx, &replaced_blks, &result);34073407+ else34083408+ go_on = FAIL;34093409+ }34103410+34113411+ return result;34123412+}34133413+34143414+#if CMD_DMA34153415+static int do_garbage_collection(u32 discard_cnt)34163416+{34173417+ u32 *pbt = (u32 *)g_pBlockTable;34183418+ u32 pba;34193419+ u8 bt_block_erased = 0;34203420+ int i, cnt, ret = FAIL;34213421+ u64 addr;34223422+34233423+ i = 0;34243424+ while ((i < DeviceInfo.wDataBlockNum) && (discard_cnt > 0) &&34253425+ ((ftl_cmd_cnt + 28) < 256)) {34263426+ if (((pbt[i] & BAD_BLOCK) != BAD_BLOCK) &&34273427+ (pbt[i] & DISCARD_BLOCK)) {34283428+ if (IN_PROGRESS_BLOCK_TABLE != g_cBlockTableStatus) {34293429+ g_cBlockTableStatus = IN_PROGRESS_BLOCK_TABLE;34303430+ FTL_Write_IN_Progress_Block_Table_Page();34313431+ }34323432+34333433+ addr = FTL_Get_Physical_Block_Addr((u64)i *34343434+ DeviceInfo.wBlockDataSize);34353435+ pba = BLK_FROM_ADDR(addr);34363436+34373437+ for (cnt = FIRST_BT_ID; cnt <= LAST_BT_ID; cnt++) {34383438+ if (pba == g_pBTBlocks[cnt - FIRST_BT_ID]) {34393439+ nand_dbg_print(NAND_DBG_DEBUG,34403440+ "GC will erase BT block %u\n",34413441+ (unsigned int)pba);34423442+ discard_cnt--;34433443+ i++;34443444+ bt_block_erased = 1;34453445+ break;34463446+ }34473447+ }34483448+34493449+ if (bt_block_erased) {34503450+ bt_block_erased = 0;34513451+ continue;34523452+ }34533453+34543454+ addr = FTL_Get_Physical_Block_Addr((u64)i *34553455+ DeviceInfo.wBlockDataSize);34563456+34573457+ if (PASS == GLOB_FTL_Block_Erase(addr)) {34583458+ pbt[i] &= (u32)(~DISCARD_BLOCK);34593459+ pbt[i] |= (u32)(SPARE_BLOCK);34603460+ p_BTableChangesDelta =34613461+ (struct BTableChangesDelta *)34623462+ g_pBTDelta_Free;34633463+ g_pBTDelta_Free +=34643464+ sizeof(struct BTableChangesDelta);34653465+ p_BTableChangesDelta->ftl_cmd_cnt =34663466+ ftl_cmd_cnt - 1;34673467+ p_BTableChangesDelta->BT_Index = i;34683468+ p_BTableChangesDelta->BT_Entry_Value = pbt[i];34693469+ p_BTableChangesDelta->ValidFields = 0x0C;34703470+ discard_cnt--;34713471+ ret = PASS;34723472+ } else {34733473+ MARK_BLOCK_AS_BAD(pbt[i]);34743474+ }34753475+ }34763476+34773477+ i++;34783478+ }34793479+34803480+ return ret;34813481+}34823482+34833483+#else34843484+static int do_garbage_collection(u32 discard_cnt)34853485+{34863486+ u32 *pbt = (u32 *)g_pBlockTable;34873487+ u32 pba;34883488+ u8 bt_block_erased = 0;34893489+ int i, cnt, ret = FAIL;34903490+ u64 addr;34913491+34923492+ i = 0;34933493+ while ((i < DeviceInfo.wDataBlockNum) && (discard_cnt > 0)) {34943494+ if (((pbt[i] & BAD_BLOCK) != BAD_BLOCK) &&34953495+ (pbt[i] & DISCARD_BLOCK)) {34963496+ if (IN_PROGRESS_BLOCK_TABLE != g_cBlockTableStatus) {34973497+ g_cBlockTableStatus = IN_PROGRESS_BLOCK_TABLE;34983498+ FTL_Write_IN_Progress_Block_Table_Page();34993499+ }35003500+35013501+ addr = FTL_Get_Physical_Block_Addr((u64)i *35023502+ DeviceInfo.wBlockDataSize);35033503+ pba = BLK_FROM_ADDR(addr);35043504+35053505+ for (cnt = FIRST_BT_ID; cnt <= LAST_BT_ID; cnt++) {35063506+ if (pba == g_pBTBlocks[cnt - FIRST_BT_ID]) {35073507+ nand_dbg_print(NAND_DBG_DEBUG,35083508+ "GC will erase BT block %d\n",35093509+ pba);35103510+ discard_cnt--;35113511+ i++;35123512+ bt_block_erased = 1;35133513+ break;35143514+ }35153515+ }35163516+35173517+ if (bt_block_erased) {35183518+ bt_block_erased = 0;35193519+ continue;35203520+ }35213521+35223522+ /* If the discard block is L2 cache block, then just skip it */35233523+ for (cnt = 0; cnt < BLK_NUM_FOR_L2_CACHE; cnt++) {35243524+ if (cache_l2.blk_array[cnt] == pba) {35253525+ nand_dbg_print(NAND_DBG_DEBUG,35263526+ "GC will erase L2 cache blk %d\n",35273527+ pba);35283528+ break;35293529+ }35303530+ }35313531+ if (cnt < BLK_NUM_FOR_L2_CACHE) { /* Skip it */35323532+ discard_cnt--;35333533+ i++;35343534+ continue;35353535+ }35363536+35373537+ addr = FTL_Get_Physical_Block_Addr((u64)i *35383538+ DeviceInfo.wBlockDataSize);35393539+35403540+ if (PASS == GLOB_FTL_Block_Erase(addr)) {35413541+ pbt[i] &= (u32)(~DISCARD_BLOCK);35423542+ pbt[i] |= (u32)(SPARE_BLOCK);35433543+ discard_cnt--;35443544+ ret = PASS;35453545+ } else {35463546+ MARK_BLOCK_AS_BAD(pbt[i]);35473547+ }35483548+ }35493549+35503550+ i++;35513551+ }35523552+35533553+ return ret;35543554+}35553555+#endif35563556+35573557+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&35583558+* Function: GLOB_FTL_Garbage_Collection35593559+* Inputs: none35603560+* Outputs: PASS / FAIL (returns the number of un-erased blocks35613561+* Description: search the block table for all discarded blocks to erase35623562+* for each discarded block:35633563+* set the flash block to IN_PROGRESS35643564+* erase the block35653565+* update the block table35663566+* write the block table to flash35673567+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/35683568+int GLOB_FTL_Garbage_Collection(void)35693569+{35703570+ u32 i;35713571+ u32 wDiscard = 0;35723572+ int wResult = FAIL;35733573+ u32 *pbt = (u32 *)g_pBlockTable;35743574+35753575+ nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n",35763576+ __FILE__, __LINE__, __func__);35773577+35783578+ if (GC_Called) {35793579+ printk(KERN_ALERT "GLOB_FTL_Garbage_Collection() "35803580+ "has been re-entered! Exit.\n");35813581+ return PASS;35823582+ }35833583+35843584+ GC_Called = 1;35853585+35863586+ GLOB_FTL_BT_Garbage_Collection();35873587+35883588+ for (i = 0; i < DeviceInfo.wDataBlockNum; i++) {35893589+ if (IS_DISCARDED_BLOCK(i))35903590+ wDiscard++;35913591+ }35923592+35933593+ if (wDiscard <= 0) {35943594+ GC_Called = 0;35953595+ return wResult;35963596+ }35973597+35983598+ nand_dbg_print(NAND_DBG_DEBUG,35993599+ "Found %d discarded blocks\n", wDiscard);36003600+36013601+ FTL_Write_Block_Table(FAIL);36023602+36033603+ wResult = do_garbage_collection(wDiscard);36043604+36053605+ FTL_Write_Block_Table(FAIL);36063606+36073607+ GC_Called = 0;36083608+36093609+ return wResult;36103610+}36113611+36123612+36133613+#if CMD_DMA36143614+static int do_bt_garbage_collection(void)36153615+{36163616+ u32 pba, lba;36173617+ u32 *pbt = (u32 *)g_pBlockTable;36183618+ u32 *pBTBlocksNode = (u32 *)g_pBTBlocks;36193619+ u64 addr;36203620+ int i, ret = FAIL;36213621+36223622+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",36233623+ __FILE__, __LINE__, __func__);36243624+36253625+ if (BT_GC_Called)36263626+ return PASS;36273627+36283628+ BT_GC_Called = 1;36293629+36303630+ for (i = last_erased; (i <= LAST_BT_ID) &&36313631+ (g_pBTBlocks[((i + 2) % (1 + LAST_BT_ID - FIRST_BT_ID)) +36323632+ FIRST_BT_ID - FIRST_BT_ID] != BTBLOCK_INVAL) &&36333633+ ((ftl_cmd_cnt + 28)) < 256; i++) {36343634+ pba = pBTBlocksNode[i - FIRST_BT_ID];36353635+ lba = FTL_Get_Block_Index(pba);36363636+ nand_dbg_print(NAND_DBG_DEBUG,36373637+ "do_bt_garbage_collection: pba %d, lba %d\n",36383638+ pba, lba);36393639+ nand_dbg_print(NAND_DBG_DEBUG,36403640+ "Block Table Entry: %d", pbt[lba]);36413641+36423642+ if (((pbt[lba] & BAD_BLOCK) != BAD_BLOCK) &&36433643+ (pbt[lba] & DISCARD_BLOCK)) {36443644+ nand_dbg_print(NAND_DBG_DEBUG,36453645+ "do_bt_garbage_collection_cdma: "36463646+ "Erasing Block tables present in block %d\n",36473647+ pba);36483648+ addr = FTL_Get_Physical_Block_Addr((u64)lba *36493649+ DeviceInfo.wBlockDataSize);36503650+ if (PASS == GLOB_FTL_Block_Erase(addr)) {36513651+ pbt[lba] &= (u32)(~DISCARD_BLOCK);36523652+ pbt[lba] |= (u32)(SPARE_BLOCK);36533653+36543654+ p_BTableChangesDelta =36553655+ (struct BTableChangesDelta *)36563656+ g_pBTDelta_Free;36573657+ g_pBTDelta_Free +=36583658+ sizeof(struct BTableChangesDelta);36593659+36603660+ p_BTableChangesDelta->ftl_cmd_cnt =36613661+ ftl_cmd_cnt - 1;36623662+ p_BTableChangesDelta->BT_Index = lba;36633663+ p_BTableChangesDelta->BT_Entry_Value =36643664+ pbt[lba];36653665+36663666+ p_BTableChangesDelta->ValidFields = 0x0C;36673667+36683668+ ret = PASS;36693669+ pBTBlocksNode[last_erased - FIRST_BT_ID] =36703670+ BTBLOCK_INVAL;36713671+ nand_dbg_print(NAND_DBG_DEBUG,36723672+ "resetting bt entry at index %d "36733673+ "value %d\n", i,36743674+ pBTBlocksNode[i - FIRST_BT_ID]);36753675+ if (last_erased == LAST_BT_ID)36763676+ last_erased = FIRST_BT_ID;36773677+ else36783678+ last_erased++;36793679+ } else {36803680+ MARK_BLOCK_AS_BAD(pbt[lba]);36813681+ }36823682+ }36833683+ }36843684+36853685+ BT_GC_Called = 0;36863686+36873687+ return ret;36883688+}36893689+36903690+#else36913691+static int do_bt_garbage_collection(void)36923692+{36933693+ u32 pba, lba;36943694+ u32 *pbt = (u32 *)g_pBlockTable;36953695+ u32 *pBTBlocksNode = (u32 *)g_pBTBlocks;36963696+ u64 addr;36973697+ int i, ret = FAIL;36983698+36993699+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",37003700+ __FILE__, __LINE__, __func__);37013701+37023702+ if (BT_GC_Called)37033703+ return PASS;37043704+37053705+ BT_GC_Called = 1;37063706+37073707+ for (i = last_erased; (i <= LAST_BT_ID) &&37083708+ (g_pBTBlocks[((i + 2) % (1 + LAST_BT_ID - FIRST_BT_ID)) +37093709+ FIRST_BT_ID - FIRST_BT_ID] != BTBLOCK_INVAL); i++) {37103710+ pba = pBTBlocksNode[i - FIRST_BT_ID];37113711+ lba = FTL_Get_Block_Index(pba);37123712+ nand_dbg_print(NAND_DBG_DEBUG,37133713+ "do_bt_garbage_collection_cdma: pba %d, lba %d\n",37143714+ pba, lba);37153715+ nand_dbg_print(NAND_DBG_DEBUG,37163716+ "Block Table Entry: %d", pbt[lba]);37173717+37183718+ if (((pbt[lba] & BAD_BLOCK) != BAD_BLOCK) &&37193719+ (pbt[lba] & DISCARD_BLOCK)) {37203720+ nand_dbg_print(NAND_DBG_DEBUG,37213721+ "do_bt_garbage_collection: "37223722+ "Erasing Block tables present in block %d\n",37233723+ pba);37243724+ addr = FTL_Get_Physical_Block_Addr((u64)lba *37253725+ DeviceInfo.wBlockDataSize);37263726+ if (PASS == GLOB_FTL_Block_Erase(addr)) {37273727+ pbt[lba] &= (u32)(~DISCARD_BLOCK);37283728+ pbt[lba] |= (u32)(SPARE_BLOCK);37293729+ ret = PASS;37303730+ pBTBlocksNode[last_erased - FIRST_BT_ID] =37313731+ BTBLOCK_INVAL;37323732+ nand_dbg_print(NAND_DBG_DEBUG,37333733+ "resetting bt entry at index %d "37343734+ "value %d\n", i,37353735+ pBTBlocksNode[i - FIRST_BT_ID]);37363736+ if (last_erased == LAST_BT_ID)37373737+ last_erased = FIRST_BT_ID;37383738+ else37393739+ last_erased++;37403740+ } else {37413741+ MARK_BLOCK_AS_BAD(pbt[lba]);37423742+ }37433743+ }37443744+ }37453745+37463746+ BT_GC_Called = 0;37473747+37483748+ return ret;37493749+}37503750+37513751+#endif37523752+37533753+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&37543754+* Function: GLOB_FTL_BT_Garbage_Collection37553755+* Inputs: none37563756+* Outputs: PASS / FAIL (returns the number of un-erased blocks37573757+* Description: Erases discarded blocks containing Block table37583758+*37593759+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/37603760+int GLOB_FTL_BT_Garbage_Collection(void)37613761+{37623762+ return do_bt_garbage_collection();37633763+}37643764+37653765+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&37663766+* Function: FTL_Replace_OneBlock37673767+* Inputs: Block number 137683768+* Block number 237693769+* Outputs: Replaced Block Number37703770+* Description: Interchange block table entries at wBlockNum and wReplaceNum37713771+*37723772+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/37733773+static u32 FTL_Replace_OneBlock(u32 blk, u32 rep_blk)37743774+{37753775+ u32 tmp_blk;37763776+ u32 replace_node = BAD_BLOCK;37773777+ u32 *pbt = (u32 *)g_pBlockTable;37783778+37793779+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",37803780+ __FILE__, __LINE__, __func__);37813781+37823782+ if (rep_blk != BAD_BLOCK) {37833783+ if (IS_BAD_BLOCK(blk))37843784+ tmp_blk = pbt[blk];37853785+ else37863786+ tmp_blk = DISCARD_BLOCK | (~SPARE_BLOCK & pbt[blk]);37873787+37883788+ replace_node = (u32) ((~SPARE_BLOCK) & pbt[rep_blk]);37893789+ pbt[blk] = replace_node;37903790+ pbt[rep_blk] = tmp_blk;37913791+37923792+#if CMD_DMA37933793+ p_BTableChangesDelta =37943794+ (struct BTableChangesDelta *)g_pBTDelta_Free;37953795+ g_pBTDelta_Free += sizeof(struct BTableChangesDelta);37963796+37973797+ p_BTableChangesDelta->ftl_cmd_cnt = ftl_cmd_cnt;37983798+ p_BTableChangesDelta->BT_Index = blk;37993799+ p_BTableChangesDelta->BT_Entry_Value = pbt[blk];38003800+38013801+ p_BTableChangesDelta->ValidFields = 0x0C;38023802+38033803+ p_BTableChangesDelta =38043804+ (struct BTableChangesDelta *)g_pBTDelta_Free;38053805+ g_pBTDelta_Free += sizeof(struct BTableChangesDelta);38063806+38073807+ p_BTableChangesDelta->ftl_cmd_cnt = ftl_cmd_cnt;38083808+ p_BTableChangesDelta->BT_Index = rep_blk;38093809+ p_BTableChangesDelta->BT_Entry_Value = pbt[rep_blk];38103810+ p_BTableChangesDelta->ValidFields = 0x0C;38113811+#endif38123812+ }38133813+38143814+ return replace_node;38153815+}38163816+38173817+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&38183818+* Function: FTL_Write_Block_Table_Data38193819+* Inputs: Block table size in pages38203820+* Outputs: PASS=0 / FAIL=138213821+* Description: Write block table data in flash38223822+* If first page and last page38233823+* Write data+BT flag38243824+* else38253825+* Write data38263826+* BT flag is a counter. Its value is incremented for block table38273827+* write in a new Block38283828+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/38293829+static int FTL_Write_Block_Table_Data(void)38303830+{38313831+ u64 dwBlockTableAddr, pTempAddr;38323832+ u32 Block;38333833+ u16 Page, PageCount;38343834+ u8 *tempBuf = tmp_buf_write_blk_table_data;38353835+ int wBytesCopied;38363836+ u16 bt_pages;38373837+38383838+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",38393839+ __FILE__, __LINE__, __func__);38403840+38413841+ dwBlockTableAddr =38423842+ (u64)((u64)g_wBlockTableIndex * DeviceInfo.wBlockDataSize +38433843+ (u64)g_wBlockTableOffset * DeviceInfo.wPageDataSize);38443844+ pTempAddr = dwBlockTableAddr;38453845+38463846+ bt_pages = FTL_Get_Block_Table_Flash_Size_Pages();38473847+38483848+ nand_dbg_print(NAND_DBG_DEBUG, "FTL_Write_Block_Table_Data: "38493849+ "page= %d BlockTableIndex= %d "38503850+ "BlockTableOffset=%d\n", bt_pages,38513851+ g_wBlockTableIndex, g_wBlockTableOffset);38523852+38533853+ Block = BLK_FROM_ADDR(pTempAddr);38543854+ Page = PAGE_FROM_ADDR(pTempAddr, Block);38553855+ PageCount = 1;38563856+38573857+ if (bt_block_changed) {38583858+ if (bt_flag == LAST_BT_ID) {38593859+ bt_flag = FIRST_BT_ID;38603860+ g_pBTBlocks[bt_flag - FIRST_BT_ID] = Block;38613861+ } else if (bt_flag < LAST_BT_ID) {38623862+ bt_flag++;38633863+ g_pBTBlocks[bt_flag - FIRST_BT_ID] = Block;38643864+ }38653865+38663866+ if ((bt_flag > (LAST_BT_ID-4)) &&38673867+ g_pBTBlocks[FIRST_BT_ID - FIRST_BT_ID] !=38683868+ BTBLOCK_INVAL) {38693869+ bt_block_changed = 0;38703870+ GLOB_FTL_BT_Garbage_Collection();38713871+ }38723872+38733873+ bt_block_changed = 0;38743874+ nand_dbg_print(NAND_DBG_DEBUG,38753875+ "Block Table Counter is %u Block %u\n",38763876+ bt_flag, (unsigned int)Block);38773877+ }38783878+38793879+ memset(tempBuf, 0, 3);38803880+ tempBuf[3] = bt_flag;38813881+ wBytesCopied = FTL_Copy_Block_Table_To_Flash(tempBuf + 4,38823882+ DeviceInfo.wPageDataSize - 4, 0);38833883+ memset(&tempBuf[wBytesCopied + 4], 0xff,38843884+ DeviceInfo.wPageSize - (wBytesCopied + 4));38853885+ FTL_Insert_Block_Table_Signature(&tempBuf[DeviceInfo.wPageDataSize],38863886+ bt_flag);38873887+38883888+#if CMD_DMA38893889+ memcpy(g_pNextBlockTable, tempBuf,38903890+ DeviceInfo.wPageSize * sizeof(u8));38913891+ nand_dbg_print(NAND_DBG_DEBUG, "Writing First Page of Block Table "38923892+ "Block %u Page %u\n", (unsigned int)Block, Page);38933893+ if (FAIL == GLOB_LLD_Write_Page_Main_Spare_cdma(g_pNextBlockTable,38943894+ Block, Page, 1,38953895+ LLD_CMD_FLAG_MODE_CDMA | LLD_CMD_FLAG_ORDER_BEFORE_REST)) {38963896+ nand_dbg_print(NAND_DBG_WARN, "NAND Program fail in "38973897+ "%s, Line %d, Function: %s, "38983898+ "new Bad Block %d generated!\n",38993899+ __FILE__, __LINE__, __func__, Block);39003900+ goto func_return;39013901+ }39023902+39033903+ ftl_cmd_cnt++;39043904+ g_pNextBlockTable += ((DeviceInfo.wPageSize * sizeof(u8)));39053905+#else39063906+ if (FAIL == GLOB_LLD_Write_Page_Main_Spare(tempBuf, Block, Page, 1)) {39073907+ nand_dbg_print(NAND_DBG_WARN,39083908+ "NAND Program fail in %s, Line %d, Function: %s, "39093909+ "new Bad Block %d generated!\n",39103910+ __FILE__, __LINE__, __func__, Block);39113911+ goto func_return;39123912+ }39133913+#endif39143914+39153915+ if (bt_pages > 1) {39163916+ PageCount = bt_pages - 1;39173917+ if (PageCount > 1) {39183918+ wBytesCopied += FTL_Copy_Block_Table_To_Flash(tempBuf,39193919+ DeviceInfo.wPageDataSize * (PageCount - 1),39203920+ wBytesCopied);39213921+39223922+#if CMD_DMA39233923+ memcpy(g_pNextBlockTable, tempBuf,39243924+ (PageCount - 1) * DeviceInfo.wPageDataSize);39253925+ if (FAIL == GLOB_LLD_Write_Page_Main_cdma(39263926+ g_pNextBlockTable, Block, Page + 1,39273927+ PageCount - 1)) {39283928+ nand_dbg_print(NAND_DBG_WARN,39293929+ "NAND Program fail in %s, Line %d, "39303930+ "Function: %s, "39313931+ "new Bad Block %d generated!\n",39323932+ __FILE__, __LINE__, __func__,39333933+ (int)Block);39343934+ goto func_return;39353935+ }39363936+39373937+ ftl_cmd_cnt++;39383938+ g_pNextBlockTable += (PageCount - 1) *39393939+ DeviceInfo.wPageDataSize * sizeof(u8);39403940+#else39413941+ if (FAIL == GLOB_LLD_Write_Page_Main(tempBuf,39423942+ Block, Page + 1, PageCount - 1)) {39433943+ nand_dbg_print(NAND_DBG_WARN,39443944+ "NAND Program fail in %s, Line %d, "39453945+ "Function: %s, "39463946+ "new Bad Block %d generated!\n",39473947+ __FILE__, __LINE__, __func__,39483948+ (int)Block);39493949+ goto func_return;39503950+ }39513951+#endif39523952+ }39533953+39543954+ wBytesCopied = FTL_Copy_Block_Table_To_Flash(tempBuf,39553955+ DeviceInfo.wPageDataSize, wBytesCopied);39563956+ memset(&tempBuf[wBytesCopied], 0xff,39573957+ DeviceInfo.wPageSize-wBytesCopied);39583958+ FTL_Insert_Block_Table_Signature(39593959+ &tempBuf[DeviceInfo.wPageDataSize], bt_flag);39603960+#if CMD_DMA39613961+ memcpy(g_pNextBlockTable, tempBuf,39623962+ DeviceInfo.wPageSize * sizeof(u8));39633963+ nand_dbg_print(NAND_DBG_DEBUG,39643964+ "Writing the last Page of Block Table "39653965+ "Block %u Page %u\n",39663966+ (unsigned int)Block, Page + bt_pages - 1);39673967+ if (FAIL == GLOB_LLD_Write_Page_Main_Spare_cdma(39683968+ g_pNextBlockTable, Block, Page + bt_pages - 1, 1,39693969+ LLD_CMD_FLAG_MODE_CDMA |39703970+ LLD_CMD_FLAG_ORDER_BEFORE_REST)) {39713971+ nand_dbg_print(NAND_DBG_WARN,39723972+ "NAND Program fail in %s, Line %d, "39733973+ "Function: %s, new Bad Block %d generated!\n",39743974+ __FILE__, __LINE__, __func__, Block);39753975+ goto func_return;39763976+ }39773977+ ftl_cmd_cnt++;39783978+#else39793979+ if (FAIL == GLOB_LLD_Write_Page_Main_Spare(tempBuf,39803980+ Block, Page+bt_pages - 1, 1)) {39813981+ nand_dbg_print(NAND_DBG_WARN,39823982+ "NAND Program fail in %s, Line %d, "39833983+ "Function: %s, "39843984+ "new Bad Block %d generated!\n",39853985+ __FILE__, __LINE__, __func__, Block);39863986+ goto func_return;39873987+ }39883988+#endif39893989+ }39903990+39913991+ nand_dbg_print(NAND_DBG_DEBUG, "FTL_Write_Block_Table_Data: done\n");39923992+39933993+func_return:39943994+ return PASS;39953995+}39963996+39973997+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&39983998+* Function: FTL_Replace_Block_Table39993999+* Inputs: None40004000+* Outputs: PASS=0 / FAIL=140014001+* Description: Get a new block to write block table40024002+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/40034003+static u32 FTL_Replace_Block_Table(void)40044004+{40054005+ u32 blk;40064006+ int gc;40074007+40084008+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",40094009+ __FILE__, __LINE__, __func__);40104010+40114011+ blk = FTL_Replace_LWBlock(BLOCK_TABLE_INDEX, &gc);40124012+40134013+ if ((BAD_BLOCK == blk) && (PASS == gc)) {40144014+ GLOB_FTL_Garbage_Collection();40154015+ blk = FTL_Replace_LWBlock(BLOCK_TABLE_INDEX, &gc);40164016+ }40174017+ if (BAD_BLOCK == blk)40184018+ printk(KERN_ERR "%s, %s: There is no spare block. "40194019+ "It should never happen\n",40204020+ __FILE__, __func__);40214021+40224022+ nand_dbg_print(NAND_DBG_DEBUG, "New Block table Block is %d\n", blk);40234023+40244024+ return blk;40254025+}40264026+40274027+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&40284028+* Function: FTL_Replace_LWBlock40294029+* Inputs: Block number40304030+* Pointer to Garbage Collect flag40314031+* Outputs:40324032+* Description: Determine the least weared block by traversing40334033+* block table40344034+* Set Garbage collection to be called if number of spare40354035+* block is less than Free Block Gate count40364036+* Change Block table entry to map least worn block for current40374037+* operation40384038+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/40394039+static u32 FTL_Replace_LWBlock(u32 wBlockNum, int *pGarbageCollect)40404040+{40414041+ u32 i;40424042+ u32 *pbt = (u32 *)g_pBlockTable;40434043+ u8 wLeastWornCounter = 0xFF;40444044+ u32 wLeastWornIndex = BAD_BLOCK;40454045+ u32 wSpareBlockNum = 0;40464046+ u32 wDiscardBlockNum = 0;40474047+40484048+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",40494049+ __FILE__, __LINE__, __func__);40504050+40514051+ if (IS_SPARE_BLOCK(wBlockNum)) {40524052+ *pGarbageCollect = FAIL;40534053+ pbt[wBlockNum] = (u32)(pbt[wBlockNum] & (~SPARE_BLOCK));40544054+#if CMD_DMA40554055+ p_BTableChangesDelta =40564056+ (struct BTableChangesDelta *)g_pBTDelta_Free;40574057+ g_pBTDelta_Free += sizeof(struct BTableChangesDelta);40584058+ p_BTableChangesDelta->ftl_cmd_cnt =40594059+ ftl_cmd_cnt;40604060+ p_BTableChangesDelta->BT_Index = (u32)(wBlockNum);40614061+ p_BTableChangesDelta->BT_Entry_Value = pbt[wBlockNum];40624062+ p_BTableChangesDelta->ValidFields = 0x0C;40634063+#endif40644064+ return pbt[wBlockNum];40654065+ }40664066+40674067+ for (i = 0; i < DeviceInfo.wDataBlockNum; i++) {40684068+ if (IS_DISCARDED_BLOCK(i))40694069+ wDiscardBlockNum++;40704070+40714071+ if (IS_SPARE_BLOCK(i)) {40724072+ u32 wPhysicalIndex = (u32)((~BAD_BLOCK) & pbt[i]);40734073+ if (wPhysicalIndex > DeviceInfo.wSpectraEndBlock)40744074+ printk(KERN_ERR "FTL_Replace_LWBlock: "40754075+ "This should never occur!\n");40764076+ if (g_pWearCounter[wPhysicalIndex -40774077+ DeviceInfo.wSpectraStartBlock] <40784078+ wLeastWornCounter) {40794079+ wLeastWornCounter =40804080+ g_pWearCounter[wPhysicalIndex -40814081+ DeviceInfo.wSpectraStartBlock];40824082+ wLeastWornIndex = i;40834083+ }40844084+ wSpareBlockNum++;40854085+ }40864086+ }40874087+40884088+ nand_dbg_print(NAND_DBG_WARN,40894089+ "FTL_Replace_LWBlock: Least Worn Counter %d\n",40904090+ (int)wLeastWornCounter);40914091+40924092+ if ((wDiscardBlockNum >= NUM_FREE_BLOCKS_GATE) ||40934093+ (wSpareBlockNum <= NUM_FREE_BLOCKS_GATE))40944094+ *pGarbageCollect = PASS;40954095+ else40964096+ *pGarbageCollect = FAIL;40974097+40984098+ nand_dbg_print(NAND_DBG_DEBUG,40994099+ "FTL_Replace_LWBlock: Discarded Blocks %u Spare"41004100+ " Blocks %u\n",41014101+ (unsigned int)wDiscardBlockNum,41024102+ (unsigned int)wSpareBlockNum);41034103+41044104+ return FTL_Replace_OneBlock(wBlockNum, wLeastWornIndex);41054105+}41064106+41074107+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&41084108+* Function: FTL_Replace_MWBlock41094109+* Inputs: None41104110+* Outputs: most worn spare block no./BAD_BLOCK41114111+* Description: It finds most worn spare block.41124112+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/41134113+static u32 FTL_Replace_MWBlock(void)41144114+{41154115+ u32 i;41164116+ u32 *pbt = (u32 *)g_pBlockTable;41174117+ u8 wMostWornCounter = 0;41184118+ u32 wMostWornIndex = BAD_BLOCK;41194119+ u32 wSpareBlockNum = 0;41204120+41214121+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",41224122+ __FILE__, __LINE__, __func__);41234123+41244124+ for (i = 0; i < DeviceInfo.wDataBlockNum; i++) {41254125+ if (IS_SPARE_BLOCK(i)) {41264126+ u32 wPhysicalIndex = (u32)((~SPARE_BLOCK) & pbt[i]);41274127+ if (g_pWearCounter[wPhysicalIndex -41284128+ DeviceInfo.wSpectraStartBlock] >41294129+ wMostWornCounter) {41304130+ wMostWornCounter =41314131+ g_pWearCounter[wPhysicalIndex -41324132+ DeviceInfo.wSpectraStartBlock];41334133+ wMostWornIndex = wPhysicalIndex;41344134+ }41354135+ wSpareBlockNum++;41364136+ }41374137+ }41384138+41394139+ if (wSpareBlockNum <= 2)41404140+ return BAD_BLOCK;41414141+41424142+ return wMostWornIndex;41434143+}41444144+41454145+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&41464146+* Function: FTL_Replace_Block41474147+* Inputs: Block Address41484148+* Outputs: PASS=0 / FAIL=141494149+* Description: If block specified by blk_addr parameter is not free,41504150+* replace it with the least worn block.41514151+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/41524152+static int FTL_Replace_Block(u64 blk_addr)41534153+{41544154+ u32 current_blk = BLK_FROM_ADDR(blk_addr);41554155+ u32 *pbt = (u32 *)g_pBlockTable;41564156+ int wResult = PASS;41574157+ int GarbageCollect = FAIL;41584158+41594159+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",41604160+ __FILE__, __LINE__, __func__);41614161+41624162+ if (IS_SPARE_BLOCK(current_blk)) {41634163+ pbt[current_blk] = (~SPARE_BLOCK) & pbt[current_blk];41644164+#if CMD_DMA41654165+ p_BTableChangesDelta =41664166+ (struct BTableChangesDelta *)g_pBTDelta_Free;41674167+ g_pBTDelta_Free += sizeof(struct BTableChangesDelta);41684168+ p_BTableChangesDelta->ftl_cmd_cnt =41694169+ ftl_cmd_cnt;41704170+ p_BTableChangesDelta->BT_Index = current_blk;41714171+ p_BTableChangesDelta->BT_Entry_Value = pbt[current_blk];41724172+ p_BTableChangesDelta->ValidFields = 0x0C ;41734173+#endif41744174+ return wResult;41754175+ }41764176+41774177+ FTL_Replace_LWBlock(current_blk, &GarbageCollect);41784178+41794179+ if (PASS == GarbageCollect)41804180+ wResult = GLOB_FTL_Garbage_Collection();41814181+41824182+ return wResult;41834183+}41844184+41854185+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&41864186+* Function: GLOB_FTL_Is_BadBlock41874187+* Inputs: block number to test41884188+* Outputs: PASS (block is BAD) / FAIL (block is not bad)41894189+* Description: test if this block number is flagged as bad41904190+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/41914191+int GLOB_FTL_Is_BadBlock(u32 wBlockNum)41924192+{41934193+ u32 *pbt = (u32 *)g_pBlockTable;41944194+41954195+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",41964196+ __FILE__, __LINE__, __func__);41974197+41984198+ if (wBlockNum >= DeviceInfo.wSpectraStartBlock41994199+ && BAD_BLOCK == (pbt[wBlockNum] & BAD_BLOCK))42004200+ return PASS;42014201+ else42024202+ return FAIL;42034203+}42044204+42054205+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&42064206+* Function: GLOB_FTL_Flush_Cache42074207+* Inputs: none42084208+* Outputs: PASS=0 / FAIL=142094209+* Description: flush all the cache blocks to flash42104210+* if a cache block is not dirty, don't do anything with it42114211+* else, write the block and update the block table42124212+* Note: This function should be called at shutdown/power down.42134213+* to write important data into device42144214+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/42154215+int GLOB_FTL_Flush_Cache(void)42164216+{42174217+ int i, ret;42184218+42194219+ nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n",42204220+ __FILE__, __LINE__, __func__);42214221+42224222+ for (i = 0; i < CACHE_ITEM_NUM; i++) {42234223+ if (SET == Cache.array[i].changed) {42244224+#if CMD_DMA42254225+#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE42264226+ int_cache[ftl_cmd_cnt].item = i;42274227+ int_cache[ftl_cmd_cnt].cache.address =42284228+ Cache.array[i].address;42294229+ int_cache[ftl_cmd_cnt].cache.changed = CLEAR;42304230+#endif42314231+#endif42324232+ ret = write_back_to_l2_cache(Cache.array[i].buf, Cache.array[i].address);42334233+ if (PASS == ret) {42344234+ Cache.array[i].changed = CLEAR;42354235+ } else {42364236+ printk(KERN_ALERT "Failed when write back to L2 cache!\n");42374237+ /* TODO - How to handle this? */42384238+ }42394239+ }42404240+ }42414241+42424242+ flush_l2_cache();42434243+42444244+ return FTL_Write_Block_Table(FAIL);42454245+}42464246+42474247+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&42484248+* Function: GLOB_FTL_Page_Read42494249+* Inputs: pointer to data42504250+* logical address of data (u64 is LBA * Bytes/Page)42514251+* Outputs: PASS=0 / FAIL=142524252+* Description: reads a page of data into RAM from the cache42534253+* if the data is not already in cache, read from flash to cache42544254+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/42554255+int GLOB_FTL_Page_Read(u8 *data, u64 logical_addr)42564256+{42574257+ u16 cache_item;42584258+ int res = PASS;42594259+42604260+ nand_dbg_print(NAND_DBG_DEBUG, "GLOB_FTL_Page_Read - "42614261+ "page_addr: %llu\n", logical_addr);42624262+42634263+ cache_item = FTL_Cache_If_Hit(logical_addr);42644264+42654265+ if (UNHIT_CACHE_ITEM == cache_item) {42664266+ nand_dbg_print(NAND_DBG_DEBUG,42674267+ "GLOB_FTL_Page_Read: Cache not hit\n");42684268+ res = FTL_Cache_Write();42694269+ if (ERR == FTL_Cache_Read(logical_addr))42704270+ res = ERR;42714271+ cache_item = Cache.LRU;42724272+ }42734273+42744274+ FTL_Cache_Read_Page(data, logical_addr, cache_item);42754275+42764276+ return res;42774277+}42784278+42794279+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&42804280+* Function: GLOB_FTL_Page_Write42814281+* Inputs: pointer to data42824282+* address of data (ADDRESSTYPE is LBA * Bytes/Page)42834283+* Outputs: PASS=0 / FAIL=142844284+* Description: writes a page of data from RAM to the cache42854285+* if the data is not already in cache, write back the42864286+* least recently used block and read the addressed block42874287+* from flash to cache42884288+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/42894289+int GLOB_FTL_Page_Write(u8 *pData, u64 dwPageAddr)42904290+{42914291+ u16 cache_blk;42924292+ u32 *pbt = (u32 *)g_pBlockTable;42934293+ int wResult = PASS;42944294+42954295+ nand_dbg_print(NAND_DBG_TRACE, "GLOB_FTL_Page_Write - "42964296+ "dwPageAddr: %llu\n", dwPageAddr);42974297+42984298+ cache_blk = FTL_Cache_If_Hit(dwPageAddr);42994299+43004300+ if (UNHIT_CACHE_ITEM == cache_blk) {43014301+ wResult = FTL_Cache_Write();43024302+ if (IS_BAD_BLOCK(BLK_FROM_ADDR(dwPageAddr))) {43034303+ wResult = FTL_Replace_Block(dwPageAddr);43044304+ pbt[BLK_FROM_ADDR(dwPageAddr)] |= SPARE_BLOCK;43054305+ if (wResult == FAIL)43064306+ return FAIL;43074307+ }43084308+ if (ERR == FTL_Cache_Read(dwPageAddr))43094309+ wResult = ERR;43104310+ cache_blk = Cache.LRU;43114311+ FTL_Cache_Write_Page(pData, dwPageAddr, cache_blk, 0);43124312+ } else {43134313+#if CMD_DMA43144314+ FTL_Cache_Write_Page(pData, dwPageAddr, cache_blk,43154315+ LLD_CMD_FLAG_ORDER_BEFORE_REST);43164316+#else43174317+ FTL_Cache_Write_Page(pData, dwPageAddr, cache_blk, 0);43184318+#endif43194319+ }43204320+43214321+ return wResult;43224322+}43234323+43244324+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&43254325+* Function: GLOB_FTL_Block_Erase43264326+* Inputs: address of block to erase (now in byte format, should change to43274327+* block format)43284328+* Outputs: PASS=0 / FAIL=143294329+* Description: erases the specified block43304330+* increments the erase count43314331+* If erase count reaches its upper limit,call function to43324332+* do the ajustment as per the relative erase count values43334333+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/43344334+int GLOB_FTL_Block_Erase(u64 blk_addr)43354335+{43364336+ int status;43374337+ u32 BlkIdx;43384338+43394339+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",43404340+ __FILE__, __LINE__, __func__);43414341+43424342+ BlkIdx = (u32)(blk_addr >> DeviceInfo.nBitsInBlockDataSize);43434343+43444344+ if (BlkIdx < DeviceInfo.wSpectraStartBlock) {43454345+ printk(KERN_ERR "GLOB_FTL_Block_Erase: "43464346+ "This should never occur\n");43474347+ return FAIL;43484348+ }43494349+43504350+#if CMD_DMA43514351+ status = GLOB_LLD_Erase_Block_cdma(BlkIdx, LLD_CMD_FLAG_MODE_CDMA);43524352+ if (status == FAIL)43534353+ nand_dbg_print(NAND_DBG_WARN,43544354+ "NAND Program fail in %s, Line %d, "43554355+ "Function: %s, new Bad Block %d generated!\n",43564356+ __FILE__, __LINE__, __func__, BlkIdx);43574357+#else43584358+ status = GLOB_LLD_Erase_Block(BlkIdx);43594359+ if (status == FAIL) {43604360+ nand_dbg_print(NAND_DBG_WARN,43614361+ "NAND Program fail in %s, Line %d, "43624362+ "Function: %s, new Bad Block %d generated!\n",43634363+ __FILE__, __LINE__, __func__, BlkIdx);43644364+ return status;43654365+ }43664366+#endif43674367+43684368+ if (DeviceInfo.MLCDevice) {43694369+ g_pReadCounter[BlkIdx - DeviceInfo.wSpectraStartBlock] = 0;43704370+ if (g_cBlockTableStatus != IN_PROGRESS_BLOCK_TABLE) {43714371+ g_cBlockTableStatus = IN_PROGRESS_BLOCK_TABLE;43724372+ FTL_Write_IN_Progress_Block_Table_Page();43734373+ }43744374+ }43754375+43764376+ g_pWearCounter[BlkIdx - DeviceInfo.wSpectraStartBlock]++;43774377+43784378+#if CMD_DMA43794379+ p_BTableChangesDelta =43804380+ (struct BTableChangesDelta *)g_pBTDelta_Free;43814381+ g_pBTDelta_Free += sizeof(struct BTableChangesDelta);43824382+ p_BTableChangesDelta->ftl_cmd_cnt = ftl_cmd_cnt;43834383+ p_BTableChangesDelta->WC_Index =43844384+ BlkIdx - DeviceInfo.wSpectraStartBlock;43854385+ p_BTableChangesDelta->WC_Entry_Value =43864386+ g_pWearCounter[BlkIdx - DeviceInfo.wSpectraStartBlock];43874387+ p_BTableChangesDelta->ValidFields = 0x30;43884388+43894389+ if (DeviceInfo.MLCDevice) {43904390+ p_BTableChangesDelta =43914391+ (struct BTableChangesDelta *)g_pBTDelta_Free;43924392+ g_pBTDelta_Free += sizeof(struct BTableChangesDelta);43934393+ p_BTableChangesDelta->ftl_cmd_cnt =43944394+ ftl_cmd_cnt;43954395+ p_BTableChangesDelta->RC_Index =43964396+ BlkIdx - DeviceInfo.wSpectraStartBlock;43974397+ p_BTableChangesDelta->RC_Entry_Value =43984398+ g_pReadCounter[BlkIdx -43994399+ DeviceInfo.wSpectraStartBlock];44004400+ p_BTableChangesDelta->ValidFields = 0xC0;44014401+ }44024402+44034403+ ftl_cmd_cnt++;44044404+#endif44054405+44064406+ if (g_pWearCounter[BlkIdx - DeviceInfo.wSpectraStartBlock] == 0xFE)44074407+ FTL_Adjust_Relative_Erase_Count(BlkIdx);44084408+44094409+ return status;44104410+}44114411+44124412+44134413+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&44144414+* Function: FTL_Adjust_Relative_Erase_Count44154415+* Inputs: index to block that was just incremented and is at the max44164416+* Outputs: PASS=0 / FAIL=144174417+* Description: If any erase counts at MAX, adjusts erase count of every44184418+* block by substracting least worn44194419+* counter from counter value of every entry in wear table44204420+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/44214421+static int FTL_Adjust_Relative_Erase_Count(u32 Index_of_MAX)44224422+{44234423+ u8 wLeastWornCounter = MAX_BYTE_VALUE;44244424+ u8 wWearCounter;44254425+ u32 i, wWearIndex;44264426+ u32 *pbt = (u32 *)g_pBlockTable;44274427+ int wResult = PASS;44284428+44294429+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",44304430+ __FILE__, __LINE__, __func__);44314431+44324432+ for (i = 0; i < DeviceInfo.wDataBlockNum; i++) {44334433+ if (IS_BAD_BLOCK(i))44344434+ continue;44354435+ wWearIndex = (u32)(pbt[i] & (~BAD_BLOCK));44364436+44374437+ if ((wWearIndex - DeviceInfo.wSpectraStartBlock) < 0)44384438+ printk(KERN_ERR "FTL_Adjust_Relative_Erase_Count:"44394439+ "This should never occur\n");44404440+ wWearCounter = g_pWearCounter[wWearIndex -44414441+ DeviceInfo.wSpectraStartBlock];44424442+ if (wWearCounter < wLeastWornCounter)44434443+ wLeastWornCounter = wWearCounter;44444444+ }44454445+44464446+ if (wLeastWornCounter == 0) {44474447+ nand_dbg_print(NAND_DBG_WARN,44484448+ "Adjusting Wear Levelling Counters: Special Case\n");44494449+ g_pWearCounter[Index_of_MAX -44504450+ DeviceInfo.wSpectraStartBlock]--;44514451+#if CMD_DMA44524452+ p_BTableChangesDelta =44534453+ (struct BTableChangesDelta *)g_pBTDelta_Free;44544454+ g_pBTDelta_Free += sizeof(struct BTableChangesDelta);44554455+ p_BTableChangesDelta->ftl_cmd_cnt = ftl_cmd_cnt;44564456+ p_BTableChangesDelta->WC_Index =44574457+ Index_of_MAX - DeviceInfo.wSpectraStartBlock;44584458+ p_BTableChangesDelta->WC_Entry_Value =44594459+ g_pWearCounter[Index_of_MAX -44604460+ DeviceInfo.wSpectraStartBlock];44614461+ p_BTableChangesDelta->ValidFields = 0x30;44624462+#endif44634463+ FTL_Static_Wear_Leveling();44644464+ } else {44654465+ for (i = 0; i < DeviceInfo.wDataBlockNum; i++)44664466+ if (!IS_BAD_BLOCK(i)) {44674467+ wWearIndex = (u32)(pbt[i] & (~BAD_BLOCK));44684468+ g_pWearCounter[wWearIndex -44694469+ DeviceInfo.wSpectraStartBlock] =44704470+ (u8)(g_pWearCounter44714471+ [wWearIndex -44724472+ DeviceInfo.wSpectraStartBlock] -44734473+ wLeastWornCounter);44744474+#if CMD_DMA44754475+ p_BTableChangesDelta =44764476+ (struct BTableChangesDelta *)g_pBTDelta_Free;44774477+ g_pBTDelta_Free +=44784478+ sizeof(struct BTableChangesDelta);44794479+44804480+ p_BTableChangesDelta->ftl_cmd_cnt =44814481+ ftl_cmd_cnt;44824482+ p_BTableChangesDelta->WC_Index = wWearIndex -44834483+ DeviceInfo.wSpectraStartBlock;44844484+ p_BTableChangesDelta->WC_Entry_Value =44854485+ g_pWearCounter[wWearIndex -44864486+ DeviceInfo.wSpectraStartBlock];44874487+ p_BTableChangesDelta->ValidFields = 0x30;44884488+#endif44894489+ }44904490+ }44914491+44924492+ return wResult;44934493+}44944494+44954495+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&44964496+* Function: FTL_Write_IN_Progress_Block_Table_Page44974497+* Inputs: None44984498+* Outputs: None44994499+* Description: It writes in-progress flag page to the page next to45004500+* block table45014501+***********************************************************************/45024502+static int FTL_Write_IN_Progress_Block_Table_Page(void)45034503+{45044504+ int wResult = PASS;45054505+ u16 bt_pages;45064506+ u16 dwIPFPageAddr;45074507+#if CMD_DMA45084508+#else45094509+ u32 *pbt = (u32 *)g_pBlockTable;45104510+ u32 wTempBlockTableIndex;45114511+#endif45124512+45134513+ nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n",45144514+ __FILE__, __LINE__, __func__);45154515+45164516+ bt_pages = FTL_Get_Block_Table_Flash_Size_Pages();45174517+45184518+ dwIPFPageAddr = g_wBlockTableOffset + bt_pages;45194519+45204520+ nand_dbg_print(NAND_DBG_DEBUG, "Writing IPF at "45214521+ "Block %d Page %d\n",45224522+ g_wBlockTableIndex, dwIPFPageAddr);45234523+45244524+#if CMD_DMA45254525+ wResult = GLOB_LLD_Write_Page_Main_Spare_cdma(g_pIPF,45264526+ g_wBlockTableIndex, dwIPFPageAddr, 1,45274527+ LLD_CMD_FLAG_MODE_CDMA | LLD_CMD_FLAG_ORDER_BEFORE_REST);45284528+ if (wResult == FAIL) {45294529+ nand_dbg_print(NAND_DBG_WARN,45304530+ "NAND Program fail in %s, Line %d, "45314531+ "Function: %s, new Bad Block %d generated!\n",45324532+ __FILE__, __LINE__, __func__,45334533+ g_wBlockTableIndex);45344534+ }45354535+ g_wBlockTableOffset = dwIPFPageAddr + 1;45364536+ p_BTableChangesDelta = (struct BTableChangesDelta *)g_pBTDelta_Free;45374537+ g_pBTDelta_Free += sizeof(struct BTableChangesDelta);45384538+ p_BTableChangesDelta->ftl_cmd_cnt = ftl_cmd_cnt;45394539+ p_BTableChangesDelta->g_wBlockTableOffset = g_wBlockTableOffset;45404540+ p_BTableChangesDelta->ValidFields = 0x01;45414541+ ftl_cmd_cnt++;45424542+#else45434543+ wResult = GLOB_LLD_Write_Page_Main_Spare(g_pIPF,45444544+ g_wBlockTableIndex, dwIPFPageAddr, 1);45454545+ if (wResult == FAIL) {45464546+ nand_dbg_print(NAND_DBG_WARN,45474547+ "NAND Program fail in %s, Line %d, "45484548+ "Function: %s, new Bad Block %d generated!\n",45494549+ __FILE__, __LINE__, __func__,45504550+ (int)g_wBlockTableIndex);45514551+ MARK_BLOCK_AS_BAD(pbt[BLOCK_TABLE_INDEX]);45524552+ wTempBlockTableIndex = FTL_Replace_Block_Table();45534553+ bt_block_changed = 1;45544554+ if (BAD_BLOCK == wTempBlockTableIndex)45554555+ return ERR;45564556+ g_wBlockTableIndex = wTempBlockTableIndex;45574557+ g_wBlockTableOffset = 0;45584558+ /* Block table tag is '00'. Means it's used one */45594559+ pbt[BLOCK_TABLE_INDEX] = g_wBlockTableIndex;45604560+ return FAIL;45614561+ }45624562+ g_wBlockTableOffset = dwIPFPageAddr + 1;45634563+#endif45644564+ return wResult;45654565+}45664566+45674567+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&45684568+* Function: FTL_Read_Disturbance45694569+* Inputs: block address45704570+* Outputs: PASS=0 / FAIL=145714571+* Description: used to handle read disturbance. Data in block that45724572+* reaches its read limit is moved to new block45734573+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/45744574+int FTL_Read_Disturbance(u32 blk_addr)45754575+{45764576+ int wResult = FAIL;45774577+ u32 *pbt = (u32 *) g_pBlockTable;45784578+ u32 dwOldBlockAddr = blk_addr;45794579+ u32 wBlockNum;45804580+ u32 i;45814581+ u32 wLeastReadCounter = 0xFFFF;45824582+ u32 wLeastReadIndex = BAD_BLOCK;45834583+ u32 wSpareBlockNum = 0;45844584+ u32 wTempNode;45854585+ u32 wReplacedNode;45864586+ u8 *g_pTempBuf;45874587+45884588+ nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n",45894589+ __FILE__, __LINE__, __func__);45904590+45914591+#if CMD_DMA45924592+ g_pTempBuf = cp_back_buf_copies[cp_back_buf_idx];45934593+ cp_back_buf_idx++;45944594+ if (cp_back_buf_idx > COPY_BACK_BUF_NUM) {45954595+ printk(KERN_ERR "cp_back_buf_copies overflow! Exit."45964596+ "Maybe too many pending commands in your CDMA chain.\n");45974597+ return FAIL;45984598+ }45994599+#else46004600+ g_pTempBuf = tmp_buf_read_disturbance;46014601+#endif46024602+46034603+ wBlockNum = FTL_Get_Block_Index(blk_addr);46044604+46054605+ do {46064606+ /* This is a bug.Here 'i' should be logical block number46074607+ * and start from 1 (0 is reserved for block table).46084608+ * Have fixed it. - Yunpeng 2008. 12. 1946094609+ */46104610+ for (i = 1; i < DeviceInfo.wDataBlockNum; i++) {46114611+ if (IS_SPARE_BLOCK(i)) {46124612+ u32 wPhysicalIndex =46134613+ (u32)((~SPARE_BLOCK) & pbt[i]);46144614+ if (g_pReadCounter[wPhysicalIndex -46154615+ DeviceInfo.wSpectraStartBlock] <46164616+ wLeastReadCounter) {46174617+ wLeastReadCounter =46184618+ g_pReadCounter[wPhysicalIndex -46194619+ DeviceInfo.wSpectraStartBlock];46204620+ wLeastReadIndex = i;46214621+ }46224622+ wSpareBlockNum++;46234623+ }46244624+ }46254625+46264626+ if (wSpareBlockNum <= NUM_FREE_BLOCKS_GATE) {46274627+ wResult = GLOB_FTL_Garbage_Collection();46284628+ if (PASS == wResult)46294629+ continue;46304630+ else46314631+ break;46324632+ } else {46334633+ wTempNode = (u32)(DISCARD_BLOCK | pbt[wBlockNum]);46344634+ wReplacedNode = (u32)((~SPARE_BLOCK) &46354635+ pbt[wLeastReadIndex]);46364636+#if CMD_DMA46374637+ pbt[wBlockNum] = wReplacedNode;46384638+ pbt[wLeastReadIndex] = wTempNode;46394639+ p_BTableChangesDelta =46404640+ (struct BTableChangesDelta *)g_pBTDelta_Free;46414641+ g_pBTDelta_Free += sizeof(struct BTableChangesDelta);46424642+46434643+ p_BTableChangesDelta->ftl_cmd_cnt =46444644+ ftl_cmd_cnt;46454645+ p_BTableChangesDelta->BT_Index = wBlockNum;46464646+ p_BTableChangesDelta->BT_Entry_Value = pbt[wBlockNum];46474647+ p_BTableChangesDelta->ValidFields = 0x0C;46484648+46494649+ p_BTableChangesDelta =46504650+ (struct BTableChangesDelta *)g_pBTDelta_Free;46514651+ g_pBTDelta_Free += sizeof(struct BTableChangesDelta);46524652+46534653+ p_BTableChangesDelta->ftl_cmd_cnt =46544654+ ftl_cmd_cnt;46554655+ p_BTableChangesDelta->BT_Index = wLeastReadIndex;46564656+ p_BTableChangesDelta->BT_Entry_Value =46574657+ pbt[wLeastReadIndex];46584658+ p_BTableChangesDelta->ValidFields = 0x0C;46594659+46604660+ wResult = GLOB_LLD_Read_Page_Main_cdma(g_pTempBuf,46614661+ dwOldBlockAddr, 0, DeviceInfo.wPagesPerBlock,46624662+ LLD_CMD_FLAG_MODE_CDMA);46634663+ if (wResult == FAIL)46644664+ return wResult;46654665+46664666+ ftl_cmd_cnt++;46674667+46684668+ if (wResult != FAIL) {46694669+ if (FAIL == GLOB_LLD_Write_Page_Main_cdma(46704670+ g_pTempBuf, pbt[wBlockNum], 0,46714671+ DeviceInfo.wPagesPerBlock)) {46724672+ nand_dbg_print(NAND_DBG_WARN,46734673+ "NAND Program fail in "46744674+ "%s, Line %d, Function: %s, "46754675+ "new Bad Block %d "46764676+ "generated!\n",46774677+ __FILE__, __LINE__, __func__,46784678+ (int)pbt[wBlockNum]);46794679+ wResult = FAIL;46804680+ MARK_BLOCK_AS_BAD(pbt[wBlockNum]);46814681+ }46824682+ ftl_cmd_cnt++;46834683+ }46844684+#else46854685+ wResult = GLOB_LLD_Read_Page_Main(g_pTempBuf,46864686+ dwOldBlockAddr, 0, DeviceInfo.wPagesPerBlock);46874687+ if (wResult == FAIL)46884688+ return wResult;46894689+46904690+ if (wResult != FAIL) {46914691+ /* This is a bug. At this time, pbt[wBlockNum]46924692+ is still the physical address of46934693+ discard block, and should not be write.46944694+ Have fixed it as below.46954695+ -- Yunpeng 2008.12.1946964696+ */46974697+ wResult = GLOB_LLD_Write_Page_Main(g_pTempBuf,46984698+ wReplacedNode, 0,46994699+ DeviceInfo.wPagesPerBlock);47004700+ if (wResult == FAIL) {47014701+ nand_dbg_print(NAND_DBG_WARN,47024702+ "NAND Program fail in "47034703+ "%s, Line %d, Function: %s, "47044704+ "new Bad Block %d "47054705+ "generated!\n",47064706+ __FILE__, __LINE__, __func__,47074707+ (int)wReplacedNode);47084708+ MARK_BLOCK_AS_BAD(wReplacedNode);47094709+ } else {47104710+ pbt[wBlockNum] = wReplacedNode;47114711+ pbt[wLeastReadIndex] = wTempNode;47124712+ }47134713+ }47144714+47154715+ if ((wResult == PASS) && (g_cBlockTableStatus !=47164716+ IN_PROGRESS_BLOCK_TABLE)) {47174717+ g_cBlockTableStatus = IN_PROGRESS_BLOCK_TABLE;47184718+ FTL_Write_IN_Progress_Block_Table_Page();47194719+ }47204720+#endif47214721+ }47224722+ } while (wResult != PASS)47234723+ ;47244724+47254725+#if CMD_DMA47264726+ /* ... */47274727+#endif47284728+47294729+ return wResult;47304730+}47314731+
+198
drivers/staging/spectra/flash.h
···11+/*22+ * NAND Flash Controller Device Driver33+ * Copyright (c) 2009, Intel Corporation and its suppliers.44+ *55+ * This program is free software; you can redistribute it and/or modify it66+ * under the terms and conditions of the GNU General Public License,77+ * version 2, as published by the Free Software Foundation.88+ *99+ * This program is distributed in the hope it will be useful, but WITHOUT1010+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or1111+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for1212+ * more details.1313+ *1414+ * You should have received a copy of the GNU General Public License along with1515+ * this program; if not, write to the Free Software Foundation, Inc.,1616+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.1717+ *1818+ */1919+2020+#ifndef _FLASH_INTERFACE_2121+#define _FLASH_INTERFACE_2222+2323+#include "ffsport.h"2424+#include "spectraswconfig.h"2525+2626+#define MAX_BYTE_VALUE 0xFF2727+#define MAX_WORD_VALUE 0xFFFF2828+#define MAX_U32_VALUE 0xFFFFFFFF2929+3030+#define MAX_BLOCKNODE_VALUE 0xFFFFFF3131+#define DISCARD_BLOCK 0x8000003232+#define SPARE_BLOCK 0x4000003333+#define BAD_BLOCK 0xC000003434+3535+#define UNHIT_CACHE_ITEM 0xFFFF3636+3737+#define NAND_CACHE_INIT_ADDR 0xffffffffffffffffULL3838+3939+#define IN_PROGRESS_BLOCK_TABLE 0x004040+#define CURRENT_BLOCK_TABLE 0x014141+4242+#define BTSIG_OFFSET (0)4343+#define BTSIG_BYTES (5)4444+#define BTSIG_DELTA (3)4545+4646+#define MAX_READ_COUNTER 0x27104747+4848+#define FIRST_BT_ID (1)4949+#define LAST_BT_ID (254)5050+#define BTBLOCK_INVAL (u32)(0xFFFFFFFF)5151+5252+struct device_info_tag {5353+ u16 wDeviceMaker;5454+ u16 wDeviceID;5555+ u32 wDeviceType;5656+ u32 wSpectraStartBlock;5757+ u32 wSpectraEndBlock;5858+ u32 wTotalBlocks;5959+ u16 wPagesPerBlock;6060+ u16 wPageSize;6161+ u16 wPageDataSize;6262+ u16 wPageSpareSize;6363+ u16 wNumPageSpareFlag;6464+ u16 wECCBytesPerSector;6565+ u32 wBlockSize;6666+ u32 wBlockDataSize;6767+ u32 wDataBlockNum;6868+ u8 bPlaneNum;6969+ u16 wDeviceMainAreaSize;7070+ u16 wDeviceSpareAreaSize;7171+ u16 wDevicesConnected;7272+ u16 wDeviceWidth;7373+ u16 wHWRevision;7474+ u16 wHWFeatures;7575+7676+ u16 wONFIDevFeatures;7777+ u16 wONFIOptCommands;7878+ u16 wONFITimingMode;7979+ u16 wONFIPgmCacheTimingMode;8080+8181+ u16 MLCDevice;8282+ u16 wSpareSkipBytes;8383+8484+ u8 nBitsInPageNumber;8585+ u8 nBitsInPageDataSize;8686+ u8 nBitsInBlockDataSize;8787+};8888+8989+extern struct device_info_tag DeviceInfo;9090+9191+/* Cache item format */9292+struct flash_cache_item_tag {9393+ u64 address;9494+ u16 use_cnt;9595+ u16 changed;9696+ u8 *buf;9797+};9898+9999+struct flash_cache_tag {100100+ u32 cache_item_size; /* Size in bytes of each cache item */101101+ u16 pages_per_item; /* How many NAND pages in each cache item */102102+ u16 LRU; /* No. of the least recently used cache item */103103+ struct flash_cache_item_tag array[CACHE_ITEM_NUM];104104+};105105+106106+/*107107+ *Data structure for each list node of the managment table108108+ * used for the Level 2 Cache. Each node maps one logical NAND block.109109+ */110110+struct spectra_l2_cache_list {111111+ struct list_head list;112112+ u32 logical_blk_num; /* Logical block number */113113+ u32 pages_array[]; /* Page map array of this logical block.114114+ * Array index is the logical block number,115115+ * and for every item of this arry:116116+ * high 16 bit is index of the L2 cache block num,117117+ * low 16 bit is the phy page num118118+ * of the above L2 cache block.119119+ * This array will be kmalloc during run time.120120+ */121121+};122122+123123+struct spectra_l2_cache_info {124124+ u32 blk_array[BLK_NUM_FOR_L2_CACHE];125125+ u16 cur_blk_idx; /* idx to the phy block number of current using */126126+ u16 cur_page_num; /* pages number of current using */127127+ struct spectra_l2_cache_list table; /* First node of the table */128128+};129129+130130+#define RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE 1131131+132132+#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE133133+struct flash_cache_mod_item_tag {134134+ u64 address;135135+ u8 changed;136136+};137137+138138+struct flash_cache_delta_list_tag {139139+ u8 item; /* used cache item */140140+ struct flash_cache_mod_item_tag cache;141141+};142142+#endif143143+144144+extern struct flash_cache_tag Cache;145145+146146+extern u8 *buf_read_page_main_spare;147147+extern u8 *buf_write_page_main_spare;148148+extern u8 *buf_read_page_spare;149149+extern u8 *buf_get_bad_block;150150+extern u8 *cdma_desc_buf;151151+extern u8 *memcp_desc_buf;152152+153153+/* struture used for IndentfyDevice function */154154+struct spectra_indentfy_dev_tag {155155+ u32 NumBlocks;156156+ u16 PagesPerBlock;157157+ u16 PageDataSize;158158+ u16 wECCBytesPerSector;159159+ u32 wDataBlockNum;160160+};161161+162162+int GLOB_FTL_Flash_Init(void);163163+int GLOB_FTL_Flash_Release(void);164164+/*void GLOB_FTL_Erase_Flash(void);*/165165+int GLOB_FTL_Block_Erase(u64 block_addr);166166+int GLOB_FTL_Is_BadBlock(u32 block_num);167167+int GLOB_FTL_IdentifyDevice(struct spectra_indentfy_dev_tag *dev_data);168168+int GLOB_FTL_Event_Status(int *);169169+u16 glob_ftl_execute_cmds(void);170170+171171+/*int FTL_Read_Disturbance(ADDRESSTYPE dwBlockAddr);*/172172+int FTL_Read_Disturbance(u32 dwBlockAddr);173173+174174+/*Flash r/w based on cache*/175175+int GLOB_FTL_Page_Read(u8 *read_data, u64 page_addr);176176+int GLOB_FTL_Page_Write(u8 *write_data, u64 page_addr);177177+int GLOB_FTL_Wear_Leveling(void);178178+int GLOB_FTL_Flash_Format(void);179179+int GLOB_FTL_Init(void);180180+int GLOB_FTL_Flush_Cache(void);181181+int GLOB_FTL_Garbage_Collection(void);182182+int GLOB_FTL_BT_Garbage_Collection(void);183183+void GLOB_FTL_Cache_Release(void);184184+u8 *get_blk_table_start_addr(void);185185+u8 *get_wear_leveling_table_start_addr(void);186186+unsigned long get_blk_table_len(void);187187+unsigned long get_wear_leveling_table_len(void);188188+189189+#if DEBUG_BNDRY190190+void debug_boundary_lineno_error(int chnl, int limit, int no, int lineno,191191+ char *filename);192192+#define debug_boundary_error(chnl, limit, no) debug_boundary_lineno_error(chnl,\193193+ limit, no, __LINE__, __FILE__)194194+#else195195+#define debug_boundary_error(chnl, limit, no) ;196196+#endif197197+198198+#endif /*_FLASH_INTERFACE_*/
+339
drivers/staging/spectra/lld.c
···11+/*22+ * NAND Flash Controller Device Driver33+ * Copyright (c) 2009, Intel Corporation and its suppliers.44+ *55+ * This program is free software; you can redistribute it and/or modify it66+ * under the terms and conditions of the GNU General Public License,77+ * version 2, as published by the Free Software Foundation.88+ *99+ * This program is distributed in the hope it will be useful, but WITHOUT1010+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or1111+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for1212+ * more details.1313+ *1414+ * You should have received a copy of the GNU General Public License along with1515+ * this program; if not, write to the Free Software Foundation, Inc.,1616+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.1717+ *1818+ */1919+2020+#include "spectraswconfig.h"2121+#include "ffsport.h"2222+#include "ffsdefs.h"2323+#include "lld.h"2424+#include "lld_nand.h"2525+2626+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/2727+#if FLASH_EMU /* vector all the LLD calls to the LLD_EMU code */2828+#include "lld_emu.h"2929+#include "lld_cdma.h"3030+3131+/* common functions: */3232+u16 GLOB_LLD_Flash_Reset(void)3333+{3434+ return emu_Flash_Reset();3535+}3636+3737+u16 GLOB_LLD_Read_Device_ID(void)3838+{3939+ return emu_Read_Device_ID();4040+}4141+4242+int GLOB_LLD_Flash_Release(void)4343+{4444+ return emu_Flash_Release();4545+}4646+4747+u16 GLOB_LLD_Flash_Init(void)4848+{4949+ return emu_Flash_Init();5050+}5151+5252+u16 GLOB_LLD_Erase_Block(u32 block_add)5353+{5454+ return emu_Erase_Block(block_add);5555+}5656+5757+u16 GLOB_LLD_Write_Page_Main(u8 *write_data, u32 block, u16 Page,5858+ u16 PageCount)5959+{6060+ return emu_Write_Page_Main(write_data, block, Page, PageCount);6161+}6262+6363+u16 GLOB_LLD_Read_Page_Main(u8 *read_data, u32 block, u16 Page,6464+ u16 PageCount)6565+{6666+ return emu_Read_Page_Main(read_data, block, Page, PageCount);6767+}6868+6969+u16 GLOB_LLD_Read_Page_Main_Polling(u8 *read_data,7070+ u32 block, u16 page, u16 page_count)7171+{7272+ return emu_Read_Page_Main(read_data, block, page, page_count);7373+}7474+7575+u16 GLOB_LLD_Write_Page_Main_Spare(u8 *write_data, u32 block,7676+ u16 Page, u16 PageCount)7777+{7878+ return emu_Write_Page_Main_Spare(write_data, block, Page, PageCount);7979+}8080+8181+u16 GLOB_LLD_Read_Page_Main_Spare(u8 *read_data, u32 block,8282+ u16 Page, u16 PageCount)8383+{8484+ return emu_Read_Page_Main_Spare(read_data, block, Page, PageCount);8585+}8686+8787+u16 GLOB_LLD_Write_Page_Spare(u8 *write_data, u32 block, u16 Page,8888+ u16 PageCount)8989+{9090+ return emu_Write_Page_Spare(write_data, block, Page, PageCount);9191+}9292+9393+u16 GLOB_LLD_Read_Page_Spare(u8 *read_data, u32 block, u16 Page,9494+ u16 PageCount)9595+{9696+ return emu_Read_Page_Spare(read_data, block, Page, PageCount);9797+}9898+9999+u16 GLOB_LLD_Get_Bad_Block(u32 block)100100+{101101+ return emu_Get_Bad_Block(block);102102+}103103+104104+#endif /* FLASH_EMU */105105+106106+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/107107+#if FLASH_MTD /* vector all the LLD calls to the LLD_MTD code */108108+#include "lld_mtd.h"109109+#include "lld_cdma.h"110110+111111+/* common functions: */112112+u16 GLOB_LLD_Flash_Reset(void)113113+{114114+ return mtd_Flash_Reset();115115+}116116+117117+u16 GLOB_LLD_Read_Device_ID(void)118118+{119119+ return mtd_Read_Device_ID();120120+}121121+122122+int GLOB_LLD_Flash_Release(void)123123+{124124+ return mtd_Flash_Release();125125+}126126+127127+u16 GLOB_LLD_Flash_Init(void)128128+{129129+ return mtd_Flash_Init();130130+}131131+132132+u16 GLOB_LLD_Erase_Block(u32 block_add)133133+{134134+ return mtd_Erase_Block(block_add);135135+}136136+137137+u16 GLOB_LLD_Write_Page_Main(u8 *write_data, u32 block, u16 Page,138138+ u16 PageCount)139139+{140140+ return mtd_Write_Page_Main(write_data, block, Page, PageCount);141141+}142142+143143+u16 GLOB_LLD_Read_Page_Main(u8 *read_data, u32 block, u16 Page,144144+ u16 PageCount)145145+{146146+ return mtd_Read_Page_Main(read_data, block, Page, PageCount);147147+}148148+149149+u16 GLOB_LLD_Read_Page_Main_Polling(u8 *read_data,150150+ u32 block, u16 page, u16 page_count)151151+{152152+ return mtd_Read_Page_Main(read_data, block, page, page_count);153153+}154154+155155+u16 GLOB_LLD_Write_Page_Main_Spare(u8 *write_data, u32 block,156156+ u16 Page, u16 PageCount)157157+{158158+ return mtd_Write_Page_Main_Spare(write_data, block, Page, PageCount);159159+}160160+161161+u16 GLOB_LLD_Read_Page_Main_Spare(u8 *read_data, u32 block,162162+ u16 Page, u16 PageCount)163163+{164164+ return mtd_Read_Page_Main_Spare(read_data, block, Page, PageCount);165165+}166166+167167+u16 GLOB_LLD_Write_Page_Spare(u8 *write_data, u32 block, u16 Page,168168+ u16 PageCount)169169+{170170+ return mtd_Write_Page_Spare(write_data, block, Page, PageCount);171171+}172172+173173+u16 GLOB_LLD_Read_Page_Spare(u8 *read_data, u32 block, u16 Page,174174+ u16 PageCount)175175+{176176+ return mtd_Read_Page_Spare(read_data, block, Page, PageCount);177177+}178178+179179+u16 GLOB_LLD_Get_Bad_Block(u32 block)180180+{181181+ return mtd_Get_Bad_Block(block);182182+}183183+184184+#endif /* FLASH_MTD */185185+186186+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/187187+#if FLASH_NAND /* vector all the LLD calls to the NAND controller code */188188+#include "lld_nand.h"189189+#include "lld_cdma.h"190190+#include "flash.h"191191+192192+/* common functions for LLD_NAND */193193+void GLOB_LLD_ECC_Control(int enable)194194+{195195+ NAND_ECC_Ctrl(enable);196196+}197197+198198+/* common functions for LLD_NAND */199199+u16 GLOB_LLD_Flash_Reset(void)200200+{201201+ return NAND_Flash_Reset();202202+}203203+204204+u16 GLOB_LLD_Read_Device_ID(void)205205+{206206+ return NAND_Read_Device_ID();207207+}208208+209209+u16 GLOB_LLD_UnlockArrayAll(void)210210+{211211+ return NAND_UnlockArrayAll();212212+}213213+214214+u16 GLOB_LLD_Flash_Init(void)215215+{216216+ return NAND_Flash_Init();217217+}218218+219219+int GLOB_LLD_Flash_Release(void)220220+{221221+ return nand_release_spectra();222222+}223223+224224+u16 GLOB_LLD_Erase_Block(u32 block_add)225225+{226226+ return NAND_Erase_Block(block_add);227227+}228228+229229+230230+u16 GLOB_LLD_Write_Page_Main(u8 *write_data, u32 block, u16 Page,231231+ u16 PageCount)232232+{233233+ return NAND_Write_Page_Main(write_data, block, Page, PageCount);234234+}235235+236236+u16 GLOB_LLD_Read_Page_Main(u8 *read_data, u32 block, u16 page,237237+ u16 page_count)238238+{239239+ if (page_count == 1) /* Using polling to improve read speed */240240+ return NAND_Read_Page_Main_Polling(read_data, block, page, 1);241241+ else242242+ return NAND_Read_Page_Main(read_data, block, page, page_count);243243+}244244+245245+u16 GLOB_LLD_Read_Page_Main_Polling(u8 *read_data,246246+ u32 block, u16 page, u16 page_count)247247+{248248+ return NAND_Read_Page_Main_Polling(read_data,249249+ block, page, page_count);250250+}251251+252252+u16 GLOB_LLD_Write_Page_Main_Spare(u8 *write_data, u32 block,253253+ u16 Page, u16 PageCount)254254+{255255+ return NAND_Write_Page_Main_Spare(write_data, block, Page, PageCount);256256+}257257+258258+u16 GLOB_LLD_Write_Page_Spare(u8 *write_data, u32 block, u16 Page,259259+ u16 PageCount)260260+{261261+ return NAND_Write_Page_Spare(write_data, block, Page, PageCount);262262+}263263+264264+u16 GLOB_LLD_Read_Page_Main_Spare(u8 *read_data, u32 block,265265+ u16 page, u16 page_count)266266+{267267+ return NAND_Read_Page_Main_Spare(read_data, block, page, page_count);268268+}269269+270270+u16 GLOB_LLD_Read_Page_Spare(u8 *read_data, u32 block, u16 Page,271271+ u16 PageCount)272272+{273273+ return NAND_Read_Page_Spare(read_data, block, Page, PageCount);274274+}275275+276276+u16 GLOB_LLD_Get_Bad_Block(u32 block)277277+{278278+ return NAND_Get_Bad_Block(block);279279+}280280+281281+#if CMD_DMA282282+u16 GLOB_LLD_Event_Status(void)283283+{284284+ return CDMA_Event_Status();285285+}286286+287287+u16 glob_lld_execute_cmds(void)288288+{289289+ return CDMA_Execute_CMDs();290290+}291291+292292+u16 GLOB_LLD_MemCopy_CMD(u8 *dest, u8 *src,293293+ u32 ByteCount, u16 flag)294294+{295295+ /* Replace the hardware memcopy with software memcpy function */296296+ if (CDMA_Execute_CMDs())297297+ return FAIL;298298+ memcpy(dest, src, ByteCount);299299+ return PASS;300300+301301+ /* return CDMA_MemCopy_CMD(dest, src, ByteCount, flag); */302302+}303303+304304+u16 GLOB_LLD_Erase_Block_cdma(u32 block, u16 flags)305305+{306306+ return CDMA_Data_CMD(ERASE_CMD, 0, block, 0, 0, flags);307307+}308308+309309+u16 GLOB_LLD_Write_Page_Main_cdma(u8 *data, u32 block, u16 page, u16 count)310310+{311311+ return CDMA_Data_CMD(WRITE_MAIN_CMD, data, block, page, count, 0);312312+}313313+314314+u16 GLOB_LLD_Read_Page_Main_cdma(u8 *data, u32 block, u16 page,315315+ u16 count, u16 flags)316316+{317317+ return CDMA_Data_CMD(READ_MAIN_CMD, data, block, page, count, flags);318318+}319319+320320+u16 GLOB_LLD_Write_Page_Main_Spare_cdma(u8 *data, u32 block, u16 page,321321+ u16 count, u16 flags)322322+{323323+ return CDMA_Data_CMD(WRITE_MAIN_SPARE_CMD,324324+ data, block, page, count, flags);325325+}326326+327327+u16 GLOB_LLD_Read_Page_Main_Spare_cdma(u8 *data,328328+ u32 block, u16 page, u16 count)329329+{330330+ return CDMA_Data_CMD(READ_MAIN_SPARE_CMD, data, block, page, count,331331+ LLD_CMD_FLAG_MODE_CDMA);332332+}333333+334334+#endif /* CMD_DMA */335335+#endif /* FLASH_NAND */336336+337337+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/338338+339339+/* end of LLD.c */
+111
drivers/staging/spectra/lld.h
···11+/*22+ * NAND Flash Controller Device Driver33+ * Copyright (c) 2009, Intel Corporation and its suppliers.44+ *55+ * This program is free software; you can redistribute it and/or modify it66+ * under the terms and conditions of the GNU General Public License,77+ * version 2, as published by the Free Software Foundation.88+ *99+ * This program is distributed in the hope it will be useful, but WITHOUT1010+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or1111+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for1212+ * more details.1313+ *1414+ * You should have received a copy of the GNU General Public License along with1515+ * this program; if not, write to the Free Software Foundation, Inc.,1616+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.1717+ *1818+ */1919+2020+2121+2222+#ifndef _LLD_2323+#define _LLD_2424+2525+#include "ffsport.h"2626+#include "spectraswconfig.h"2727+#include "flash.h"2828+2929+#define GOOD_BLOCK 03030+#define DEFECTIVE_BLOCK 13131+#define READ_ERROR 23232+3333+#define CLK_X 53434+#define CLK_MULTI 43535+3636+/* Typedefs */3737+3838+/* prototypes: API for LLD */3939+/* Currently, Write_Page_Main4040+ * MemCopy4141+ * Read_Page_Main_Spare4242+ * do not have flag because they were not implemented prior to this4343+ * They are not being added to keep changes to a minimum for now.4444+ * Currently, they are not required (only reqd for Wr_P_M_S.)4545+ * Later on, these NEED to be changed.4646+ */4747+4848+extern void GLOB_LLD_ECC_Control(int enable);4949+5050+extern u16 GLOB_LLD_Flash_Reset(void);5151+5252+extern u16 GLOB_LLD_Read_Device_ID(void);5353+5454+extern u16 GLOB_LLD_UnlockArrayAll(void);5555+5656+extern u16 GLOB_LLD_Flash_Init(void);5757+5858+extern int GLOB_LLD_Flash_Release(void);5959+6060+extern u16 GLOB_LLD_Erase_Block(u32 block_add);6161+6262+extern u16 GLOB_LLD_Write_Page_Main(u8 *write_data,6363+ u32 block, u16 Page, u16 PageCount);6464+6565+extern u16 GLOB_LLD_Read_Page_Main(u8 *read_data,6666+ u32 block, u16 page, u16 page_count);6767+6868+extern u16 GLOB_LLD_Read_Page_Main_Polling(u8 *read_data,6969+ u32 block, u16 page, u16 page_count);7070+7171+extern u16 GLOB_LLD_Write_Page_Main_Spare(u8 *write_data,7272+ u32 block, u16 Page, u16 PageCount);7373+7474+extern u16 GLOB_LLD_Write_Page_Spare(u8 *write_data,7575+ u32 block, u16 Page, u16 PageCount);7676+7777+extern u16 GLOB_LLD_Read_Page_Main_Spare(u8 *read_data,7878+ u32 block, u16 page, u16 page_count);7979+8080+extern u16 GLOB_LLD_Read_Page_Spare(u8 *read_data,8181+ u32 block, u16 Page, u16 PageCount);8282+8383+extern u16 GLOB_LLD_Get_Bad_Block(u32 block);8484+8585+extern u16 GLOB_LLD_Event_Status(void);8686+8787+extern u16 GLOB_LLD_MemCopy_CMD(u8 *dest, u8 *src, u32 ByteCount, u16 flag);8888+8989+extern u16 glob_lld_execute_cmds(void);9090+9191+extern u16 GLOB_LLD_Erase_Block_cdma(u32 block, u16 flags);9292+9393+extern u16 GLOB_LLD_Write_Page_Main_cdma(u8 *data,9494+ u32 block, u16 page, u16 count);9595+9696+extern u16 GLOB_LLD_Read_Page_Main_cdma(u8 *data,9797+ u32 block, u16 page, u16 count, u16 flags);9898+9999+extern u16 GLOB_LLD_Write_Page_Main_Spare_cdma(u8 *data,100100+ u32 block, u16 page, u16 count, u16 flags);101101+102102+extern u16 GLOB_LLD_Read_Page_Main_Spare_cdma(u8 *data,103103+ u32 block, u16 page, u16 count);104104+105105+#define LLD_CMD_FLAG_ORDER_BEFORE_REST (0x1)106106+#define LLD_CMD_FLAG_MODE_CDMA (0x8)107107+108108+109109+#endif /*_LLD_ */110110+111111+
+910
drivers/staging/spectra/lld_cdma.c
···11+/*22+ * NAND Flash Controller Device Driver33+ * Copyright (c) 2009, Intel Corporation and its suppliers.44+ *55+ * This program is free software; you can redistribute it and/or modify it66+ * under the terms and conditions of the GNU General Public License,77+ * version 2, as published by the Free Software Foundation.88+ *99+ * This program is distributed in the hope it will be useful, but WITHOUT1010+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or1111+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for1212+ * more details.1313+ *1414+ * You should have received a copy of the GNU General Public License along with1515+ * this program; if not, write to the Free Software Foundation, Inc.,1616+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.1717+ *1818+ */1919+2020+#include <linux/fs.h>2121+#include <linux/slab.h>2222+2323+#include "spectraswconfig.h"2424+#include "lld.h"2525+#include "lld_nand.h"2626+#include "lld_cdma.h"2727+#include "lld_emu.h"2828+#include "flash.h"2929+#include "nand_regs.h"3030+3131+#define MAX_PENDING_CMDS 43232+#define MODE_02 (0x2 << 26)3333+3434+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&3535+* Function: CDMA_Data_Cmd3636+* Inputs: cmd code (aligned for hw)3737+* data: pointer to source or destination3838+* block: block address3939+* page: page address4040+* num: num pages to transfer4141+* Outputs: PASS4242+* Description: This function takes the parameters and puts them4343+* into the "pending commands" array.4444+* It does not parse or validate the parameters.4545+* The array index is same as the tag.4646+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/4747+u16 CDMA_Data_CMD(u8 cmd, u8 *data, u32 block, u16 page, u16 num, u16 flags)4848+{4949+ u8 bank;5050+5151+ nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n",5252+ __FILE__, __LINE__, __func__);5353+5454+ if (0 == cmd)5555+ nand_dbg_print(NAND_DBG_DEBUG,5656+ "%s, Line %d, Illegal cmd (0)\n", __FILE__, __LINE__);5757+5858+ /* If a command of another bank comes, then first execute */5959+ /* pending commands of the current bank, then set the new */6060+ /* bank as current bank */6161+ bank = block / (DeviceInfo.wTotalBlocks / totalUsedBanks);6262+ if (bank != info.flash_bank) {6363+ nand_dbg_print(NAND_DBG_WARN,6464+ "Will access new bank. old bank: %d, new bank: %d\n",6565+ info.flash_bank, bank);6666+ if (CDMA_Execute_CMDs()) {6767+ printk(KERN_ERR "CDMA_Execute_CMDs fail!\n");6868+ return FAIL;6969+ }7070+ info.flash_bank = bank;7171+ }7272+7373+ info.pcmds[info.pcmds_num].CMD = cmd;7474+ info.pcmds[info.pcmds_num].DataAddr = data;7575+ info.pcmds[info.pcmds_num].Block = block;7676+ info.pcmds[info.pcmds_num].Page = page;7777+ info.pcmds[info.pcmds_num].PageCount = num;7878+ info.pcmds[info.pcmds_num].DataDestAddr = 0;7979+ info.pcmds[info.pcmds_num].DataSrcAddr = 0;8080+ info.pcmds[info.pcmds_num].MemCopyByteCnt = 0;8181+ info.pcmds[info.pcmds_num].Flags = flags;8282+ info.pcmds[info.pcmds_num].Status = 0xB0B;8383+8484+ switch (cmd) {8585+ case WRITE_MAIN_SPARE_CMD:8686+ Conv_Main_Spare_Data_Log2Phy_Format(data, num);8787+ break;8888+ case WRITE_SPARE_CMD:8989+ Conv_Spare_Data_Log2Phy_Format(data);9090+ break;9191+ default:9292+ break;9393+ }9494+9595+ info.pcmds_num++;9696+9797+ if (info.pcmds_num >= MAX_PENDING_CMDS) {9898+ if (CDMA_Execute_CMDs()) {9999+ printk(KERN_ERR "CDMA_Execute_CMDs fail!\n");100100+ return FAIL;101101+ }102102+ }103103+104104+ return PASS;105105+}106106+107107+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&108108+* Function: CDMA_MemCopy_CMD109109+* Inputs: dest: pointer to destination110110+* src: pointer to source111111+* count: num bytes to transfer112112+* Outputs: PASS113113+* Description: This function takes the parameters and puts them114114+* into the "pending commands" array.115115+* It does not parse or validate the parameters.116116+* The array index is same as the tag.117117+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/118118+u16 CDMA_MemCopy_CMD(u8 *dest, u8 *src, u32 byte_cnt, u16 flags)119119+{120120+ nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n",121121+ __FILE__, __LINE__, __func__);122122+123123+ info.pcmds[info.pcmds_num].CMD = MEMCOPY_CMD;124124+ info.pcmds[info.pcmds_num].DataAddr = 0;125125+ info.pcmds[info.pcmds_num].Block = 0;126126+ info.pcmds[info.pcmds_num].Page = 0;127127+ info.pcmds[info.pcmds_num].PageCount = 0;128128+ info.pcmds[info.pcmds_num].DataDestAddr = dest;129129+ info.pcmds[info.pcmds_num].DataSrcAddr = src;130130+ info.pcmds[info.pcmds_num].MemCopyByteCnt = byte_cnt;131131+ info.pcmds[info.pcmds_num].Flags = flags;132132+ info.pcmds[info.pcmds_num].Status = 0xB0B;133133+134134+ info.pcmds_num++;135135+136136+ if (info.pcmds_num >= MAX_PENDING_CMDS) {137137+ if (CDMA_Execute_CMDs()) {138138+ printk(KERN_ERR "CDMA_Execute_CMDs fail!\n");139139+ return FAIL;140140+ }141141+ }142142+143143+ return PASS;144144+}145145+146146+#if 0147147+/* Prints the PendingCMDs array */148148+void print_pending_cmds(void)149149+{150150+ u16 i;151151+152152+ nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n",153153+ __FILE__, __LINE__, __func__);154154+155155+ for (i = 0; i < info.pcmds_num; i++) {156156+ nand_dbg_print(NAND_DBG_DEBUG, "\ni: %d\n", i);157157+ switch (info.pcmds[i].CMD) {158158+ case ERASE_CMD:159159+ nand_dbg_print(NAND_DBG_DEBUG,160160+ "Erase Command (0x%x)\n",161161+ info.pcmds[i].CMD);162162+ break;163163+ case WRITE_MAIN_CMD:164164+ nand_dbg_print(NAND_DBG_DEBUG,165165+ "Write Main Command (0x%x)\n",166166+ info.pcmds[i].CMD);167167+ break;168168+ case WRITE_MAIN_SPARE_CMD:169169+ nand_dbg_print(NAND_DBG_DEBUG,170170+ "Write Main Spare Command (0x%x)\n",171171+ info.pcmds[i].CMD);172172+ break;173173+ case READ_MAIN_SPARE_CMD:174174+ nand_dbg_print(NAND_DBG_DEBUG,175175+ "Read Main Spare Command (0x%x)\n",176176+ info.pcmds[i].CMD);177177+ break;178178+ case READ_MAIN_CMD:179179+ nand_dbg_print(NAND_DBG_DEBUG,180180+ "Read Main Command (0x%x)\n",181181+ info.pcmds[i].CMD);182182+ break;183183+ case MEMCOPY_CMD:184184+ nand_dbg_print(NAND_DBG_DEBUG,185185+ "Memcopy Command (0x%x)\n",186186+ info.pcmds[i].CMD);187187+ break;188188+ case DUMMY_CMD:189189+ nand_dbg_print(NAND_DBG_DEBUG,190190+ "Dummy Command (0x%x)\n",191191+ info.pcmds[i].CMD);192192+ break;193193+ default:194194+ nand_dbg_print(NAND_DBG_DEBUG,195195+ "Illegal Command (0x%x)\n",196196+ info.pcmds[i].CMD);197197+ break;198198+ }199199+200200+ nand_dbg_print(NAND_DBG_DEBUG, "DataAddr: 0x%x\n",201201+ (u32)info.pcmds[i].DataAddr);202202+ nand_dbg_print(NAND_DBG_DEBUG, "Block: %d\n",203203+ info.pcmds[i].Block);204204+ nand_dbg_print(NAND_DBG_DEBUG, "Page: %d\n",205205+ info.pcmds[i].Page);206206+ nand_dbg_print(NAND_DBG_DEBUG, "PageCount: %d\n",207207+ info.pcmds[i].PageCount);208208+ nand_dbg_print(NAND_DBG_DEBUG, "DataDestAddr: 0x%x\n",209209+ (u32)info.pcmds[i].DataDestAddr);210210+ nand_dbg_print(NAND_DBG_DEBUG, "DataSrcAddr: 0x%x\n",211211+ (u32)info.pcmds[i].DataSrcAddr);212212+ nand_dbg_print(NAND_DBG_DEBUG, "MemCopyByteCnt: %d\n",213213+ info.pcmds[i].MemCopyByteCnt);214214+ nand_dbg_print(NAND_DBG_DEBUG, "Flags: 0x%x\n",215215+ info.pcmds[i].Flags);216216+ nand_dbg_print(NAND_DBG_DEBUG, "Status: 0x%x\n",217217+ info.pcmds[i].Status);218218+ }219219+}220220+221221+/* Print the CDMA descriptors */222222+void print_cdma_descriptors(void)223223+{224224+ struct cdma_descriptor *pc;225225+ int i;226226+227227+ pc = (struct cdma_descriptor *)info.cdma_desc_buf;228228+229229+ nand_dbg_print(NAND_DBG_DEBUG, "\nWill dump cdma descriptors:\n");230230+231231+ for (i = 0; i < info.cdma_num; i++) {232232+ nand_dbg_print(NAND_DBG_DEBUG, "\ni: %d\n", i);233233+ nand_dbg_print(NAND_DBG_DEBUG,234234+ "NxtPointerHi: 0x%x, NxtPointerLo: 0x%x\n",235235+ pc[i].NxtPointerHi, pc[i].NxtPointerLo);236236+ nand_dbg_print(NAND_DBG_DEBUG,237237+ "FlashPointerHi: 0x%x, FlashPointerLo: 0x%x\n",238238+ pc[i].FlashPointerHi, pc[i].FlashPointerLo);239239+ nand_dbg_print(NAND_DBG_DEBUG, "CommandType: 0x%x\n",240240+ pc[i].CommandType);241241+ nand_dbg_print(NAND_DBG_DEBUG,242242+ "MemAddrHi: 0x%x, MemAddrLo: 0x%x\n",243243+ pc[i].MemAddrHi, pc[i].MemAddrLo);244244+ nand_dbg_print(NAND_DBG_DEBUG, "CommandFlags: 0x%x\n",245245+ pc[i].CommandFlags);246246+ nand_dbg_print(NAND_DBG_DEBUG, "Channel: %d, Status: 0x%x\n",247247+ pc[i].Channel, pc[i].Status);248248+ nand_dbg_print(NAND_DBG_DEBUG,249249+ "MemCopyPointerHi: 0x%x, MemCopyPointerLo: 0x%x\n",250250+ pc[i].MemCopyPointerHi, pc[i].MemCopyPointerLo);251251+ nand_dbg_print(NAND_DBG_DEBUG,252252+ "Reserved12: 0x%x, Reserved13: 0x%x, "253253+ "Reserved14: 0x%x, pcmd: %d\n",254254+ pc[i].Reserved12, pc[i].Reserved13,255255+ pc[i].Reserved14, pc[i].pcmd);256256+ }257257+}258258+259259+/* Print the Memory copy descriptors */260260+static void print_memcp_descriptors(void)261261+{262262+ struct memcpy_descriptor *pm;263263+ int i;264264+265265+ pm = (struct memcpy_descriptor *)info.memcp_desc_buf;266266+267267+ nand_dbg_print(NAND_DBG_DEBUG, "\nWill dump mem_cpy descriptors:\n");268268+269269+ for (i = 0; i < info.cdma_num; i++) {270270+ nand_dbg_print(NAND_DBG_DEBUG, "\ni: %d\n", i);271271+ nand_dbg_print(NAND_DBG_DEBUG,272272+ "NxtPointerHi: 0x%x, NxtPointerLo: 0x%x\n",273273+ pm[i].NxtPointerHi, pm[i].NxtPointerLo);274274+ nand_dbg_print(NAND_DBG_DEBUG,275275+ "SrcAddrHi: 0x%x, SrcAddrLo: 0x%x\n",276276+ pm[i].SrcAddrHi, pm[i].SrcAddrLo);277277+ nand_dbg_print(NAND_DBG_DEBUG,278278+ "DestAddrHi: 0x%x, DestAddrLo: 0x%x\n",279279+ pm[i].DestAddrHi, pm[i].DestAddrLo);280280+ nand_dbg_print(NAND_DBG_DEBUG, "XferSize: %d\n",281281+ pm[i].XferSize);282282+ nand_dbg_print(NAND_DBG_DEBUG, "MemCopyFlags: 0x%x\n",283283+ pm[i].MemCopyFlags);284284+ nand_dbg_print(NAND_DBG_DEBUG, "MemCopyStatus: %d\n",285285+ pm[i].MemCopyStatus);286286+ nand_dbg_print(NAND_DBG_DEBUG, "reserved9: 0x%x\n",287287+ pm[i].reserved9);288288+ nand_dbg_print(NAND_DBG_DEBUG, "reserved10: 0x%x\n",289289+ pm[i].reserved10);290290+ nand_dbg_print(NAND_DBG_DEBUG, "reserved11: 0x%x\n",291291+ pm[i].reserved11);292292+ nand_dbg_print(NAND_DBG_DEBUG, "reserved12: 0x%x\n",293293+ pm[i].reserved12);294294+ nand_dbg_print(NAND_DBG_DEBUG, "reserved13: 0x%x\n",295295+ pm[i].reserved13);296296+ nand_dbg_print(NAND_DBG_DEBUG, "reserved14: 0x%x\n",297297+ pm[i].reserved14);298298+ nand_dbg_print(NAND_DBG_DEBUG, "reserved15: 0x%x\n",299299+ pm[i].reserved15);300300+ }301301+}302302+#endif303303+304304+/* Reset cdma_descriptor chain to 0 */305305+static void reset_cdma_desc(int i)306306+{307307+ struct cdma_descriptor *ptr;308308+309309+ BUG_ON(i >= MAX_DESCS);310310+311311+ ptr = (struct cdma_descriptor *)info.cdma_desc_buf;312312+313313+ ptr[i].NxtPointerHi = 0;314314+ ptr[i].NxtPointerLo = 0;315315+ ptr[i].FlashPointerHi = 0;316316+ ptr[i].FlashPointerLo = 0;317317+ ptr[i].CommandType = 0;318318+ ptr[i].MemAddrHi = 0;319319+ ptr[i].MemAddrLo = 0;320320+ ptr[i].CommandFlags = 0;321321+ ptr[i].Channel = 0;322322+ ptr[i].Status = 0;323323+ ptr[i].MemCopyPointerHi = 0;324324+ ptr[i].MemCopyPointerLo = 0;325325+}326326+327327+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&328328+* Function: CDMA_UpdateEventStatus329329+* Inputs: none330330+* Outputs: none331331+* Description: This function update the event status of all the channels332332+* when an error condition is reported.333333+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/334334+void CDMA_UpdateEventStatus(void)335335+{336336+ int i, j, active_chan;337337+ struct cdma_descriptor *ptr;338338+339339+ nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n",340340+ __FILE__, __LINE__, __func__);341341+342342+ ptr = (struct cdma_descriptor *)info.cdma_desc_buf;343343+344344+ for (j = 0; j < info.cdma_num; j++) {345345+ /* Check for the descriptor with failure */346346+ if ((ptr[j].Status & CMD_DMA_DESC_FAIL))347347+ break;348348+349349+ }350350+351351+ /* All the previous cmd's status for this channel must be good */352352+ for (i = 0; i < j; i++) {353353+ if (ptr[i].pcmd != 0xff)354354+ info.pcmds[ptr[i].pcmd].Status = CMD_PASS;355355+ }356356+357357+ /* Abort the channel with type 0 reset command. It resets the */358358+ /* selected channel after the descriptor completes the flash */359359+ /* operation and status has been updated for the descriptor. */360360+ /* Memory Copy and Sync associated with this descriptor will */361361+ /* not be executed */362362+ active_chan = ioread32(FlashReg + CHNL_ACTIVE);363363+ if ((active_chan & (1 << info.flash_bank)) == (1 << info.flash_bank)) {364364+ iowrite32(MODE_02 | (0 << 4), FlashMem); /* Type 0 reset */365365+ iowrite32((0xF << 4) | info.flash_bank, FlashMem + 0x10);366366+ } else { /* Should not reached here */367367+ printk(KERN_ERR "Error! Used bank is not set in"368368+ " reg CHNL_ACTIVE\n");369369+ }370370+}371371+372372+static void cdma_trans(u16 chan)373373+{374374+ u32 addr;375375+376376+ addr = info.cdma_desc;377377+378378+ iowrite32(MODE_10 | (chan << 24), FlashMem);379379+ iowrite32((1 << 7) | chan, FlashMem + 0x10);380380+381381+ iowrite32(MODE_10 | (chan << 24) | ((0x0FFFF & (addr >> 16)) << 8),382382+ FlashMem);383383+ iowrite32((1 << 7) | (1 << 4) | 0, FlashMem + 0x10);384384+385385+ iowrite32(MODE_10 | (chan << 24) | ((0x0FFFF & addr) << 8), FlashMem);386386+ iowrite32((1 << 7) | (1 << 5) | 0, FlashMem + 0x10);387387+388388+ iowrite32(MODE_10 | (chan << 24), FlashMem);389389+ iowrite32((1 << 7) | (1 << 5) | (1 << 4) | 0, FlashMem + 0x10);390390+}391391+392392+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&393393+* Function: CDMA_Execute_CMDs (for use with CMD_DMA)394394+* Inputs: tag_count: the number of pending cmds to do395395+* Outputs: PASS/FAIL396396+* Description: Build the SDMA chain(s) by making one CMD-DMA descriptor397397+* for each pending command, start the CDMA engine, and return.398398+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/399399+u16 CDMA_Execute_CMDs(void)400400+{401401+ int i, ret;402402+ u64 flash_add;403403+ u32 ptr;404404+ dma_addr_t map_addr, next_ptr;405405+ u16 status = PASS;406406+ u16 tmp_c;407407+ struct cdma_descriptor *pc;408408+ struct memcpy_descriptor *pm;409409+410410+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",411411+ __FILE__, __LINE__, __func__);412412+413413+ /* No pending cmds to execute, just exit */414414+ if (0 == info.pcmds_num) {415415+ nand_dbg_print(NAND_DBG_TRACE,416416+ "No pending cmds to execute. Just exit.\n");417417+ return PASS;418418+ }419419+420420+ for (i = 0; i < MAX_DESCS; i++)421421+ reset_cdma_desc(i);422422+423423+ pc = (struct cdma_descriptor *)info.cdma_desc_buf;424424+ pm = (struct memcpy_descriptor *)info.memcp_desc_buf;425425+426426+ info.cdma_desc = virt_to_bus(info.cdma_desc_buf);427427+ info.memcp_desc = virt_to_bus(info.memcp_desc_buf);428428+ next_ptr = info.cdma_desc;429429+ info.cdma_num = 0;430430+431431+ for (i = 0; i < info.pcmds_num; i++) {432432+ if (info.pcmds[i].Block >= DeviceInfo.wTotalBlocks) {433433+ info.pcmds[i].Status = CMD_NOT_DONE;434434+ continue;435435+ }436436+437437+ next_ptr += sizeof(struct cdma_descriptor);438438+ pc[info.cdma_num].NxtPointerHi = next_ptr >> 16;439439+ pc[info.cdma_num].NxtPointerLo = next_ptr & 0xffff;440440+441441+ /* Use the Block offset within a bank */442442+ tmp_c = info.pcmds[i].Block /443443+ (DeviceInfo.wTotalBlocks / totalUsedBanks);444444+ flash_add = (u64)(info.pcmds[i].Block - tmp_c *445445+ (DeviceInfo.wTotalBlocks / totalUsedBanks)) *446446+ DeviceInfo.wBlockDataSize +447447+ (u64)(info.pcmds[i].Page) *448448+ DeviceInfo.wPageDataSize;449449+450450+ ptr = MODE_10 | (info.flash_bank << 24) |451451+ (u32)GLOB_u64_Div(flash_add,452452+ DeviceInfo.wPageDataSize);453453+ pc[info.cdma_num].FlashPointerHi = ptr >> 16;454454+ pc[info.cdma_num].FlashPointerLo = ptr & 0xffff;455455+456456+ if ((info.pcmds[i].CMD == WRITE_MAIN_SPARE_CMD) ||457457+ (info.pcmds[i].CMD == READ_MAIN_SPARE_CMD)) {458458+ /* Descriptor to set Main+Spare Access Mode */459459+ pc[info.cdma_num].CommandType = 0x43;460460+ pc[info.cdma_num].CommandFlags =461461+ (0 << 10) | (1 << 9) | (0 << 8) | 0x40;462462+ pc[info.cdma_num].MemAddrHi = 0;463463+ pc[info.cdma_num].MemAddrLo = 0;464464+ pc[info.cdma_num].Channel = 0;465465+ pc[info.cdma_num].Status = 0;466466+ pc[info.cdma_num].pcmd = i;467467+468468+ info.cdma_num++;469469+ BUG_ON(info.cdma_num >= MAX_DESCS);470470+471471+ reset_cdma_desc(info.cdma_num);472472+ next_ptr += sizeof(struct cdma_descriptor);473473+ pc[info.cdma_num].NxtPointerHi = next_ptr >> 16;474474+ pc[info.cdma_num].NxtPointerLo = next_ptr & 0xffff;475475+ pc[info.cdma_num].FlashPointerHi = ptr >> 16;476476+ pc[info.cdma_num].FlashPointerLo = ptr & 0xffff;477477+ }478478+479479+ switch (info.pcmds[i].CMD) {480480+ case ERASE_CMD:481481+ pc[info.cdma_num].CommandType = 1;482482+ pc[info.cdma_num].CommandFlags =483483+ (0 << 10) | (1 << 9) | (0 << 8) | 0x40;484484+ pc[info.cdma_num].MemAddrHi = 0;485485+ pc[info.cdma_num].MemAddrLo = 0;486486+ break;487487+488488+ case WRITE_MAIN_CMD:489489+ pc[info.cdma_num].CommandType =490490+ 0x2100 | info.pcmds[i].PageCount;491491+ pc[info.cdma_num].CommandFlags =492492+ (0 << 10) | (1 << 9) | (0 << 8) | 0x40;493493+ map_addr = virt_to_bus(info.pcmds[i].DataAddr);494494+ pc[info.cdma_num].MemAddrHi = map_addr >> 16;495495+ pc[info.cdma_num].MemAddrLo = map_addr & 0xffff;496496+ break;497497+498498+ case READ_MAIN_CMD:499499+ pc[info.cdma_num].CommandType =500500+ 0x2000 | info.pcmds[i].PageCount;501501+ pc[info.cdma_num].CommandFlags =502502+ (0 << 10) | (1 << 9) | (0 << 8) | 0x40;503503+ map_addr = virt_to_bus(info.pcmds[i].DataAddr);504504+ pc[info.cdma_num].MemAddrHi = map_addr >> 16;505505+ pc[info.cdma_num].MemAddrLo = map_addr & 0xffff;506506+ break;507507+508508+ case WRITE_MAIN_SPARE_CMD:509509+ pc[info.cdma_num].CommandType =510510+ 0x2100 | info.pcmds[i].PageCount;511511+ pc[info.cdma_num].CommandFlags =512512+ (0 << 10) | (1 << 9) | (0 << 8) | 0x40;513513+ map_addr = virt_to_bus(info.pcmds[i].DataAddr);514514+ pc[info.cdma_num].MemAddrHi = map_addr >> 16;515515+ pc[info.cdma_num].MemAddrLo = map_addr & 0xffff;516516+ break;517517+518518+ case READ_MAIN_SPARE_CMD:519519+ pc[info.cdma_num].CommandType =520520+ 0x2000 | info.pcmds[i].PageCount;521521+ pc[info.cdma_num].CommandFlags =522522+ (0 << 10) | (1 << 9) | (0 << 8) | 0x40;523523+ map_addr = virt_to_bus(info.pcmds[i].DataAddr);524524+ pc[info.cdma_num].MemAddrHi = map_addr >> 16;525525+ pc[info.cdma_num].MemAddrLo = map_addr & 0xffff;526526+ break;527527+528528+ case MEMCOPY_CMD:529529+ pc[info.cdma_num].CommandType = 0xFFFF; /* NOP cmd */530530+ /* Set bit 11 to let the CDMA engine continue to */531531+ /* execute only after it has finished processing */532532+ /* the memcopy descriptor. */533533+ /* Also set bit 10 and bit 9 to 1 */534534+ pc[info.cdma_num].CommandFlags = 0x0E40;535535+ map_addr = info.memcp_desc + info.cdma_num *536536+ sizeof(struct memcpy_descriptor);537537+ pc[info.cdma_num].MemCopyPointerHi = map_addr >> 16;538538+ pc[info.cdma_num].MemCopyPointerLo = map_addr & 0xffff;539539+540540+ pm[info.cdma_num].NxtPointerHi = 0;541541+ pm[info.cdma_num].NxtPointerLo = 0;542542+543543+ map_addr = virt_to_bus(info.pcmds[i].DataSrcAddr);544544+ pm[info.cdma_num].SrcAddrHi = map_addr >> 16;545545+ pm[info.cdma_num].SrcAddrLo = map_addr & 0xffff;546546+ map_addr = virt_to_bus(info.pcmds[i].DataDestAddr);547547+ pm[info.cdma_num].DestAddrHi = map_addr >> 16;548548+ pm[info.cdma_num].DestAddrLo = map_addr & 0xffff;549549+550550+ pm[info.cdma_num].XferSize =551551+ info.pcmds[i].MemCopyByteCnt;552552+ pm[info.cdma_num].MemCopyFlags =553553+ (0 << 15 | 0 << 14 | 27 << 8 | 0x40);554554+ pm[info.cdma_num].MemCopyStatus = 0;555555+ break;556556+557557+ case DUMMY_CMD:558558+ default:559559+ pc[info.cdma_num].CommandType = 0XFFFF;560560+ pc[info.cdma_num].CommandFlags =561561+ (0 << 10) | (1 << 9) | (0 << 8) | 0x40;562562+ pc[info.cdma_num].MemAddrHi = 0;563563+ pc[info.cdma_num].MemAddrLo = 0;564564+ break;565565+ }566566+567567+ pc[info.cdma_num].Channel = 0;568568+ pc[info.cdma_num].Status = 0;569569+ pc[info.cdma_num].pcmd = i;570570+571571+ info.cdma_num++;572572+ BUG_ON(info.cdma_num >= MAX_DESCS);573573+574574+ if ((info.pcmds[i].CMD == WRITE_MAIN_SPARE_CMD) ||575575+ (info.pcmds[i].CMD == READ_MAIN_SPARE_CMD)) {576576+ /* Descriptor to set back Main Area Access Mode */577577+ reset_cdma_desc(info.cdma_num);578578+ next_ptr += sizeof(struct cdma_descriptor);579579+ pc[info.cdma_num].NxtPointerHi = next_ptr >> 16;580580+ pc[info.cdma_num].NxtPointerLo = next_ptr & 0xffff;581581+582582+ pc[info.cdma_num].FlashPointerHi = ptr >> 16;583583+ pc[info.cdma_num].FlashPointerLo = ptr & 0xffff;584584+585585+ pc[info.cdma_num].CommandType = 0x42;586586+ pc[info.cdma_num].CommandFlags =587587+ (0 << 10) | (1 << 9) | (0 << 8) | 0x40;588588+ pc[info.cdma_num].MemAddrHi = 0;589589+ pc[info.cdma_num].MemAddrLo = 0;590590+591591+ pc[info.cdma_num].Channel = 0;592592+ pc[info.cdma_num].Status = 0;593593+ pc[info.cdma_num].pcmd = i;594594+595595+ info.cdma_num++;596596+ BUG_ON(info.cdma_num >= MAX_DESCS);597597+ }598598+ }599599+600600+ /* Add a dummy descriptor at end of the CDMA chain */601601+ reset_cdma_desc(info.cdma_num);602602+ ptr = MODE_10 | (info.flash_bank << 24);603603+ pc[info.cdma_num].FlashPointerHi = ptr >> 16;604604+ pc[info.cdma_num].FlashPointerLo = ptr & 0xffff;605605+ pc[info.cdma_num].CommandType = 0xFFFF; /* NOP command */606606+ /* Set Command Flags for the last CDMA descriptor: */607607+ /* set Continue bit (bit 9) to 0 and Interrupt bit (bit 8) to 1 */608608+ pc[info.cdma_num].CommandFlags =609609+ (0 << 10) | (0 << 9) | (1 << 8) | 0x40;610610+ pc[info.cdma_num].pcmd = 0xff; /* Set it to an illegal value */611611+ info.cdma_num++;612612+ BUG_ON(info.cdma_num >= MAX_DESCS);613613+614614+ iowrite32(1, FlashReg + GLOBAL_INT_ENABLE); /* Enable Interrupt */615615+616616+ iowrite32(1, FlashReg + DMA_ENABLE);617617+ /* Wait for DMA to be enabled before issuing the next command */618618+ while (!(ioread32(FlashReg + DMA_ENABLE) & DMA_ENABLE__FLAG))619619+ ;620620+ cdma_trans(info.flash_bank);621621+622622+ ret = wait_for_completion_timeout(&info.complete, 50 * HZ);623623+ if (!ret)624624+ printk(KERN_ERR "Wait for completion timeout "625625+ "in %s, Line %d\n", __FILE__, __LINE__);626626+ status = info.ret;627627+628628+ info.pcmds_num = 0; /* Clear the pending cmds number to 0 */629629+630630+ return status;631631+}632632+633633+int is_cdma_interrupt(void)634634+{635635+ u32 ints_b0, ints_b1, ints_b2, ints_b3, ints_cdma;636636+ u32 int_en_mask;637637+ u32 cdma_int_en_mask;638638+639639+ nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n",640640+ __FILE__, __LINE__, __func__);641641+642642+ /* Set the global Enable masks for only those interrupts643643+ * that are supported */644644+ cdma_int_en_mask = (DMA_INTR__DESC_COMP_CHANNEL0 |645645+ DMA_INTR__DESC_COMP_CHANNEL1 |646646+ DMA_INTR__DESC_COMP_CHANNEL2 |647647+ DMA_INTR__DESC_COMP_CHANNEL3 |648648+ DMA_INTR__MEMCOPY_DESC_COMP);649649+650650+ int_en_mask = (INTR_STATUS0__ECC_ERR |651651+ INTR_STATUS0__PROGRAM_FAIL |652652+ INTR_STATUS0__ERASE_FAIL);653653+654654+ ints_b0 = ioread32(FlashReg + INTR_STATUS0) & int_en_mask;655655+ ints_b1 = ioread32(FlashReg + INTR_STATUS1) & int_en_mask;656656+ ints_b2 = ioread32(FlashReg + INTR_STATUS2) & int_en_mask;657657+ ints_b3 = ioread32(FlashReg + INTR_STATUS3) & int_en_mask;658658+ ints_cdma = ioread32(FlashReg + DMA_INTR) & cdma_int_en_mask;659659+660660+ nand_dbg_print(NAND_DBG_WARN, "ints_bank0 to ints_bank3: "661661+ "0x%x, 0x%x, 0x%x, 0x%x, ints_cdma: 0x%x\n",662662+ ints_b0, ints_b1, ints_b2, ints_b3, ints_cdma);663663+664664+ if (ints_b0 || ints_b1 || ints_b2 || ints_b3 || ints_cdma) {665665+ return 1;666666+ } else {667667+ iowrite32(ints_b0, FlashReg + INTR_STATUS0);668668+ iowrite32(ints_b1, FlashReg + INTR_STATUS1);669669+ iowrite32(ints_b2, FlashReg + INTR_STATUS2);670670+ iowrite32(ints_b3, FlashReg + INTR_STATUS3);671671+ nand_dbg_print(NAND_DBG_DEBUG,672672+ "Not a NAND controller interrupt! Ignore it.\n");673673+ return 0;674674+ }675675+}676676+677677+static void update_event_status(void)678678+{679679+ int i;680680+ struct cdma_descriptor *ptr;681681+682682+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",683683+ __FILE__, __LINE__, __func__);684684+685685+ ptr = (struct cdma_descriptor *)info.cdma_desc_buf;686686+687687+ for (i = 0; i < info.cdma_num; i++) {688688+ if (ptr[i].pcmd != 0xff)689689+ info.pcmds[ptr[i].pcmd].Status = CMD_PASS;690690+ if ((ptr[i].CommandType == 0x41) ||691691+ (ptr[i].CommandType == 0x42) ||692692+ (ptr[i].CommandType == 0x43))693693+ continue;694694+695695+ switch (info.pcmds[ptr[i].pcmd].CMD) {696696+ case READ_MAIN_SPARE_CMD:697697+ Conv_Main_Spare_Data_Phy2Log_Format(698698+ info.pcmds[ptr[i].pcmd].DataAddr,699699+ info.pcmds[ptr[i].pcmd].PageCount);700700+ break;701701+ case READ_SPARE_CMD:702702+ Conv_Spare_Data_Phy2Log_Format(703703+ info.pcmds[ptr[i].pcmd].DataAddr);704704+ break;705705+ }706706+ }707707+}708708+709709+static u16 do_ecc_for_desc(u32 ch, u8 *buf, u16 page)710710+{711711+ u16 event = EVENT_NONE;712712+ u16 err_byte;713713+ u16 err_page = 0;714714+ u8 err_sector;715715+ u8 err_device;716716+ u16 ecc_correction_info;717717+ u16 err_address;718718+ u32 eccSectorSize;719719+ u8 *err_pos;720720+721721+ nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n",722722+ __FILE__, __LINE__, __func__);723723+724724+ eccSectorSize = ECC_SECTOR_SIZE * (DeviceInfo.wDevicesConnected);725725+726726+ do {727727+ if (0 == ch)728728+ err_page = ioread32(FlashReg + ERR_PAGE_ADDR0);729729+ else if (1 == ch)730730+ err_page = ioread32(FlashReg + ERR_PAGE_ADDR1);731731+ else if (2 == ch)732732+ err_page = ioread32(FlashReg + ERR_PAGE_ADDR2);733733+ else if (3 == ch)734734+ err_page = ioread32(FlashReg + ERR_PAGE_ADDR3);735735+736736+ err_address = ioread32(FlashReg + ECC_ERROR_ADDRESS);737737+ err_byte = err_address & ECC_ERROR_ADDRESS__OFFSET;738738+ err_sector = ((err_address &739739+ ECC_ERROR_ADDRESS__SECTOR_NR) >> 12);740740+741741+ ecc_correction_info = ioread32(FlashReg + ERR_CORRECTION_INFO);742742+ err_device = ((ecc_correction_info &743743+ ERR_CORRECTION_INFO__DEVICE_NR) >> 8);744744+745745+ if (ecc_correction_info & ERR_CORRECTION_INFO__ERROR_TYPE) {746746+ event = EVENT_UNCORRECTABLE_DATA_ERROR;747747+ } else {748748+ event = EVENT_CORRECTABLE_DATA_ERROR_FIXED;749749+ if (err_byte < ECC_SECTOR_SIZE) {750750+ err_pos = buf +751751+ (err_page - page) *752752+ DeviceInfo.wPageDataSize +753753+ err_sector * eccSectorSize +754754+ err_byte *755755+ DeviceInfo.wDevicesConnected +756756+ err_device;757757+ *err_pos ^= ecc_correction_info &758758+ ERR_CORRECTION_INFO__BYTEMASK;759759+ }760760+ }761761+ } while (!(ecc_correction_info & ERR_CORRECTION_INFO__LAST_ERR_INFO));762762+763763+ return event;764764+}765765+766766+static u16 process_ecc_int(u32 c, u16 *p_desc_num)767767+{768768+ struct cdma_descriptor *ptr;769769+ u16 j;770770+ int event = EVENT_PASS;771771+772772+ nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n",773773+ __FILE__, __LINE__, __func__);774774+775775+ if (c != info.flash_bank)776776+ printk(KERN_ERR "Error!info.flash_bank is %d, while c is %d\n",777777+ info.flash_bank, c);778778+779779+ ptr = (struct cdma_descriptor *)info.cdma_desc_buf;780780+781781+ for (j = 0; j < info.cdma_num; j++)782782+ if ((ptr[j].Status & CMD_DMA_DESC_COMP) != CMD_DMA_DESC_COMP)783783+ break;784784+785785+ *p_desc_num = j; /* Pass the descripter number found here */786786+787787+ if (j >= info.cdma_num) {788788+ printk(KERN_ERR "Can not find the correct descriptor number "789789+ "when ecc interrupt triggered!"790790+ "info.cdma_num: %d, j: %d\n", info.cdma_num, j);791791+ return EVENT_UNCORRECTABLE_DATA_ERROR;792792+ }793793+794794+ event = do_ecc_for_desc(c, info.pcmds[ptr[j].pcmd].DataAddr,795795+ info.pcmds[ptr[j].pcmd].Page);796796+797797+ if (EVENT_UNCORRECTABLE_DATA_ERROR == event) {798798+ printk(KERN_ERR "Uncorrectable ECC error!"799799+ "info.cdma_num: %d, j: %d, "800800+ "pending cmd CMD: 0x%x, "801801+ "Block: 0x%x, Page: 0x%x, PageCount: 0x%x\n",802802+ info.cdma_num, j,803803+ info.pcmds[ptr[j].pcmd].CMD,804804+ info.pcmds[ptr[j].pcmd].Block,805805+ info.pcmds[ptr[j].pcmd].Page,806806+ info.pcmds[ptr[j].pcmd].PageCount);807807+808808+ if (ptr[j].pcmd != 0xff)809809+ info.pcmds[ptr[j].pcmd].Status = CMD_FAIL;810810+ CDMA_UpdateEventStatus();811811+ }812812+813813+ return event;814814+}815815+816816+static void process_prog_erase_fail_int(u16 desc_num)817817+{818818+ struct cdma_descriptor *ptr;819819+820820+ nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n",821821+ __FILE__, __LINE__, __func__);822822+823823+ ptr = (struct cdma_descriptor *)info.cdma_desc_buf;824824+825825+ if (ptr[desc_num].pcmd != 0xFF)826826+ info.pcmds[ptr[desc_num].pcmd].Status = CMD_FAIL;827827+828828+ CDMA_UpdateEventStatus();829829+}830830+831831+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&832832+* Function: CDMA_Event_Status (for use with CMD_DMA)833833+* Inputs: none834834+* Outputs: Event_Status code835835+* Description: This function is called after an interrupt has happened836836+* It reads the HW status register and ...tbd837837+* It returns the appropriate event status838838+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/839839+u16 CDMA_Event_Status(void)840840+{841841+ u32 ints_addr[4] = {INTR_STATUS0, INTR_STATUS1,842842+ INTR_STATUS2, INTR_STATUS3};843843+ u32 dma_intr_bit[4] = {DMA_INTR__DESC_COMP_CHANNEL0,844844+ DMA_INTR__DESC_COMP_CHANNEL1,845845+ DMA_INTR__DESC_COMP_CHANNEL2,846846+ DMA_INTR__DESC_COMP_CHANNEL3};847847+ u32 cdma_int_status, int_status;848848+ u32 ecc_enable = 0;849849+ u16 event = EVENT_PASS;850850+ u16 cur_desc = 0;851851+852852+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",853853+ __FILE__, __LINE__, __func__);854854+855855+ ecc_enable = ioread32(FlashReg + ECC_ENABLE);856856+857857+ while (1) {858858+ int_status = ioread32(FlashReg + ints_addr[info.flash_bank]);859859+ if (ecc_enable && (int_status & INTR_STATUS0__ECC_ERR)) {860860+ event = process_ecc_int(info.flash_bank, &cur_desc);861861+ iowrite32(INTR_STATUS0__ECC_ERR,862862+ FlashReg + ints_addr[info.flash_bank]);863863+ if (EVENT_UNCORRECTABLE_DATA_ERROR == event) {864864+ nand_dbg_print(NAND_DBG_WARN,865865+ "ints_bank0 to ints_bank3: "866866+ "0x%x, 0x%x, 0x%x, 0x%x, "867867+ "ints_cdma: 0x%x\n",868868+ ioread32(FlashReg + INTR_STATUS0),869869+ ioread32(FlashReg + INTR_STATUS1),870870+ ioread32(FlashReg + INTR_STATUS2),871871+ ioread32(FlashReg + INTR_STATUS3),872872+ ioread32(FlashReg + DMA_INTR));873873+ break;874874+ }875875+ } else if (int_status & INTR_STATUS0__PROGRAM_FAIL) {876876+ printk(KERN_ERR "NAND program fail interrupt!\n");877877+ process_prog_erase_fail_int(cur_desc);878878+ event = EVENT_PROGRAM_FAILURE;879879+ break;880880+ } else if (int_status & INTR_STATUS0__ERASE_FAIL) {881881+ printk(KERN_ERR "NAND erase fail interrupt!\n");882882+ process_prog_erase_fail_int(cur_desc);883883+ event = EVENT_ERASE_FAILURE;884884+ break;885885+ } else {886886+ cdma_int_status = ioread32(FlashReg + DMA_INTR);887887+ if (cdma_int_status & dma_intr_bit[info.flash_bank]) {888888+ iowrite32(dma_intr_bit[info.flash_bank],889889+ FlashReg + DMA_INTR);890890+ update_event_status();891891+ event = EVENT_PASS;892892+ break;893893+ }894894+ }895895+ }896896+897897+ int_status = ioread32(FlashReg + ints_addr[info.flash_bank]);898898+ iowrite32(int_status, FlashReg + ints_addr[info.flash_bank]);899899+ cdma_int_status = ioread32(FlashReg + DMA_INTR);900900+ iowrite32(cdma_int_status, FlashReg + DMA_INTR);901901+902902+ iowrite32(0, FlashReg + DMA_ENABLE);903903+ while ((ioread32(FlashReg + DMA_ENABLE) & DMA_ENABLE__FLAG))904904+ ;905905+906906+ return event;907907+}908908+909909+910910+
+123
drivers/staging/spectra/lld_cdma.h
···11+/*22+ * NAND Flash Controller Device Driver33+ * Copyright (c) 2009, Intel Corporation and its suppliers.44+ *55+ * This program is free software; you can redistribute it and/or modify it66+ * under the terms and conditions of the GNU General Public License,77+ * version 2, as published by the Free Software Foundation.88+ *99+ * This program is distributed in the hope it will be useful, but WITHOUT1010+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or1111+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for1212+ * more details.1313+ *1414+ * You should have received a copy of the GNU General Public License along with1515+ * this program; if not, write to the Free Software Foundation, Inc.,1616+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.1717+ *1818+ */1919+2020+/* header for LLD_CDMA.c module */2121+2222+#ifndef _LLD_CDMA_2323+#define _LLD_CDMA_2424+2525+#include "flash.h"2626+2727+#define DEBUG_SYNC 12828+2929+/*/////////// CDMA specific MACRO definition */3030+#define MAX_DESCS (255)3131+#define MAX_CHANS (4)3232+#define MAX_SYNC_POINTS (16)3333+#define MAX_DESC_PER_CHAN (MAX_DESCS * 3 + MAX_SYNC_POINTS + 2)3434+3535+#define CHANNEL_SYNC_MASK (0x000F)3636+#define CHANNEL_DMA_MASK (0x00F0)3737+#define CHANNEL_ID_MASK (0x0300)3838+#define CHANNEL_CONT_MASK (0x4000)3939+#define CHANNEL_INTR_MASK (0x8000)4040+4141+#define CHANNEL_SYNC_OFFSET (0)4242+#define CHANNEL_DMA_OFFSET (4)4343+#define CHANNEL_ID_OFFSET (8)4444+#define CHANNEL_CONT_OFFSET (14)4545+#define CHANNEL_INTR_OFFSET (15)4646+4747+u16 CDMA_Data_CMD(u8 cmd, u8 *data, u32 block, u16 page, u16 num, u16 flags);4848+u16 CDMA_MemCopy_CMD(u8 *dest, u8 *src, u32 byte_cnt, u16 flags);4949+u16 CDMA_Execute_CMDs(void);5050+void print_pending_cmds(void);5151+void print_cdma_descriptors(void);5252+5353+extern u8 g_SBDCmdIndex;5454+extern struct mrst_nand_info info;5555+5656+5757+/*/////////// prototypes: APIs for LLD_CDMA */5858+int is_cdma_interrupt(void);5959+u16 CDMA_Event_Status(void);6060+6161+/* CMD-DMA Descriptor Struct. These are defined by the CMD_DMA HW */6262+struct cdma_descriptor {6363+ u32 NxtPointerHi;6464+ u32 NxtPointerLo;6565+ u32 FlashPointerHi;6666+ u32 FlashPointerLo;6767+ u32 CommandType;6868+ u32 MemAddrHi;6969+ u32 MemAddrLo;7070+ u32 CommandFlags;7171+ u32 Channel;7272+ u32 Status;7373+ u32 MemCopyPointerHi;7474+ u32 MemCopyPointerLo;7575+ u32 Reserved12;7676+ u32 Reserved13;7777+ u32 Reserved14;7878+ u32 pcmd; /* pending cmd num related to this descriptor */7979+};8080+8181+/* This struct holds one MemCopy descriptor as defined by the HW */8282+struct memcpy_descriptor {8383+ u32 NxtPointerHi;8484+ u32 NxtPointerLo;8585+ u32 SrcAddrHi;8686+ u32 SrcAddrLo;8787+ u32 DestAddrHi;8888+ u32 DestAddrLo;8989+ u32 XferSize;9090+ u32 MemCopyFlags;9191+ u32 MemCopyStatus;9292+ u32 reserved9;9393+ u32 reserved10;9494+ u32 reserved11;9595+ u32 reserved12;9696+ u32 reserved13;9797+ u32 reserved14;9898+ u32 reserved15;9999+};100100+101101+/* Pending CMD table entries (includes MemCopy parameters */102102+struct pending_cmd {103103+ u8 CMD;104104+ u8 *DataAddr;105105+ u32 Block;106106+ u16 Page;107107+ u16 PageCount;108108+ u8 *DataDestAddr;109109+ u8 *DataSrcAddr;110110+ u32 MemCopyByteCnt;111111+ u16 Flags;112112+ u16 Status;113113+};114114+115115+#if DEBUG_SYNC116116+extern u32 debug_sync_cnt;117117+#endif118118+119119+/* Definitions for CMD DMA descriptor chain fields */120120+#define CMD_DMA_DESC_COMP 0x8000121121+#define CMD_DMA_DESC_FAIL 0x4000122122+123123+#endif /*_LLD_CDMA_*/
+780
drivers/staging/spectra/lld_emu.c
···11+/*22+ * NAND Flash Controller Device Driver33+ * Copyright (c) 2009, Intel Corporation and its suppliers.44+ *55+ * This program is free software; you can redistribute it and/or modify it66+ * under the terms and conditions of the GNU General Public License,77+ * version 2, as published by the Free Software Foundation.88+ *99+ * This program is distributed in the hope it will be useful, but WITHOUT1010+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or1111+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for1212+ * more details.1313+ *1414+ * You should have received a copy of the GNU General Public License along with1515+ * this program; if not, write to the Free Software Foundation, Inc.,1616+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.1717+ *1818+ */1919+2020+#include <linux/fs.h>2121+#include <linux/slab.h>2222+#include "flash.h"2323+#include "ffsdefs.h"2424+#include "lld_emu.h"2525+#include "lld.h"2626+#if CMD_DMA2727+#include "lld_cdma.h"2828+#endif2929+3030+#define GLOB_LLD_PAGES 643131+#define GLOB_LLD_PAGE_SIZE (512+16)3232+#define GLOB_LLD_PAGE_DATA_SIZE 5123333+#define GLOB_LLD_BLOCKS 20483434+3535+#if (CMD_DMA && FLASH_EMU)3636+#include "lld_cdma.h"3737+u32 totalUsedBanks;3838+u32 valid_banks[MAX_CHANS];3939+#endif4040+4141+#if FLASH_EMU /* This is for entire module */4242+4343+static u8 *flash_memory[GLOB_LLD_BLOCKS * GLOB_LLD_PAGES];4444+4545+/* Read nand emu file and then fill it's content to flash_memory */4646+int emu_load_file_to_mem(void)4747+{4848+ mm_segment_t fs;4949+ struct file *nef_filp = NULL;5050+ struct inode *inode = NULL;5151+ loff_t nef_size = 0;5252+ loff_t tmp_file_offset, file_offset;5353+ ssize_t nread;5454+ int i, rc = -EINVAL;5555+5656+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",5757+ __FILE__, __LINE__, __func__);5858+5959+ fs = get_fs();6060+ set_fs(get_ds());6161+6262+ nef_filp = filp_open("/root/nand_emu_file", O_RDWR | O_LARGEFILE, 0);6363+ if (IS_ERR(nef_filp)) {6464+ printk(KERN_ERR "filp_open error: "6565+ "Unable to open nand emu file!\n");6666+ return PTR_ERR(nef_filp);6767+ }6868+6969+ if (nef_filp->f_path.dentry) {7070+ inode = nef_filp->f_path.dentry->d_inode;7171+ } else {7272+ printk(KERN_ERR "Can not get valid inode!\n");7373+ goto out;7474+ }7575+7676+ nef_size = i_size_read(inode->i_mapping->host);7777+ if (nef_size <= 0) {7878+ printk(KERN_ERR "Invalid nand emu file size: "7979+ "0x%llx\n", nef_size);8080+ goto out;8181+ } else {8282+ nand_dbg_print(NAND_DBG_DEBUG, "nand emu file size: %lld\n",8383+ nef_size);8484+ }8585+8686+ file_offset = 0;8787+ for (i = 0; i < GLOB_LLD_BLOCKS * GLOB_LLD_PAGES; i++) {8888+ tmp_file_offset = file_offset;8989+ nread = vfs_read(nef_filp,9090+ (char __user *)flash_memory[i],9191+ GLOB_LLD_PAGE_SIZE, &tmp_file_offset);9292+ if (nread < GLOB_LLD_PAGE_SIZE) {9393+ printk(KERN_ERR "%s, Line %d - "9494+ "nand emu file partial read: "9595+ "%d bytes\n", __FILE__, __LINE__, (int)nread);9696+ goto out;9797+ }9898+ file_offset += GLOB_LLD_PAGE_SIZE;9999+ }100100+ rc = 0;101101+102102+out:103103+ filp_close(nef_filp, current->files);104104+ set_fs(fs);105105+ return rc;106106+}107107+108108+/* Write contents of flash_memory to nand emu file */109109+int emu_write_mem_to_file(void)110110+{111111+ mm_segment_t fs;112112+ struct file *nef_filp = NULL;113113+ struct inode *inode = NULL;114114+ loff_t nef_size = 0;115115+ loff_t tmp_file_offset, file_offset;116116+ ssize_t nwritten;117117+ int i, rc = -EINVAL;118118+119119+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",120120+ __FILE__, __LINE__, __func__);121121+122122+ fs = get_fs();123123+ set_fs(get_ds());124124+125125+ nef_filp = filp_open("/root/nand_emu_file", O_RDWR | O_LARGEFILE, 0);126126+ if (IS_ERR(nef_filp)) {127127+ printk(KERN_ERR "filp_open error: "128128+ "Unable to open nand emu file!\n");129129+ return PTR_ERR(nef_filp);130130+ }131131+132132+ if (nef_filp->f_path.dentry) {133133+ inode = nef_filp->f_path.dentry->d_inode;134134+ } else {135135+ printk(KERN_ERR "Invalid " "nef_filp->f_path.dentry value!\n");136136+ goto out;137137+ }138138+139139+ nef_size = i_size_read(inode->i_mapping->host);140140+ if (nef_size <= 0) {141141+ printk(KERN_ERR "Invalid "142142+ "nand emu file size: 0x%llx\n", nef_size);143143+ goto out;144144+ } else {145145+ nand_dbg_print(NAND_DBG_DEBUG, "nand emu file size: "146146+ "%lld\n", nef_size);147147+ }148148+149149+ file_offset = 0;150150+ for (i = 0; i < GLOB_LLD_BLOCKS * GLOB_LLD_PAGES; i++) {151151+ tmp_file_offset = file_offset;152152+ nwritten = vfs_write(nef_filp,153153+ (char __user *)flash_memory[i],154154+ GLOB_LLD_PAGE_SIZE, &tmp_file_offset);155155+ if (nwritten < GLOB_LLD_PAGE_SIZE) {156156+ printk(KERN_ERR "%s, Line %d - "157157+ "nand emu file partial write: "158158+ "%d bytes\n", __FILE__, __LINE__, (int)nwritten);159159+ goto out;160160+ }161161+ file_offset += GLOB_LLD_PAGE_SIZE;162162+ }163163+ rc = 0;164164+165165+out:166166+ filp_close(nef_filp, current->files);167167+ set_fs(fs);168168+ return rc;169169+}170170+171171+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&172172+* Function: emu_Flash_Init173173+* Inputs: none174174+* Outputs: PASS=0 (notice 0=ok here)175175+* Description: Creates & initializes the flash RAM array.176176+*177177+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/178178+u16 emu_Flash_Init(void)179179+{180180+ int i;181181+182182+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",183183+ __FILE__, __LINE__, __func__);184184+185185+ flash_memory[0] = (u8 *)vmalloc(GLOB_LLD_PAGE_SIZE *186186+ GLOB_LLD_BLOCKS *187187+ GLOB_LLD_PAGES *188188+ sizeof(u8));189189+ if (!flash_memory[0]) {190190+ printk(KERN_ERR "Fail to allocate memory "191191+ "for nand emulator!\n");192192+ return ERR;193193+ }194194+195195+ memset((char *)(flash_memory[0]), 0xFF,196196+ GLOB_LLD_PAGE_SIZE * GLOB_LLD_BLOCKS * GLOB_LLD_PAGES *197197+ sizeof(u8));198198+199199+ for (i = 1; i < GLOB_LLD_BLOCKS * GLOB_LLD_PAGES; i++)200200+ flash_memory[i] = flash_memory[i - 1] + GLOB_LLD_PAGE_SIZE;201201+202202+ emu_load_file_to_mem(); /* Load nand emu file to mem */203203+204204+ return PASS;205205+}206206+207207+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&208208+* Function: emu_Flash_Release209209+* Inputs: none210210+* Outputs: PASS=0 (notice 0=ok here)211211+* Description: Releases the flash.212212+*213213+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/214214+int emu_Flash_Release(void)215215+{216216+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",217217+ __FILE__, __LINE__, __func__);218218+219219+ emu_write_mem_to_file(); /* Write back mem to nand emu file */220220+221221+ vfree(flash_memory[0]);222222+ return PASS;223223+}224224+225225+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&226226+* Function: emu_Read_Device_ID227227+* Inputs: none228228+* Outputs: PASS=1 FAIL=0229229+* Description: Reads the info from the controller registers.230230+* Sets up DeviceInfo structure with device parameters231231+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/232232+233233+u16 emu_Read_Device_ID(void)234234+{235235+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",236236+ __FILE__, __LINE__, __func__);237237+238238+ DeviceInfo.wDeviceMaker = 0;239239+ DeviceInfo.wDeviceType = 8;240240+ DeviceInfo.wSpectraStartBlock = 36;241241+ DeviceInfo.wSpectraEndBlock = GLOB_LLD_BLOCKS - 1;242242+ DeviceInfo.wTotalBlocks = GLOB_LLD_BLOCKS;243243+ DeviceInfo.wPagesPerBlock = GLOB_LLD_PAGES;244244+ DeviceInfo.wPageSize = GLOB_LLD_PAGE_SIZE;245245+ DeviceInfo.wPageDataSize = GLOB_LLD_PAGE_DATA_SIZE;246246+ DeviceInfo.wPageSpareSize = GLOB_LLD_PAGE_SIZE -247247+ GLOB_LLD_PAGE_DATA_SIZE;248248+ DeviceInfo.wBlockSize = DeviceInfo.wPageSize * GLOB_LLD_PAGES;249249+ DeviceInfo.wBlockDataSize = DeviceInfo.wPageDataSize * GLOB_LLD_PAGES;250250+ DeviceInfo.wDataBlockNum = (u32) (DeviceInfo.wSpectraEndBlock -251251+ DeviceInfo.wSpectraStartBlock252252+ + 1);253253+ DeviceInfo.MLCDevice = 1; /* Emulate MLC device */254254+ DeviceInfo.nBitsInPageNumber =255255+ (u8)GLOB_Calc_Used_Bits(DeviceInfo.wPagesPerBlock);256256+ DeviceInfo.nBitsInPageDataSize =257257+ (u8)GLOB_Calc_Used_Bits(DeviceInfo.wPageDataSize);258258+ DeviceInfo.nBitsInBlockDataSize =259259+ (u8)GLOB_Calc_Used_Bits(DeviceInfo.wBlockDataSize);260260+261261+#if CMD_DMA262262+ totalUsedBanks = 4;263263+ valid_banks[0] = 1;264264+ valid_banks[1] = 1;265265+ valid_banks[2] = 1;266266+ valid_banks[3] = 1;267267+#endif268268+269269+ return PASS;270270+}271271+272272+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&273273+* Function: emu_Flash_Reset274274+* Inputs: none275275+* Outputs: PASS=0 (notice 0=ok here)276276+* Description: Reset the flash277277+*278278+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/279279+u16 emu_Flash_Reset(void)280280+{281281+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",282282+ __FILE__, __LINE__, __func__);283283+284284+ return PASS;285285+}286286+287287+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&288288+* Function: emu_Erase_Block289289+* Inputs: Address290290+* Outputs: PASS=0 (notice 0=ok here)291291+* Description: Erase a block292292+*293293+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/294294+u16 emu_Erase_Block(u32 block_add)295295+{296296+ int i;297297+298298+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",299299+ __FILE__, __LINE__, __func__);300300+301301+ if (block_add >= DeviceInfo.wTotalBlocks) {302302+ printk(KERN_ERR "emu_Erase_Block error! "303303+ "Too big block address: %d\n", block_add);304304+ return FAIL;305305+ }306306+307307+ nand_dbg_print(NAND_DBG_DEBUG, "Erasing block %d\n",308308+ (int)block_add);309309+310310+ for (i = block_add * GLOB_LLD_PAGES;311311+ i < ((block_add + 1) * GLOB_LLD_PAGES); i++) {312312+ if (flash_memory[i]) {313313+ memset((u8 *)(flash_memory[i]), 0xFF,314314+ DeviceInfo.wPageSize * sizeof(u8));315315+ }316316+ }317317+318318+ return PASS;319319+}320320+321321+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&322322+* Function: emu_Write_Page_Main323323+* Inputs: Write buffer address pointer324324+* Block number325325+* Page number326326+* Number of pages to process327327+* Outputs: PASS=0 (notice 0=ok here)328328+* Description: Write the data in the buffer to main area of flash329329+*330330+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/331331+u16 emu_Write_Page_Main(u8 *write_data, u32 Block,332332+ u16 Page, u16 PageCount)333333+{334334+ int i;335335+336336+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",337337+ __FILE__, __LINE__, __func__);338338+339339+ if (Block >= DeviceInfo.wTotalBlocks)340340+ return FAIL;341341+342342+ if (Page + PageCount > DeviceInfo.wPagesPerBlock)343343+ return FAIL;344344+345345+ nand_dbg_print(NAND_DBG_DEBUG, "emu_Write_Page_Main: "346346+ "lba %u Page %u PageCount %u\n",347347+ (unsigned int)Block,348348+ (unsigned int)Page, (unsigned int)PageCount);349349+350350+ for (i = 0; i < PageCount; i++) {351351+ if (NULL == flash_memory[Block * GLOB_LLD_PAGES + Page]) {352352+ printk(KERN_ERR "Run out of memory\n");353353+ return FAIL;354354+ }355355+ memcpy((u8 *) (flash_memory[Block * GLOB_LLD_PAGES + Page]),356356+ write_data, DeviceInfo.wPageDataSize);357357+ write_data += DeviceInfo.wPageDataSize;358358+ Page++;359359+ }360360+361361+ return PASS;362362+}363363+364364+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&365365+* Function: emu_Read_Page_Main366366+* Inputs: Read buffer address pointer367367+* Block number368368+* Page number369369+* Number of pages to process370370+* Outputs: PASS=0 (notice 0=ok here)371371+* Description: Read the data from the flash main area to the buffer372372+*373373+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/374374+u16 emu_Read_Page_Main(u8 *read_data, u32 Block,375375+ u16 Page, u16 PageCount)376376+{377377+ int i;378378+379379+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",380380+ __FILE__, __LINE__, __func__);381381+382382+ if (Block >= DeviceInfo.wTotalBlocks)383383+ return FAIL;384384+385385+ if (Page + PageCount > DeviceInfo.wPagesPerBlock)386386+ return FAIL;387387+388388+ nand_dbg_print(NAND_DBG_DEBUG, "emu_Read_Page_Main: "389389+ "lba %u Page %u PageCount %u\n",390390+ (unsigned int)Block,391391+ (unsigned int)Page, (unsigned int)PageCount);392392+393393+ for (i = 0; i < PageCount; i++) {394394+ if (NULL == flash_memory[Block * GLOB_LLD_PAGES + Page]) {395395+ memset(read_data, 0xFF, DeviceInfo.wPageDataSize);396396+ } else {397397+ memcpy(read_data,398398+ (u8 *) (flash_memory[Block * GLOB_LLD_PAGES399399+ + Page]),400400+ DeviceInfo.wPageDataSize);401401+ }402402+ read_data += DeviceInfo.wPageDataSize;403403+ Page++;404404+ }405405+406406+ return PASS;407407+}408408+409409+#ifndef ELDORA410410+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&411411+* Function: emu_Read_Page_Main_Spare412412+* Inputs: Write Buffer413413+* Address414414+* Buffer size415415+* Outputs: PASS=0 (notice 0=ok here)416416+* Description: Read from flash main+spare area417417+*418418+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/419419+u16 emu_Read_Page_Main_Spare(u8 *read_data, u32 Block,420420+ u16 Page, u16 PageCount)421421+{422422+ int i;423423+424424+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",425425+ __FILE__, __LINE__, __func__);426426+427427+ if (Block >= DeviceInfo.wTotalBlocks) {428428+ printk(KERN_ERR "Read Page Main+Spare "429429+ "Error: Block Address too big\n");430430+ return FAIL;431431+ }432432+433433+ if (Page + PageCount > DeviceInfo.wPagesPerBlock) {434434+ printk(KERN_ERR "Read Page Main+Spare "435435+ "Error: Page number too big\n");436436+ return FAIL;437437+ }438438+439439+ nand_dbg_print(NAND_DBG_DEBUG, "Read Page Main + Spare - "440440+ "No. of pages %u block %u start page %u\n",441441+ (unsigned int)PageCount,442442+ (unsigned int)Block, (unsigned int)Page);443443+444444+ for (i = 0; i < PageCount; i++) {445445+ if (NULL == flash_memory[Block * GLOB_LLD_PAGES + Page]) {446446+ memset(read_data, 0xFF, DeviceInfo.wPageSize);447447+ } else {448448+ memcpy(read_data, (u8 *) (flash_memory[Block *449449+ GLOB_LLD_PAGES450450+ + Page]),451451+ DeviceInfo.wPageSize);452452+ }453453+454454+ read_data += DeviceInfo.wPageSize;455455+ Page++;456456+ }457457+458458+ return PASS;459459+}460460+461461+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&462462+* Function: emu_Write_Page_Main_Spare463463+* Inputs: Write buffer464464+* address465465+* buffer length466466+* Outputs: PASS=0 (notice 0=ok here)467467+* Description: Write the buffer to main+spare area of flash468468+*469469+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/470470+u16 emu_Write_Page_Main_Spare(u8 *write_data, u32 Block,471471+ u16 Page, u16 page_count)472472+{473473+ u16 i;474474+475475+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",476476+ __FILE__, __LINE__, __func__);477477+478478+ if (Block >= DeviceInfo.wTotalBlocks) {479479+ printk(KERN_ERR "Write Page Main + Spare "480480+ "Error: Block Address too big\n");481481+ return FAIL;482482+ }483483+484484+ if (Page + page_count > DeviceInfo.wPagesPerBlock) {485485+ printk(KERN_ERR "Write Page Main + Spare "486486+ "Error: Page number too big\n");487487+ return FAIL;488488+ }489489+490490+ nand_dbg_print(NAND_DBG_DEBUG, "Write Page Main+Spare - "491491+ "No. of pages %u block %u start page %u\n",492492+ (unsigned int)page_count,493493+ (unsigned int)Block, (unsigned int)Page);494494+495495+ for (i = 0; i < page_count; i++) {496496+ if (NULL == flash_memory[Block * GLOB_LLD_PAGES + Page]) {497497+ printk(KERN_ERR "Run out of memory!\n");498498+ return FAIL;499499+ }500500+ memcpy((u8 *) (flash_memory[Block * GLOB_LLD_PAGES + Page]),501501+ write_data, DeviceInfo.wPageSize);502502+ write_data += DeviceInfo.wPageSize;503503+ Page++;504504+ }505505+506506+ return PASS;507507+}508508+509509+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&510510+* Function: emu_Write_Page_Spare511511+* Inputs: Write buffer512512+* Address513513+* buffer size514514+* Outputs: PASS=0 (notice 0=ok here)515515+* Description: Write the buffer in the spare area516516+*517517+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/518518+u16 emu_Write_Page_Spare(u8 *write_data, u32 Block,519519+ u16 Page, u16 PageCount)520520+{521521+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",522522+ __FILE__, __LINE__, __func__);523523+524524+ if (Block >= DeviceInfo.wTotalBlocks) {525525+ printk(KERN_ERR "Read Page Spare Error: "526526+ "Block Address too big\n");527527+ return FAIL;528528+ }529529+530530+ if (Page + PageCount > DeviceInfo.wPagesPerBlock) {531531+ printk(KERN_ERR "Read Page Spare Error: "532532+ "Page number too big\n");533533+ return FAIL;534534+ }535535+536536+ nand_dbg_print(NAND_DBG_DEBUG, "Write Page Spare- "537537+ "block %u page %u\n",538538+ (unsigned int)Block, (unsigned int)Page);539539+540540+ if (NULL == flash_memory[Block * GLOB_LLD_PAGES + Page]) {541541+ printk(KERN_ERR "Run out of memory!\n");542542+ return FAIL;543543+ }544544+545545+ memcpy((u8 *) (flash_memory[Block * GLOB_LLD_PAGES + Page] +546546+ DeviceInfo.wPageDataSize), write_data,547547+ (DeviceInfo.wPageSize - DeviceInfo.wPageDataSize));548548+549549+ return PASS;550550+}551551+552552+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&553553+* Function: emu_Read_Page_Spare554554+* Inputs: Write Buffer555555+* Address556556+* Buffer size557557+* Outputs: PASS=0 (notice 0=ok here)558558+* Description: Read data from the spare area559559+*560560+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/561561+u16 emu_Read_Page_Spare(u8 *write_data, u32 Block,562562+ u16 Page, u16 PageCount)563563+{564564+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",565565+ __FILE__, __LINE__, __func__);566566+567567+ if (Block >= DeviceInfo.wTotalBlocks) {568568+ printk(KERN_ERR "Read Page Spare "569569+ "Error: Block Address too big\n");570570+ return FAIL;571571+ }572572+573573+ if (Page + PageCount > DeviceInfo.wPagesPerBlock) {574574+ printk(KERN_ERR "Read Page Spare "575575+ "Error: Page number too big\n");576576+ return FAIL;577577+ }578578+579579+ nand_dbg_print(NAND_DBG_DEBUG, "Read Page Spare- "580580+ "block %u page %u\n",581581+ (unsigned int)Block, (unsigned int)Page);582582+583583+ if (NULL == flash_memory[Block * GLOB_LLD_PAGES + Page]) {584584+ memset(write_data, 0xFF,585585+ (DeviceInfo.wPageSize - DeviceInfo.wPageDataSize));586586+ } else {587587+ memcpy(write_data,588588+ (u8 *) (flash_memory[Block * GLOB_LLD_PAGES + Page]589589+ + DeviceInfo.wPageDataSize),590590+ (DeviceInfo.wPageSize - DeviceInfo.wPageDataSize));591591+ }592592+593593+ return PASS;594594+}595595+596596+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&597597+* Function: emu_Enable_Disable_Interrupts598598+* Inputs: enable or disable599599+* Outputs: none600600+* Description: NOP601601+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/602602+void emu_Enable_Disable_Interrupts(u16 INT_ENABLE)603603+{604604+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",605605+ __FILE__, __LINE__, __func__);606606+}607607+608608+u16 emu_Get_Bad_Block(u32 block)609609+{610610+ return 0;611611+}612612+613613+#if CMD_DMA614614+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&615615+* Support for CDMA functions616616+************************************617617+* emu_CDMA_Flash_Init618618+* CDMA_process_data command (use LLD_CDMA)619619+* CDMA_MemCopy_CMD (use LLD_CDMA)620620+* emu_CDMA_execute all commands621621+* emu_CDMA_Event_Status622622+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/623623+u16 emu_CDMA_Flash_Init(void)624624+{625625+ u16 i;626626+627627+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",628628+ __FILE__, __LINE__, __func__);629629+630630+ for (i = 0; i < MAX_DESCS + MAX_CHANS; i++) {631631+ PendingCMD[i].CMD = 0;632632+ PendingCMD[i].Tag = 0;633633+ PendingCMD[i].DataAddr = 0;634634+ PendingCMD[i].Block = 0;635635+ PendingCMD[i].Page = 0;636636+ PendingCMD[i].PageCount = 0;637637+ PendingCMD[i].DataDestAddr = 0;638638+ PendingCMD[i].DataSrcAddr = 0;639639+ PendingCMD[i].MemCopyByteCnt = 0;640640+ PendingCMD[i].ChanSync[0] = 0;641641+ PendingCMD[i].ChanSync[1] = 0;642642+ PendingCMD[i].ChanSync[2] = 0;643643+ PendingCMD[i].ChanSync[3] = 0;644644+ PendingCMD[i].ChanSync[4] = 0;645645+ PendingCMD[i].Status = 3;646646+ }647647+648648+ return PASS;649649+}650650+651651+static void emu_isr(int irq, void *dev_id)652652+{653653+ /* TODO: ... */654654+}655655+656656+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&657657+* Function: CDMA_Execute_CMDs658658+* Inputs: tag_count: the number of pending cmds to do659659+* Outputs: PASS/FAIL660660+* Description: execute each command in the pending CMD array661661+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/662662+u16 emu_CDMA_Execute_CMDs(u16 tag_count)663663+{664664+ u16 i, j;665665+ u8 CMD; /* cmd parameter */666666+ u8 *data;667667+ u32 block;668668+ u16 page;669669+ u16 count;670670+ u16 status = PASS;671671+672672+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",673673+ __FILE__, __LINE__, __func__);674674+675675+ nand_dbg_print(NAND_DBG_TRACE, "At start of Execute CMDs: "676676+ "Tag Count %u\n", tag_count);677677+678678+ for (i = 0; i < totalUsedBanks; i++) {679679+ PendingCMD[i].CMD = DUMMY_CMD;680680+ PendingCMD[i].Tag = 0xFF;681681+ PendingCMD[i].Block =682682+ (DeviceInfo.wTotalBlocks / totalUsedBanks) * i;683683+684684+ for (j = 0; j <= MAX_CHANS; j++)685685+ PendingCMD[i].ChanSync[j] = 0;686686+ }687687+688688+ CDMA_Execute_CMDs(tag_count);689689+690690+ print_pending_cmds(tag_count);691691+692692+#if DEBUG_SYNC693693+ }694694+ debug_sync_cnt++;695695+#endif696696+697697+ for (i = MAX_CHANS;698698+ i < tag_count + MAX_CHANS; i++) {699699+ CMD = PendingCMD[i].CMD;700700+ data = PendingCMD[i].DataAddr;701701+ block = PendingCMD[i].Block;702702+ page = PendingCMD[i].Page;703703+ count = PendingCMD[i].PageCount;704704+705705+ switch (CMD) {706706+ case ERASE_CMD:707707+ emu_Erase_Block(block);708708+ PendingCMD[i].Status = PASS;709709+ break;710710+ case WRITE_MAIN_CMD:711711+ emu_Write_Page_Main(data, block, page, count);712712+ PendingCMD[i].Status = PASS;713713+ break;714714+ case WRITE_MAIN_SPARE_CMD:715715+ emu_Write_Page_Main_Spare(data, block, page, count);716716+ PendingCMD[i].Status = PASS;717717+ break;718718+ case READ_MAIN_CMD:719719+ emu_Read_Page_Main(data, block, page, count);720720+ PendingCMD[i].Status = PASS;721721+ break;722722+ case MEMCOPY_CMD:723723+ memcpy(PendingCMD[i].DataDestAddr,724724+ PendingCMD[i].DataSrcAddr,725725+ PendingCMD[i].MemCopyByteCnt);726726+ case DUMMY_CMD:727727+ PendingCMD[i].Status = PASS;728728+ break;729729+ default:730730+ PendingCMD[i].Status = FAIL;731731+ break;732732+ }733733+ }734734+735735+ /*736736+ * Temperory adding code to reset PendingCMD array for basic testing.737737+ * It should be done at the end of event status function.738738+ */739739+ for (i = tag_count + MAX_CHANS; i < MAX_DESCS; i++) {740740+ PendingCMD[i].CMD = 0;741741+ PendingCMD[i].Tag = 0;742742+ PendingCMD[i].DataAddr = 0;743743+ PendingCMD[i].Block = 0;744744+ PendingCMD[i].Page = 0;745745+ PendingCMD[i].PageCount = 0;746746+ PendingCMD[i].DataDestAddr = 0;747747+ PendingCMD[i].DataSrcAddr = 0;748748+ PendingCMD[i].MemCopyByteCnt = 0;749749+ PendingCMD[i].ChanSync[0] = 0;750750+ PendingCMD[i].ChanSync[1] = 0;751751+ PendingCMD[i].ChanSync[2] = 0;752752+ PendingCMD[i].ChanSync[3] = 0;753753+ PendingCMD[i].ChanSync[4] = 0;754754+ PendingCMD[i].Status = CMD_NOT_DONE;755755+ }756756+757757+ nand_dbg_print(NAND_DBG_TRACE, "At end of Execute CMDs.\n");758758+759759+ emu_isr(0, 0); /* This is a null isr now. Need fill it in future */760760+761761+ return status;762762+}763763+764764+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&765765+* Function: emu_Event_Status766766+* Inputs: none767767+* Outputs: Event_Status code768768+* Description: This function can also be used to force errors769769+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/770770+u16 emu_CDMA_Event_Status(void)771771+{772772+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",773773+ __FILE__, __LINE__, __func__);774774+775775+ return EVENT_PASS;776776+}777777+778778+#endif /* CMD_DMA */779779+#endif /* !ELDORA */780780+#endif /* FLASH_EMU */
+51
drivers/staging/spectra/lld_emu.h
···11+/*22+ * NAND Flash Controller Device Driver33+ * Copyright (c) 2009, Intel Corporation and its suppliers.44+ *55+ * This program is free software; you can redistribute it and/or modify it66+ * under the terms and conditions of the GNU General Public License,77+ * version 2, as published by the Free Software Foundation.88+ *99+ * This program is distributed in the hope it will be useful, but WITHOUT1010+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or1111+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for1212+ * more details.1313+ *1414+ * You should have received a copy of the GNU General Public License along with1515+ * this program; if not, write to the Free Software Foundation, Inc.,1616+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.1717+ *1818+ */1919+2020+#ifndef _LLD_EMU_2121+#define _LLD_EMU_2222+2323+#include "ffsport.h"2424+#include "ffsdefs.h"2525+2626+/* prototypes: emulator API functions */2727+extern u16 emu_Flash_Reset(void);2828+extern u16 emu_Flash_Init(void);2929+extern int emu_Flash_Release(void);3030+extern u16 emu_Read_Device_ID(void);3131+extern u16 emu_Erase_Block(u32 block_addr);3232+extern u16 emu_Write_Page_Main(u8 *write_data, u32 Block,3333+ u16 Page, u16 PageCount);3434+extern u16 emu_Read_Page_Main(u8 *read_data, u32 Block, u16 Page,3535+ u16 PageCount);3636+extern u16 emu_Event_Status(void);3737+extern void emu_Enable_Disable_Interrupts(u16 INT_ENABLE);3838+extern u16 emu_Write_Page_Main_Spare(u8 *write_data, u32 Block,3939+ u16 Page, u16 PageCount);4040+extern u16 emu_Write_Page_Spare(u8 *write_data, u32 Block,4141+ u16 Page, u16 PageCount);4242+extern u16 emu_Read_Page_Main_Spare(u8 *read_data, u32 Block,4343+ u16 Page, u16 PageCount);4444+extern u16 emu_Read_Page_Spare(u8 *read_data, u32 Block, u16 Page,4545+ u16 PageCount);4646+extern u16 emu_Get_Bad_Block(u32 block);4747+4848+u16 emu_CDMA_Flash_Init(void);4949+u16 emu_CDMA_Execute_CMDs(u16 tag_count);5050+u16 emu_CDMA_Event_Status(void);5151+#endif /*_LLD_EMU_*/
+687
drivers/staging/spectra/lld_mtd.c
···11+/*22+ * NAND Flash Controller Device Driver33+ * Copyright (c) 2009, Intel Corporation and its suppliers.44+ *55+ * This program is free software; you can redistribute it and/or modify it66+ * under the terms and conditions of the GNU General Public License,77+ * version 2, as published by the Free Software Foundation.88+ *99+ * This program is distributed in the hope it will be useful, but WITHOUT1010+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or1111+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for1212+ * more details.1313+ *1414+ * You should have received a copy of the GNU General Public License along with1515+ * this program; if not, write to the Free Software Foundation, Inc.,1616+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.1717+ *1818+ */1919+2020+#include <linux/fs.h>2121+#include <linux/slab.h>2222+#include <linux/mtd/mtd.h>2323+#include "flash.h"2424+#include "ffsdefs.h"2525+#include "lld_emu.h"2626+#include "lld.h"2727+#if CMD_DMA2828+#include "lld_cdma.h"2929+#endif3030+3131+#define GLOB_LLD_PAGES 643232+#define GLOB_LLD_PAGE_SIZE (512+16)3333+#define GLOB_LLD_PAGE_DATA_SIZE 5123434+#define GLOB_LLD_BLOCKS 20483535+3636+#if CMD_DMA3737+#include "lld_cdma.h"3838+u32 totalUsedBanks;3939+u32 valid_banks[MAX_CHANS];4040+#endif4141+4242+static struct mtd_info *spectra_mtd;4343+static int mtddev = -1;4444+module_param(mtddev, int, 0);4545+4646+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&4747+* Function: mtd_Flash_Init4848+* Inputs: none4949+* Outputs: PASS=0 (notice 0=ok here)5050+* Description: Creates & initializes the flash RAM array.5151+*5252+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/5353+u16 mtd_Flash_Init(void)5454+{5555+ if (mtddev == -1) {5656+ printk(KERN_ERR "No MTD device specified. Give mtddev parameter\n");5757+ return FAIL;5858+ }5959+6060+ spectra_mtd = get_mtd_device(NULL, mtddev);6161+ if (!spectra_mtd) {6262+ printk(KERN_ERR "Failed to obtain MTD device #%d\n", mtddev);6363+ return FAIL;6464+ }6565+6666+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",6767+ __FILE__, __LINE__, __func__);6868+6969+ return PASS;7070+}7171+7272+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&7373+* Function: mtd_Flash_Release7474+* Inputs: none7575+* Outputs: PASS=0 (notice 0=ok here)7676+* Description: Releases the flash.7777+*7878+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/7979+int mtd_Flash_Release(void)8080+{8181+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",8282+ __FILE__, __LINE__, __func__);8383+ if (!spectra_mtd)8484+ return PASS;8585+8686+ put_mtd_device(spectra_mtd);8787+ spectra_mtd = NULL;8888+8989+ return PASS;9090+}9191+9292+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&9393+* Function: mtd_Read_Device_ID9494+* Inputs: none9595+* Outputs: PASS=1 FAIL=09696+* Description: Reads the info from the controller registers.9797+* Sets up DeviceInfo structure with device parameters9898+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/9999+100100+u16 mtd_Read_Device_ID(void)101101+{102102+ uint64_t tmp;103103+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",104104+ __FILE__, __LINE__, __func__);105105+106106+ if (!spectra_mtd)107107+ return FAIL;108108+109109+ DeviceInfo.wDeviceMaker = 0;110110+ DeviceInfo.wDeviceType = 8;111111+ DeviceInfo.wSpectraStartBlock = SPECTRA_START_BLOCK;112112+ tmp = spectra_mtd->size;113113+ do_div(tmp, spectra_mtd->erasesize);114114+ DeviceInfo.wTotalBlocks = tmp;115115+ DeviceInfo.wSpectraEndBlock = DeviceInfo.wTotalBlocks - 1;116116+ DeviceInfo.wPagesPerBlock = spectra_mtd->erasesize / spectra_mtd->writesize;117117+ DeviceInfo.wPageSize = spectra_mtd->writesize + spectra_mtd->oobsize;118118+ DeviceInfo.wPageDataSize = spectra_mtd->writesize;119119+ DeviceInfo.wPageSpareSize = spectra_mtd->oobsize;120120+ DeviceInfo.wBlockSize = DeviceInfo.wPageSize * DeviceInfo.wPagesPerBlock;121121+ DeviceInfo.wBlockDataSize = DeviceInfo.wPageDataSize * DeviceInfo.wPagesPerBlock;122122+ DeviceInfo.wDataBlockNum = (u32) (DeviceInfo.wSpectraEndBlock -123123+ DeviceInfo.wSpectraStartBlock124124+ + 1);125125+ DeviceInfo.MLCDevice = 0;//spectra_mtd->celltype & NAND_CI_CELLTYPE_MSK;126126+ DeviceInfo.nBitsInPageNumber =127127+ (u8)GLOB_Calc_Used_Bits(DeviceInfo.wPagesPerBlock);128128+ DeviceInfo.nBitsInPageDataSize =129129+ (u8)GLOB_Calc_Used_Bits(DeviceInfo.wPageDataSize);130130+ DeviceInfo.nBitsInBlockDataSize =131131+ (u8)GLOB_Calc_Used_Bits(DeviceInfo.wBlockDataSize);132132+133133+#if CMD_DMA134134+ totalUsedBanks = 4;135135+ valid_banks[0] = 1;136136+ valid_banks[1] = 1;137137+ valid_banks[2] = 1;138138+ valid_banks[3] = 1;139139+#endif140140+141141+ return PASS;142142+}143143+144144+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&145145+* Function: mtd_Flash_Reset146146+* Inputs: none147147+* Outputs: PASS=0 (notice 0=ok here)148148+* Description: Reset the flash149149+*150150+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/151151+u16 mtd_Flash_Reset(void)152152+{153153+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",154154+ __FILE__, __LINE__, __func__);155155+156156+ return PASS;157157+}158158+159159+void erase_callback(struct erase_info *e)160160+{161161+ complete((void *)e->priv);162162+}163163+164164+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&165165+* Function: mtd_Erase_Block166166+* Inputs: Address167167+* Outputs: PASS=0 (notice 0=ok here)168168+* Description: Erase a block169169+*170170+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/171171+u16 mtd_Erase_Block(u32 block_add)172172+{173173+ struct erase_info erase;174174+ DECLARE_COMPLETION_ONSTACK(comp);175175+ int ret;176176+177177+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",178178+ __FILE__, __LINE__, __func__);179179+180180+ if (block_add >= DeviceInfo.wTotalBlocks) {181181+ printk(KERN_ERR "mtd_Erase_Block error! "182182+ "Too big block address: %d\n", block_add);183183+ return FAIL;184184+ }185185+186186+ nand_dbg_print(NAND_DBG_DEBUG, "Erasing block %d\n",187187+ (int)block_add);188188+189189+ erase.mtd = spectra_mtd;190190+ erase.callback = erase_callback;191191+ erase.addr = block_add * spectra_mtd->erasesize;192192+ erase.len = spectra_mtd->erasesize;193193+ erase.priv = (unsigned long)∁194194+195195+ ret = spectra_mtd->erase(spectra_mtd, &erase);196196+ if (!ret) {197197+ wait_for_completion(&comp);198198+ if (erase.state != MTD_ERASE_DONE)199199+ ret = -EIO;200200+ }201201+ if (ret) {202202+ printk(KERN_WARNING "mtd_Erase_Block error! "203203+ "erase of region [0x%llx, 0x%llx] failed\n",204204+ erase.addr, erase.len);205205+ return FAIL;206206+ }207207+208208+ return PASS;209209+}210210+211211+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&212212+* Function: mtd_Write_Page_Main213213+* Inputs: Write buffer address pointer214214+* Block number215215+* Page number216216+* Number of pages to process217217+* Outputs: PASS=0 (notice 0=ok here)218218+* Description: Write the data in the buffer to main area of flash219219+*220220+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/221221+u16 mtd_Write_Page_Main(u8 *write_data, u32 Block,222222+ u16 Page, u16 PageCount)223223+{224224+ size_t retlen;225225+ int ret = 0;226226+227227+ if (Block >= DeviceInfo.wTotalBlocks)228228+ return FAIL;229229+230230+ if (Page + PageCount > DeviceInfo.wPagesPerBlock)231231+ return FAIL;232232+233233+ nand_dbg_print(NAND_DBG_DEBUG, "mtd_Write_Page_Main: "234234+ "lba %u Page %u PageCount %u\n",235235+ (unsigned int)Block,236236+ (unsigned int)Page, (unsigned int)PageCount);237237+238238+239239+ while (PageCount) {240240+ ret = spectra_mtd->write(spectra_mtd,241241+ (Block * spectra_mtd->erasesize) + (Page * spectra_mtd->writesize),242242+ DeviceInfo.wPageDataSize, &retlen, write_data);243243+ if (ret) {244244+ printk(KERN_ERR "%s failed %d\n", __func__, ret);245245+ return FAIL;246246+ }247247+ write_data += DeviceInfo.wPageDataSize;248248+ Page++;249249+ PageCount--;250250+ }251251+252252+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",253253+ __FILE__, __LINE__, __func__);254254+255255+ return PASS;256256+}257257+258258+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&259259+* Function: mtd_Read_Page_Main260260+* Inputs: Read buffer address pointer261261+* Block number262262+* Page number263263+* Number of pages to process264264+* Outputs: PASS=0 (notice 0=ok here)265265+* Description: Read the data from the flash main area to the buffer266266+*267267+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/268268+u16 mtd_Read_Page_Main(u8 *read_data, u32 Block,269269+ u16 Page, u16 PageCount)270270+{271271+ size_t retlen;272272+ int ret = 0;273273+274274+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",275275+ __FILE__, __LINE__, __func__);276276+277277+ if (Block >= DeviceInfo.wTotalBlocks)278278+ return FAIL;279279+280280+ if (Page + PageCount > DeviceInfo.wPagesPerBlock)281281+ return FAIL;282282+283283+ nand_dbg_print(NAND_DBG_DEBUG, "mtd_Read_Page_Main: "284284+ "lba %u Page %u PageCount %u\n",285285+ (unsigned int)Block,286286+ (unsigned int)Page, (unsigned int)PageCount);287287+288288+289289+ while (PageCount) {290290+ ret = spectra_mtd->read(spectra_mtd,291291+ (Block * spectra_mtd->erasesize) + (Page * spectra_mtd->writesize),292292+ DeviceInfo.wPageDataSize, &retlen, read_data);293293+ if (ret) {294294+ printk(KERN_ERR "%s failed %d\n", __func__, ret);295295+ return FAIL;296296+ }297297+ read_data += DeviceInfo.wPageDataSize;298298+ Page++;299299+ PageCount--;300300+ }301301+302302+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",303303+ __FILE__, __LINE__, __func__);304304+305305+ return PASS;306306+}307307+308308+#ifndef ELDORA309309+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&310310+* Function: mtd_Read_Page_Main_Spare311311+* Inputs: Write Buffer312312+* Address313313+* Buffer size314314+* Outputs: PASS=0 (notice 0=ok here)315315+* Description: Read from flash main+spare area316316+*317317+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/318318+u16 mtd_Read_Page_Main_Spare(u8 *read_data, u32 Block,319319+ u16 Page, u16 PageCount)320320+{321321+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",322322+ __FILE__, __LINE__, __func__);323323+324324+ if (Block >= DeviceInfo.wTotalBlocks) {325325+ printk(KERN_ERR "Read Page Main+Spare "326326+ "Error: Block Address too big\n");327327+ return FAIL;328328+ }329329+330330+ if (Page + PageCount > DeviceInfo.wPagesPerBlock) {331331+ printk(KERN_ERR "Read Page Main+Spare "332332+ "Error: Page number %d+%d too big in block %d\n",333333+ Page, PageCount, Block);334334+ return FAIL;335335+ }336336+337337+ nand_dbg_print(NAND_DBG_DEBUG, "Read Page Main + Spare - "338338+ "No. of pages %u block %u start page %u\n",339339+ (unsigned int)PageCount,340340+ (unsigned int)Block, (unsigned int)Page);341341+342342+343343+ while (PageCount) {344344+ struct mtd_oob_ops ops;345345+ int ret;346346+347347+ ops.mode = MTD_OOB_AUTO;348348+ ops.datbuf = read_data;349349+ ops.len = DeviceInfo.wPageDataSize;350350+ ops.oobbuf = read_data + DeviceInfo.wPageDataSize + BTSIG_OFFSET;351351+ ops.ooblen = BTSIG_BYTES;352352+ ops.ooboffs = 0;353353+354354+ ret = spectra_mtd->read_oob(spectra_mtd,355355+ (Block * spectra_mtd->erasesize) + (Page * spectra_mtd->writesize),356356+ &ops);357357+ if (ret) {358358+ printk(KERN_ERR "%s failed %d\n", __func__, ret);359359+ return FAIL;360360+ }361361+ read_data += DeviceInfo.wPageSize;362362+ Page++;363363+ PageCount--;364364+ }365365+366366+ return PASS;367367+}368368+369369+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&370370+* Function: mtd_Write_Page_Main_Spare371371+* Inputs: Write buffer372372+* address373373+* buffer length374374+* Outputs: PASS=0 (notice 0=ok here)375375+* Description: Write the buffer to main+spare area of flash376376+*377377+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/378378+u16 mtd_Write_Page_Main_Spare(u8 *write_data, u32 Block,379379+ u16 Page, u16 page_count)380380+{381381+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",382382+ __FILE__, __LINE__, __func__);383383+384384+ if (Block >= DeviceInfo.wTotalBlocks) {385385+ printk(KERN_ERR "Write Page Main + Spare "386386+ "Error: Block Address too big\n");387387+ return FAIL;388388+ }389389+390390+ if (Page + page_count > DeviceInfo.wPagesPerBlock) {391391+ printk(KERN_ERR "Write Page Main + Spare "392392+ "Error: Page number %d+%d too big in block %d\n",393393+ Page, page_count, Block);394394+ WARN_ON(1);395395+ return FAIL;396396+ }397397+398398+ nand_dbg_print(NAND_DBG_DEBUG, "Write Page Main+Spare - "399399+ "No. of pages %u block %u start page %u\n",400400+ (unsigned int)page_count,401401+ (unsigned int)Block, (unsigned int)Page);402402+403403+ while (page_count) {404404+ struct mtd_oob_ops ops;405405+ int ret;406406+407407+ ops.mode = MTD_OOB_AUTO;408408+ ops.datbuf = write_data;409409+ ops.len = DeviceInfo.wPageDataSize;410410+ ops.oobbuf = write_data + DeviceInfo.wPageDataSize + BTSIG_OFFSET;411411+ ops.ooblen = BTSIG_BYTES;412412+ ops.ooboffs = 0;413413+414414+ ret = spectra_mtd->write_oob(spectra_mtd,415415+ (Block * spectra_mtd->erasesize) + (Page * spectra_mtd->writesize),416416+ &ops);417417+ if (ret) {418418+ printk(KERN_ERR "%s failed %d\n", __func__, ret);419419+ return FAIL;420420+ }421421+ write_data += DeviceInfo.wPageSize;422422+ Page++;423423+ page_count--;424424+ }425425+426426+ return PASS;427427+}428428+429429+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&430430+* Function: mtd_Write_Page_Spare431431+* Inputs: Write buffer432432+* Address433433+* buffer size434434+* Outputs: PASS=0 (notice 0=ok here)435435+* Description: Write the buffer in the spare area436436+*437437+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/438438+u16 mtd_Write_Page_Spare(u8 *write_data, u32 Block,439439+ u16 Page, u16 PageCount)440440+{441441+ WARN_ON(1);442442+ return FAIL;443443+}444444+445445+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&446446+* Function: mtd_Read_Page_Spare447447+* Inputs: Write Buffer448448+* Address449449+* Buffer size450450+* Outputs: PASS=0 (notice 0=ok here)451451+* Description: Read data from the spare area452452+*453453+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/454454+u16 mtd_Read_Page_Spare(u8 *read_data, u32 Block,455455+ u16 Page, u16 PageCount)456456+{457457+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",458458+ __FILE__, __LINE__, __func__);459459+460460+ if (Block >= DeviceInfo.wTotalBlocks) {461461+ printk(KERN_ERR "Read Page Spare "462462+ "Error: Block Address too big\n");463463+ return FAIL;464464+ }465465+466466+ if (Page + PageCount > DeviceInfo.wPagesPerBlock) {467467+ printk(KERN_ERR "Read Page Spare "468468+ "Error: Page number too big\n");469469+ return FAIL;470470+ }471471+472472+ nand_dbg_print(NAND_DBG_DEBUG, "Read Page Spare- "473473+ "block %u page %u (%u pages)\n",474474+ (unsigned int)Block, (unsigned int)Page, PageCount);475475+476476+ while (PageCount) {477477+ struct mtd_oob_ops ops;478478+ int ret;479479+480480+ ops.mode = MTD_OOB_AUTO;481481+ ops.datbuf = NULL;482482+ ops.len = 0;483483+ ops.oobbuf = read_data;484484+ ops.ooblen = BTSIG_BYTES;485485+ ops.ooboffs = 0;486486+487487+ ret = spectra_mtd->read_oob(spectra_mtd,488488+ (Block * spectra_mtd->erasesize) + (Page * spectra_mtd->writesize),489489+ &ops);490490+ if (ret) {491491+ printk(KERN_ERR "%s failed %d\n", __func__, ret);492492+ return FAIL;493493+ }494494+495495+ read_data += DeviceInfo.wPageSize;496496+ Page++;497497+ PageCount--;498498+ }499499+500500+ return PASS;501501+}502502+503503+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&504504+* Function: mtd_Enable_Disable_Interrupts505505+* Inputs: enable or disable506506+* Outputs: none507507+* Description: NOP508508+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/509509+void mtd_Enable_Disable_Interrupts(u16 INT_ENABLE)510510+{511511+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",512512+ __FILE__, __LINE__, __func__);513513+}514514+515515+u16 mtd_Get_Bad_Block(u32 block)516516+{517517+ return 0;518518+}519519+520520+#if CMD_DMA521521+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&522522+* Support for CDMA functions523523+************************************524524+* mtd_CDMA_Flash_Init525525+* CDMA_process_data command (use LLD_CDMA)526526+* CDMA_MemCopy_CMD (use LLD_CDMA)527527+* mtd_CDMA_execute all commands528528+* mtd_CDMA_Event_Status529529+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/530530+u16 mtd_CDMA_Flash_Init(void)531531+{532532+ u16 i;533533+534534+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",535535+ __FILE__, __LINE__, __func__);536536+537537+ for (i = 0; i < MAX_DESCS + MAX_CHANS; i++) {538538+ PendingCMD[i].CMD = 0;539539+ PendingCMD[i].Tag = 0;540540+ PendingCMD[i].DataAddr = 0;541541+ PendingCMD[i].Block = 0;542542+ PendingCMD[i].Page = 0;543543+ PendingCMD[i].PageCount = 0;544544+ PendingCMD[i].DataDestAddr = 0;545545+ PendingCMD[i].DataSrcAddr = 0;546546+ PendingCMD[i].MemCopyByteCnt = 0;547547+ PendingCMD[i].ChanSync[0] = 0;548548+ PendingCMD[i].ChanSync[1] = 0;549549+ PendingCMD[i].ChanSync[2] = 0;550550+ PendingCMD[i].ChanSync[3] = 0;551551+ PendingCMD[i].ChanSync[4] = 0;552552+ PendingCMD[i].Status = 3;553553+ }554554+555555+ return PASS;556556+}557557+558558+static void mtd_isr(int irq, void *dev_id)559559+{560560+ /* TODO: ... */561561+}562562+563563+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&564564+* Function: CDMA_Execute_CMDs565565+* Inputs: tag_count: the number of pending cmds to do566566+* Outputs: PASS/FAIL567567+* Description: execute each command in the pending CMD array568568+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/569569+u16 mtd_CDMA_Execute_CMDs(u16 tag_count)570570+{571571+ u16 i, j;572572+ u8 CMD; /* cmd parameter */573573+ u8 *data;574574+ u32 block;575575+ u16 page;576576+ u16 count;577577+ u16 status = PASS;578578+579579+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",580580+ __FILE__, __LINE__, __func__);581581+582582+ nand_dbg_print(NAND_DBG_TRACE, "At start of Execute CMDs: "583583+ "Tag Count %u\n", tag_count);584584+585585+ for (i = 0; i < totalUsedBanks; i++) {586586+ PendingCMD[i].CMD = DUMMY_CMD;587587+ PendingCMD[i].Tag = 0xFF;588588+ PendingCMD[i].Block =589589+ (DeviceInfo.wTotalBlocks / totalUsedBanks) * i;590590+591591+ for (j = 0; j <= MAX_CHANS; j++)592592+ PendingCMD[i].ChanSync[j] = 0;593593+ }594594+595595+ CDMA_Execute_CMDs(tag_count);596596+597597+#ifdef VERBOSE598598+ print_pending_cmds(tag_count);599599+#endif600600+#if DEBUG_SYNC601601+ }602602+ debug_sync_cnt++;603603+#endif604604+605605+ for (i = MAX_CHANS;606606+ i < tag_count + MAX_CHANS; i++) {607607+ CMD = PendingCMD[i].CMD;608608+ data = PendingCMD[i].DataAddr;609609+ block = PendingCMD[i].Block;610610+ page = PendingCMD[i].Page;611611+ count = PendingCMD[i].PageCount;612612+613613+ switch (CMD) {614614+ case ERASE_CMD:615615+ mtd_Erase_Block(block);616616+ PendingCMD[i].Status = PASS;617617+ break;618618+ case WRITE_MAIN_CMD:619619+ mtd_Write_Page_Main(data, block, page, count);620620+ PendingCMD[i].Status = PASS;621621+ break;622622+ case WRITE_MAIN_SPARE_CMD:623623+ mtd_Write_Page_Main_Spare(data, block, page, count);624624+ PendingCMD[i].Status = PASS;625625+ break;626626+ case READ_MAIN_CMD:627627+ mtd_Read_Page_Main(data, block, page, count);628628+ PendingCMD[i].Status = PASS;629629+ break;630630+ case MEMCOPY_CMD:631631+ memcpy(PendingCMD[i].DataDestAddr,632632+ PendingCMD[i].DataSrcAddr,633633+ PendingCMD[i].MemCopyByteCnt);634634+ case DUMMY_CMD:635635+ PendingCMD[i].Status = PASS;636636+ break;637637+ default:638638+ PendingCMD[i].Status = FAIL;639639+ break;640640+ }641641+ }642642+643643+ /*644644+ * Temperory adding code to reset PendingCMD array for basic testing.645645+ * It should be done at the end of event status function.646646+ */647647+ for (i = tag_count + MAX_CHANS; i < MAX_DESCS; i++) {648648+ PendingCMD[i].CMD = 0;649649+ PendingCMD[i].Tag = 0;650650+ PendingCMD[i].DataAddr = 0;651651+ PendingCMD[i].Block = 0;652652+ PendingCMD[i].Page = 0;653653+ PendingCMD[i].PageCount = 0;654654+ PendingCMD[i].DataDestAddr = 0;655655+ PendingCMD[i].DataSrcAddr = 0;656656+ PendingCMD[i].MemCopyByteCnt = 0;657657+ PendingCMD[i].ChanSync[0] = 0;658658+ PendingCMD[i].ChanSync[1] = 0;659659+ PendingCMD[i].ChanSync[2] = 0;660660+ PendingCMD[i].ChanSync[3] = 0;661661+ PendingCMD[i].ChanSync[4] = 0;662662+ PendingCMD[i].Status = CMD_NOT_DONE;663663+ }664664+665665+ nand_dbg_print(NAND_DBG_TRACE, "At end of Execute CMDs.\n");666666+667667+ mtd_isr(0, 0); /* This is a null isr now. Need fill it in future */668668+669669+ return status;670670+}671671+672672+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&673673+* Function: mtd_Event_Status674674+* Inputs: none675675+* Outputs: Event_Status code676676+* Description: This function can also be used to force errors677677+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/678678+u16 mtd_CDMA_Event_Status(void)679679+{680680+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",681681+ __FILE__, __LINE__, __func__);682682+683683+ return EVENT_PASS;684684+}685685+686686+#endif /* CMD_DMA */687687+#endif /* !ELDORA */
+51
drivers/staging/spectra/lld_mtd.h
···11+/*22+ * NAND Flash Controller Device Driver33+ * Copyright (c) 2009, Intel Corporation and its suppliers.44+ *55+ * This program is free software; you can redistribute it and/or modify it66+ * under the terms and conditions of the GNU General Public License,77+ * version 2, as published by the Free Software Foundation.88+ *99+ * This program is distributed in the hope it will be useful, but WITHOUT1010+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or1111+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for1212+ * more details.1313+ *1414+ * You should have received a copy of the GNU General Public License along with1515+ * this program; if not, write to the Free Software Foundation, Inc.,1616+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.1717+ *1818+ */1919+2020+#ifndef _LLD_MTD_2121+#define _LLD_MTD_2222+2323+#include "ffsport.h"2424+#include "ffsdefs.h"2525+2626+/* prototypes: MTD API functions */2727+extern u16 mtd_Flash_Reset(void);2828+extern u16 mtd_Flash_Init(void);2929+extern int mtd_Flash_Release(void);3030+extern u16 mtd_Read_Device_ID(void);3131+extern u16 mtd_Erase_Block(u32 block_addr);3232+extern u16 mtd_Write_Page_Main(u8 *write_data, u32 Block,3333+ u16 Page, u16 PageCount);3434+extern u16 mtd_Read_Page_Main(u8 *read_data, u32 Block, u16 Page,3535+ u16 PageCount);3636+extern u16 mtd_Event_Status(void);3737+extern void mtd_Enable_Disable_Interrupts(u16 INT_ENABLE);3838+extern u16 mtd_Write_Page_Main_Spare(u8 *write_data, u32 Block,3939+ u16 Page, u16 PageCount);4040+extern u16 mtd_Write_Page_Spare(u8 *write_data, u32 Block,4141+ u16 Page, u16 PageCount);4242+extern u16 mtd_Read_Page_Main_Spare(u8 *read_data, u32 Block,4343+ u16 Page, u16 PageCount);4444+extern u16 mtd_Read_Page_Spare(u8 *read_data, u32 Block, u16 Page,4545+ u16 PageCount);4646+extern u16 mtd_Get_Bad_Block(u32 block);4747+4848+u16 mtd_CDMA_Flash_Init(void);4949+u16 mtd_CDMA_Execute_CMDs(u16 tag_count);5050+u16 mtd_CDMA_Event_Status(void);5151+#endif /*_LLD_MTD_*/
···11+/*22+ * NAND Flash Controller Device Driver33+ * Copyright (c) 2009, Intel Corporation and its suppliers.44+ *55+ * This program is free software; you can redistribute it and/or modify it66+ * under the terms and conditions of the GNU General Public License,77+ * version 2, as published by the Free Software Foundation.88+ *99+ * This program is distributed in the hope it will be useful, but WITHOUT1010+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or1111+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for1212+ * more details.1313+ *1414+ * You should have received a copy of the GNU General Public License along with1515+ * this program; if not, write to the Free Software Foundation, Inc.,1616+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.1717+ *1818+ */1919+2020+#ifndef _SPECTRASWCONFIG_2121+#define _SPECTRASWCONFIG_2222+2323+/* NAND driver version */2424+#define GLOB_VERSION "driver version 20100311"2525+2626+2727+/***** Common Parameters *****/2828+#define RETRY_TIMES 32929+3030+#define READ_BADBLOCK_INFO 13131+#define READBACK_VERIFY 03232+#define AUTO_FORMAT_FLASH 03333+3434+/***** Cache Parameters *****/3535+#define CACHE_ITEM_NUM 1283636+#define BLK_NUM_FOR_L2_CACHE 163737+3838+/***** Block Table Parameters *****/3939+#define BLOCK_TABLE_INDEX 04040+4141+/***** Wear Leveling Parameters *****/4242+#define WEAR_LEVELING_GATE 0x104343+#define WEAR_LEVELING_BLOCK_NUM 104444+4545+#define DEBUG_BNDRY 04646+4747+/***** Product Feature Support *****/4848+#define FLASH_EMU defined(CONFIG_SPECTRA_EMU)4949+#define FLASH_NAND defined(CONFIG_SPECTRA_MRST_HW)5050+#define FLASH_MTD defined(CONFIG_SPECTRA_MTD)5151+#define CMD_DMA defined(CONFIG_SPECTRA_MRST_HW_DMA)5252+5353+#define SPECTRA_PARTITION_ID 05454+5555+/* Enable this macro if the number of flash blocks is larger than 16K. */5656+#define SUPPORT_LARGE_BLOCKNUM 15757+5858+/**** Block Table and Reserved Block Parameters *****/5959+#define SPECTRA_START_BLOCK 36060+//#define NUM_FREE_BLOCKS_GATE 306161+#define NUM_FREE_BLOCKS_GATE 606262+6363+/**** Hardware Parameters ****/6464+#define GLOB_HWCTL_REG_BASE 0xFFA400006565+#define GLOB_HWCTL_REG_SIZE 40966666+6767+#define GLOB_HWCTL_MEM_BASE 0xFFA480006868+#define GLOB_HWCTL_MEM_SIZE 40966969+7070+/* KBV - Updated to LNW scratch register address */7171+#define SCRATCH_REG_ADDR 0xFF1080187272+#define SCRATCH_REG_SIZE 647373+7474+#define GLOB_HWCTL_DEFAULT_BLKS 20487575+7676+#define SUPPORT_15BITECC 17777+#define SUPPORT_8BITECC 17878+7979+#define ONFI_BLOOM_TIME 08080+#define MODE5_WORKAROUND 18181+8282+#endif /*_SPECTRASWCONFIG_*/