/drivers/staging/spectra/ffsport.c
C | 841 lines | 596 code | 143 blank | 102 comment | 79 complexity | 3307cc7fcd2adb86168d20b2724f35dc MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
- /*
- * NAND Flash Controller Device Driver
- * Copyright (c) 2009, Intel Corporation and its suppliers.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
- #include "ffsport.h"
- #include "flash.h"
- #include <linux/interrupt.h>
- #include <linux/delay.h>
- #include <linux/blkdev.h>
- #include <linux/wait.h>
- #include <linux/mutex.h>
- #include <linux/kthread.h>
- #include <linux/log2.h>
- #include <linux/init.h>
- #include <linux/slab.h>
- #include <linux/async.h>
- /**** Helper functions used for Div, Remainder operation on u64 ****/
- /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
- * Function: GLOB_Calc_Used_Bits
- * Inputs: Power of 2 number
- * Outputs: Number of Used Bits
- * 0, if the argument is 0
- * Description: Calculate the number of bits used by a given power of 2 number
- * Number can be up to 32 bit
- *&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
- int GLOB_Calc_Used_Bits(u32 n)
- {
- int tot_bits = 0;
- if (n >= 1 << 16) {
- n >>= 16;
- tot_bits += 16;
- }
- if (n >= 1 << 8) {
- n >>= 8;
- tot_bits += 8;
- }
- if (n >= 1 << 4) {
- n >>= 4;
- tot_bits += 4;
- }
- if (n >= 1 << 2) {
- n >>= 2;
- tot_bits += 2;
- }
- if (n >= 1 << 1)
- tot_bits += 1;
- return ((n == 0) ? (0) : tot_bits);
- }
- /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
- * Function: GLOB_u64_Div
- * Inputs: Number of u64
- * A power of 2 number as Division
- * Outputs: Quotient of the Divisor operation
- * Description: It divides the address by divisor by using bit shift operation
- * (essentially without explicitely using "/").
- * Divisor is a power of 2 number and Divided is of u64
- *&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
- u64 GLOB_u64_Div(u64 addr, u32 divisor)
- {
- return (u64)(addr >> GLOB_Calc_Used_Bits(divisor));
- }
- /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
- * Function: GLOB_u64_Remainder
- * Inputs: Number of u64
- * Divisor Type (1 -PageAddress, 2- BlockAddress)
- * Outputs: Remainder of the Division operation
- * Description: It calculates the remainder of a number (of u64) by
- * divisor(power of 2 number ) by using bit shifting and multiply
- * operation(essentially without explicitely using "/").
- *&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
- u64 GLOB_u64_Remainder(u64 addr, u32 divisor_type)
- {
- u64 result = 0;
- if (divisor_type == 1) { /* Remainder -- Page */
- result = (addr >> DeviceInfo.nBitsInPageDataSize);
- result = result * DeviceInfo.wPageDataSize;
- } else if (divisor_type == 2) { /* Remainder -- Block */
- result = (addr >> DeviceInfo.nBitsInBlockDataSize);
- result = result * DeviceInfo.wBlockDataSize;
- }
- result = addr - result;
- return result;
- }
- #define NUM_DEVICES 1
- #define PARTITIONS 8
- #define GLOB_SBD_NAME "nd"
- #define GLOB_SBD_IRQ_NUM (29)
- #define GLOB_SBD_IOCTL_GC (0x7701)
- #define GLOB_SBD_IOCTL_WL (0x7702)
- #define GLOB_SBD_IOCTL_FORMAT (0x7703)
- #define GLOB_SBD_IOCTL_ERASE_FLASH (0x7704)
- #define GLOB_SBD_IOCTL_FLUSH_CACHE (0x7705)
- #define GLOB_SBD_IOCTL_COPY_BLK_TABLE (0x7706)
- #define GLOB_SBD_IOCTL_COPY_WEAR_LEVELING_TABLE (0x7707)
- #define GLOB_SBD_IOCTL_GET_NAND_INFO (0x7708)
- #define GLOB_SBD_IOCTL_WRITE_DATA (0x7709)
- #define GLOB_SBD_IOCTL_READ_DATA (0x770A)
- static int reserved_mb = 0;
- module_param(reserved_mb, int, 0);
- MODULE_PARM_DESC(reserved_mb, "Reserved space for OS image, in MiB (default 25 MiB)");
- int nand_debug_level;
- module_param(nand_debug_level, int, 0644);
- MODULE_PARM_DESC(nand_debug_level, "debug level value: 1-3");
- MODULE_LICENSE("GPL");
- struct spectra_nand_dev {
- struct pci_dev *dev;
- u64 size;
- u16 users;
- spinlock_t qlock;
- void __iomem *ioaddr; /* Mapped address */
- struct request_queue *queue;
- struct task_struct *thread;
- struct gendisk *gd;
- u8 *tmp_buf;
- };
- static int GLOB_SBD_majornum;
- static char *GLOB_version = GLOB_VERSION;
- static struct spectra_nand_dev nand_device[NUM_DEVICES];
- static struct mutex spectra_lock;
- static int res_blks_os = 1;
- struct spectra_indentfy_dev_tag IdentifyDeviceData;
- static int force_flush_cache(void)
- {
- nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n",
- __FILE__, __LINE__, __func__);
- if (ERR == GLOB_FTL_Flush_Cache()) {
- printk(KERN_ERR "Fail to Flush FTL Cache!\n");
- return -EFAULT;
- }
- #if CMD_DMA
- if (glob_ftl_execute_cmds())
- return -EIO;
- else
- return 0;
- #endif
- return 0;
- }
- struct ioctl_rw_page_info {
- u8 *data;
- unsigned int page;
- };
- static int ioctl_read_page_data(unsigned long arg)
- {
- u8 *buf;
- struct ioctl_rw_page_info info;
- int result = PASS;
- if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
- return -EFAULT;
- buf = kmalloc(IdentifyDeviceData.PageDataSize, GFP_ATOMIC);
- if (!buf) {
- printk(KERN_ERR "ioctl_read_page_data: "
- "failed to allocate memory\n");
- return -ENOMEM;
- }
- mutex_lock(&spectra_lock);
- result = GLOB_FTL_Page_Read(buf,
- (u64)info.page * IdentifyDeviceData.PageDataSize);
- mutex_unlock(&spectra_lock);
- if (copy_to_user((void __user *)info.data, buf,
- IdentifyDeviceData.PageDataSize)) {
- printk(KERN_ERR "ioctl_read_page_data: "
- "failed to copy user data\n");
- kfree(buf);
- return -EFAULT;
- }
- kfree(buf);
- return result;
- }
- static int ioctl_write_page_data(unsigned long arg)
- {
- u8 *buf;
- struct ioctl_rw_page_info info;
- int result = PASS;
- if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
- return -EFAULT;
- buf = kmalloc(IdentifyDeviceData.PageDataSize, GFP_ATOMIC);
- if (!buf) {
- printk(KERN_ERR "ioctl_write_page_data: "
- "failed to allocate memory\n");
- return -ENOMEM;
- }
- if (copy_from_user(buf, (void __user *)info.data,
- IdentifyDeviceData.PageDataSize)) {
- printk(KERN_ERR "ioctl_write_page_data: "
- "failed to copy user data\n");
- kfree(buf);
- return -EFAULT;
- }
- mutex_lock(&spectra_lock);
- result = GLOB_FTL_Page_Write(buf,
- (u64)info.page * IdentifyDeviceData.PageDataSize);
-