android13/kernel-5.10/drivers/rkflash/rkflash_blk.c

847 lines
18 KiB
C

// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2018 Rockchip Electronics Co. Ltd. */
#include <linux/blkdev.h>
#include <linux/blkpg.h>
#include <linux/blk-mq.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/freezer.h>
#include <linux/fs.h>
#include <linux/hdreg.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <linux/semaphore.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/timer.h>
#include <linux/wait.h>
#include <linux/version.h>
#include <linux/soc/rockchip/rk_vendor_storage.h>
#include "../soc/rockchip/flash_vendor_storage.h"
#include "rkflash_blk.h"
#include "rkflash_debug.h"
#include "rk_sftl.h"
void __printf(1, 2) sftl_printk(char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vprintk(fmt, ap);
va_end(ap);
}
/* For rkflash block dev private data */
static const struct flash_boot_ops *g_boot_ops;
static int g_flash_type = -1;
static struct flash_part disk_array[MAX_PART_COUNT];
static int g_max_part_num = 4;
#define FW_HRADER_PT_NAME ("fw_header_p")
static struct flash_part fw_header_p;
#define PART_READONLY 0x85
#define PART_WRITEONLY 0x86
#define PART_NO_ACCESS 0x87
static unsigned long totle_read_data;
static unsigned long totle_write_data;
static unsigned long totle_read_count;
static unsigned long totle_write_count;
static char *mtd_read_temp_buffer;
#define MTD_RW_SECTORS (512)
#define DISABLE_WRITE _IO('V', 0)
#define ENABLE_WRITE _IO('V', 1)
#define DISABLE_READ _IO('V', 2)
#define ENABLE_READ _IO('V', 3)
/* Thread for gc operation */
static DECLARE_WAIT_QUEUE_HEAD(nand_gc_thread_wait);
static unsigned long nand_gc_do;
static struct task_struct *nand_gc_thread __read_mostly;
/* For rkflash dev private data, including mtd dev and block dev */
static int rkflash_dev_initialised;
static DEFINE_MUTEX(g_flash_ops_mutex);
static unsigned int rk_partition_init(struct flash_part *part)
{
int i, part_num = 0;
u32 desity;
struct STRUCT_PART_INFO *g_part; /* size 2KB */
g_part = kmalloc(sizeof(*g_part), GFP_KERNEL | GFP_DMA);
if (!g_part)
return 0;
mutex_lock(&g_flash_ops_mutex);
if (g_boot_ops->read(0, 4, g_part) == 0) {
if (g_part->hdr.ui_fw_tag == RK_PARTITION_TAG) {
part_num = g_part->hdr.ui_part_entry_count;
desity = g_boot_ops->get_capacity();
for (i = 0; i < part_num; i++) {
memcpy(part[i].name,
g_part->part[i].sz_name,
32);
part[i].offset = g_part->part[i].ui_pt_off;
part[i].size = g_part->part[i].ui_pt_sz;
part[i].type = 0;
if (part[i].size == UINT_MAX)
part[i].size = desity - part[i].offset;
if (part[i].offset + part[i].size > desity) {
part[i].size = desity - part[i].offset;
break;
}
}
}
}
mutex_unlock(&g_flash_ops_mutex);
kfree(g_part);
memset(&fw_header_p, 0x0, sizeof(fw_header_p));
memcpy(fw_header_p.name, FW_HRADER_PT_NAME, strlen(FW_HRADER_PT_NAME));
fw_header_p.offset = 0x0;
fw_header_p.size = 0x4;
fw_header_p.type = 0;
return part_num;
}
static int rkflash_blk_proc_show(struct seq_file *m, void *v)
{
char *ftl_buf = kzalloc(4096, GFP_KERNEL);
#if IS_ENABLED(CONFIG_RK_SFTL)
int real_size = 0;
real_size = rknand_proc_ftlread(4096, ftl_buf);
if (real_size > 0)
seq_printf(m, "%s", ftl_buf);
#endif
seq_printf(m, "Totle Read %ld KB\n", totle_read_data >> 1);
seq_printf(m, "Totle Write %ld KB\n", totle_write_data >> 1);
seq_printf(m, "totle_write_count %ld\n", totle_write_count);
seq_printf(m, "totle_read_count %ld\n", totle_read_count);
kfree(ftl_buf);
return 0;
}
static int rkflash_blk_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, rkflash_blk_proc_show, PDE_DATA(inode));
}
static const struct proc_ops rkflash_blk_proc_fops = {
.proc_open = rkflash_blk_proc_open,
.proc_read = seq_read,
.proc_lseek = seq_lseek,
.proc_release = single_release,
};
static int rkflash_blk_create_procfs(void)
{
struct proc_dir_entry *ent;
ent = proc_create_data("rkflash", 0x664, NULL, &rkflash_blk_proc_fops,
(void *)0);
if (!ent)
return -1;
return 0;
}
static int rkflash_blk_discard(u32 sec, u32 n_sec)
{
int ret;
if (g_boot_ops->discard)
ret = g_boot_ops->discard(sec, n_sec);
else
ret = -EPERM;
return ret;
};
static int rkflash_blk_xfer(struct flash_blk_dev *dev,
unsigned long start,
unsigned long nsector,
char *buf,
int cmd)
{
int ret;
if (dev->disable_access ||
(cmd == WRITE && dev->readonly) ||
(cmd == READ && dev->writeonly)) {
return -EIO;
}
start += dev->off_size;
switch (cmd) {
case READ:
totle_read_data += nsector;
totle_read_count++;
rkflash_print_bio("rkflash r sec= %lx, n_sec= %lx\n",
start, nsector);
ret = g_boot_ops->read(start, nsector, buf);
if (ret)
ret = -EIO;
break;
case WRITE:
totle_write_data += nsector;
totle_write_count++;
rkflash_print_bio("rkflash w sec= %lx, n_sec= %lx\n",
start, nsector);
ret = g_boot_ops->write(start, nsector, buf);
if (ret)
ret = -EIO;
break;
default:
ret = -EIO;
break;
}
return ret;
}
static int rkflash_blk_check_buffer_align(struct request *req, char **pbuf)
{
int nr_vec = 0;
struct bio_vec bv;
struct req_iterator iter;
char *buffer;
void *firstbuf = 0;
char *nextbuffer = 0;
rq_for_each_segment(bv, req, iter) {
/* high mem return 0 and using kernel buffer */
if (PageHighMem(bv.bv_page))
return 0;
buffer = page_address(bv.bv_page) + bv.bv_offset;
if (!buffer)
return 0;
if (!firstbuf)
firstbuf = buffer;
nr_vec++;
if (nextbuffer && nextbuffer != buffer)
return 0;
nextbuffer = buffer + bv.bv_len;
}
*pbuf = firstbuf;
return 1;
}
static blk_status_t do_blktrans_all_request(struct flash_blk_ops *tr,
struct flash_blk_dev *dev,
struct request *req)
{
unsigned long block, nsect;
char *buf = NULL, *page_buf;
struct req_iterator rq_iter;
struct bio_vec bvec;
int ret;
unsigned long totle_nsect;
block = blk_rq_pos(req);
nsect = blk_rq_cur_bytes(req) >> 9;
totle_nsect = (req->__data_len) >> 9;
if (blk_rq_pos(req) + blk_rq_cur_sectors(req) >
get_capacity(req->rq_disk))
return BLK_STS_IOERR;
switch (req_op(req)) {
case REQ_OP_DISCARD:
rkflash_print_bio("%s discard\n", __func__);
if (rkflash_blk_discard(block, nsect))
return BLK_STS_IOERR;
return BLK_STS_OK;
case REQ_OP_READ:
rkflash_print_bio("%s read block=%lx nsec=%lx\n", __func__, block, totle_nsect);
buf = mtd_read_temp_buffer;
rkflash_blk_check_buffer_align(req, &buf);
ret = rkflash_blk_xfer(dev,
block,
totle_nsect,
buf,
REQ_OP_READ);
if (buf == mtd_read_temp_buffer) {
char *p = buf;
rq_for_each_segment(bvec, req, rq_iter) {
page_buf = kmap_atomic(bvec.bv_page);
memcpy(page_buf +
bvec.bv_offset,
p,
bvec.bv_len);
p += bvec.bv_len;
kunmap_atomic(page_buf);
}
}
if (ret)
return BLK_STS_IOERR;
else
return BLK_STS_OK;
case REQ_OP_WRITE:
rkflash_print_bio("%s write block=%lx nsec=%lx\n", __func__, block, totle_nsect);
buf = mtd_read_temp_buffer;
rkflash_blk_check_buffer_align(req, &buf);
if (buf == mtd_read_temp_buffer) {
char *p = buf;
rq_for_each_segment(bvec, req, rq_iter) {
page_buf = kmap_atomic(bvec.bv_page);
memcpy(p,
page_buf +
bvec.bv_offset,
bvec.bv_len);
p += bvec.bv_len;
kunmap_atomic(page_buf);
}
}
ret = rkflash_blk_xfer(dev,
block,
totle_nsect,
buf,
REQ_OP_WRITE);
if (ret)
return BLK_STS_IOERR;
else
return BLK_STS_OK;
default:
return BLK_STS_IOERR;
}
}
static struct request *rkflash_next_request(struct flash_blk_dev *dev)
{
struct request *rq;
struct flash_blk_ops *tr = dev->blk_ops;
rq = list_first_entry_or_null(&tr->rq_list, struct request, queuelist);
if (rq) {
list_del_init(&rq->queuelist);
blk_mq_start_request(rq);
return rq;
}
return NULL;
}
static void rkflash_blktrans_work(struct flash_blk_dev *dev)
__releases(&dev->blk_ops->queue_lock)
__acquires(&dev->blk_ops->queue_lock)
{
struct flash_blk_ops *tr = dev->blk_ops;
struct request *req = NULL;
while (1) {
blk_status_t res;
req = rkflash_next_request(dev);
if (!req)
break;
spin_unlock_irq(&dev->blk_ops->queue_lock);
mutex_lock(&g_flash_ops_mutex);
res = do_blktrans_all_request(tr, dev, req);
mutex_unlock(&g_flash_ops_mutex);
if (!blk_update_request(req, res, req->__data_len)) {
__blk_mq_end_request(req, res);
req = NULL;
}
spin_lock_irq(&dev->blk_ops->queue_lock);
}
}
static blk_status_t rkflash_queue_rq(struct blk_mq_hw_ctx *hctx,
const struct blk_mq_queue_data *bd)
{
struct flash_blk_dev *dev;
dev = hctx->queue->queuedata;
if (!dev) {
blk_mq_start_request(bd->rq);
return BLK_STS_IOERR;
}
nand_gc_do = 0;
spin_lock_irq(&dev->blk_ops->queue_lock);
list_add_tail(&bd->rq->queuelist, &dev->blk_ops->rq_list);
rkflash_blktrans_work(dev);
spin_unlock_irq(&dev->blk_ops->queue_lock);
/* wake up gc thread */
nand_gc_do = 1;
wake_up(&nand_gc_thread_wait);
return BLK_STS_OK;
}
static const struct blk_mq_ops rkflash_mq_ops = {
.queue_rq = rkflash_queue_rq,
};
static int nand_gc_has_work(void)
{
return nand_gc_do;
}
static int nand_gc_do_work(void)
{
int ret = nand_gc_has_work();
/* do garbage collect at idle state */
if (ret) {
mutex_lock(&g_flash_ops_mutex);
ret = g_boot_ops->gc();
rkflash_print_bio("%s gc result= %d\n", __func__, ret);
mutex_unlock(&g_flash_ops_mutex);
}
return ret;
}
static void nand_gc_wait_work(void)
{
unsigned long nand_gc_jiffies = HZ / 20;
if (nand_gc_has_work())
wait_event_freezable_timeout(nand_gc_thread_wait,
kthread_should_stop(),
nand_gc_jiffies);
else
wait_event_freezable(nand_gc_thread_wait,
kthread_should_stop() || nand_gc_has_work());
}
static int nand_gc_mythread(void *arg)
{
int gc_done_times = 0;
set_freezable();
while (!kthread_should_stop()) {
if (nand_gc_do_work() == 0) {
gc_done_times++;
if (gc_done_times > 10)
nand_gc_do = 0;
} else {
gc_done_times = 0;
}
nand_gc_wait_work();
}
pr_info("nand gc quited\n");
return 0;
}
static int rkflash_blk_open(struct block_device *bdev, fmode_t mode)
{
return 0;
}
static void rkflash_blk_release(struct gendisk *disk, fmode_t mode)
{
};
static int rkflash_blk_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd,
unsigned long arg)
{
struct flash_blk_dev *dev = bdev->bd_disk->private_data;
switch (cmd) {
case ENABLE_WRITE:
dev->disable_access = 0;
dev->readonly = 0;
set_disk_ro(dev->blkcore_priv, 0);
return 0;
case DISABLE_WRITE:
dev->readonly = 1;
set_disk_ro(dev->blkcore_priv, 1);
return 0;
case ENABLE_READ:
dev->disable_access = 0;
dev->writeonly = 0;
return 0;
case DISABLE_READ:
dev->writeonly = 1;
return 0;
default:
return -ENOTTY;
}
}
const struct block_device_operations rkflash_blk_trans_ops = {
.owner = THIS_MODULE,
.open = rkflash_blk_open,
.release = rkflash_blk_release,
.ioctl = rkflash_blk_ioctl,
};
static struct flash_blk_ops mytr = {
.name = "rkflash",
.major = 31,
.minorbits = 0,
.owner = THIS_MODULE,
};
static int rkflash_blk_add_dev(struct flash_blk_dev *dev,
struct flash_blk_ops *blk_ops,
struct flash_part *part)
{
struct gendisk *gd;
if (part->size == 0)
return -1;
gd = alloc_disk(1 << blk_ops->minorbits);
if (!gd) {
kfree(dev);
return -ENOMEM;
}
dev->blk_ops = blk_ops;
dev->size = part->size;
dev->off_size = part->offset;
dev->devnum = blk_ops->last_dev_index;
list_add_tail(&dev->list, &blk_ops->devs);
blk_ops->last_dev_index++;
gd->major = blk_ops->major;
gd->first_minor = (dev->devnum) << blk_ops->minorbits;
gd->fops = &rkflash_blk_trans_ops;
if (part->name[0]) {
snprintf(gd->disk_name,
sizeof(gd->disk_name),
"%s",
part->name);
} else {
gd->flags = GENHD_FL_EXT_DEVT;
gd->minors = 255;
snprintf(gd->disk_name,
sizeof(gd->disk_name),
"%s%d",
blk_ops->name,
dev->devnum);
}
set_capacity(gd, dev->size);
gd->private_data = dev;
dev->blkcore_priv = gd;
gd->queue = blk_ops->rq;
if (part->type == PART_NO_ACCESS)
dev->disable_access = 1;
if (part->type == PART_READONLY)
dev->readonly = 1;
if (part->type == PART_WRITEONLY)
dev->writeonly = 1;
if (dev->readonly)
set_disk_ro(gd, 1);
add_disk(gd);
return 0;
}
static int rkflash_blk_remove_dev(struct flash_blk_dev *dev)
{
struct gendisk *gd;
gd = dev->blkcore_priv;
list_del(&dev->list);
gd->queue = NULL;
del_gendisk(gd);
put_disk(gd);
kfree(dev);
return 0;
}
static int rkflash_blk_register(struct flash_blk_ops *blk_ops)
{
int i, ret;
u64 offset;
struct flash_blk_dev *dev;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
mtd_read_temp_buffer = kmalloc(MTD_RW_SECTORS * 512,
GFP_KERNEL | GFP_DMA);
ret = register_blkdev(blk_ops->major, blk_ops->name);
if (ret) {
kfree(dev);
return -1;
}
/* Create the request queue */
spin_lock_init(&blk_ops->queue_lock);
INIT_LIST_HEAD(&blk_ops->rq_list);
blk_ops->tag_set = kzalloc(sizeof(*blk_ops->tag_set), GFP_KERNEL);
if (!blk_ops->tag_set)
goto error1;
blk_ops->rq = blk_mq_init_sq_queue(blk_ops->tag_set, &rkflash_mq_ops, 1,
BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_BLOCKING);
if (IS_ERR(blk_ops->rq)) {
ret = PTR_ERR(blk_ops->rq);
blk_ops->rq = NULL;
goto error2;
}
blk_ops->rq->queuedata = dev;
blk_queue_max_hw_sectors(blk_ops->rq, MTD_RW_SECTORS);
blk_queue_max_segments(blk_ops->rq, MTD_RW_SECTORS);
blk_queue_flag_set(QUEUE_FLAG_DISCARD, blk_ops->rq);
blk_queue_max_discard_sectors(blk_ops->rq, UINT_MAX >> 9);
blk_ops->rq->limits.discard_granularity = 64 << 9;
if (g_flash_type == FLASH_TYPE_SFC_NAND || g_flash_type == FLASH_TYPE_NANDC_NAND)
nand_gc_thread = kthread_run(nand_gc_mythread, (void *)blk_ops, "rkflash_gc");
INIT_LIST_HEAD(&blk_ops->devs);
g_max_part_num = rk_partition_init(disk_array);
if (g_max_part_num) {
/* partition 0 is save vendor data, need hidden */
blk_ops->last_dev_index = 0;
for (i = 1; i < g_max_part_num; i++) {
offset = (u64)disk_array[i].offset;
pr_info("%10s: 0x%09llx -- 0x%09llx (%llu MB)\n",
disk_array[i].name,
offset * 512,
(u64)(offset + disk_array[i].size) * 512,
(u64)disk_array[i].size / 2048);
rkflash_blk_add_dev(dev, blk_ops, &disk_array[i]);
}
rkflash_blk_add_dev(dev, blk_ops, &fw_header_p);
} else {
struct flash_part part;
part.offset = 0;
part.size = g_boot_ops->get_capacity();
part.type = 0;
part.name[0] = 0;
rkflash_blk_add_dev(dev, blk_ops, &part);
}
rkflash_blk_create_procfs();
return 0;
error2:
kfree(blk_ops->tag_set);
error1:
unregister_blkdev(blk_ops->major, blk_ops->name);
kfree(dev);
return ret;
}
static void rkflash_blk_unregister(struct flash_blk_ops *blk_ops)
{
struct list_head *this, *next;
list_for_each_safe(this, next, &blk_ops->devs) {
struct flash_blk_dev *dev =
list_entry(this, struct flash_blk_dev, list);
rkflash_blk_remove_dev(dev);
}
blk_cleanup_queue(blk_ops->rq);
unregister_blkdev(blk_ops->major, blk_ops->name);
}
static int __maybe_unused rkflash_dev_vendor_read(u32 sec, u32 n_sec, void *p_data)
{
int ret;
if (g_boot_ops->vendor_read) {
mutex_lock(&g_flash_ops_mutex);
ret = g_boot_ops->vendor_read(sec, n_sec, p_data);
mutex_unlock(&g_flash_ops_mutex);
} else {
ret = -EPERM;
}
return ret;
}
static int __maybe_unused rkflash_dev_vendor_write(u32 sec, u32 n_sec, void *p_data)
{
int ret;
if (g_boot_ops->vendor_write) {
mutex_lock(&g_flash_ops_mutex);
ret = g_boot_ops->vendor_write(sec,
n_sec,
p_data);
mutex_unlock(&g_flash_ops_mutex);
} else {
ret = -EPERM;
}
return ret;
}
int rkflash_dev_init(void __iomem *reg_addr,
enum flash_type type,
const struct flash_boot_ops *ops)
{
int ret = -1;
pr_err("%s enter\n", __func__);
if (rkflash_dev_initialised) {
pr_err("rkflash has already inited as id[%d]\n", g_flash_type);
return -1;
}
if (!ops->init)
return -EINVAL;
ret = ops->init(reg_addr);
if (ret) {
pr_err("rkflash[%d] is invalid", type);
return -ENODEV;
}
pr_info("rkflash[%d] init success\n", type);
g_boot_ops = ops;
/* vendor part */
switch (type) {
case FLASH_TYPE_SFC_NOR:
#if IS_ENABLED(CONFIG_RK_SFC_NOR_MTD) && IS_ENABLED(CONFIG_ROCKCHIP_MTD_VENDOR_STORAGE)
break;
#else
flash_vendor_dev_ops_register(rkflash_dev_vendor_read,
rkflash_dev_vendor_write);
#endif
break;
case FLASH_TYPE_SFC_NAND:
#ifdef CONFIG_RK_SFC_NAND_MTD
break;
#endif
case FLASH_TYPE_NANDC_NAND:
#if defined(CONFIG_RK_SFTL)
rk_sftl_vendor_dev_ops_register(rkflash_dev_vendor_read,
rkflash_dev_vendor_write);
ret = rk_sftl_vendor_storage_init();
if (!ret) {
rk_vendor_register(rk_sftl_vendor_read,
rk_sftl_vendor_write);
rk_sftl_vendor_register();
pr_info("rkflashd vendor storage init ok !\n");
} else {
pr_info("rkflash vendor storage init failed !\n");
}
break;
#endif
default:
break;
}
switch (type) {
case FLASH_TYPE_SFC_NOR:
#ifdef CONFIG_RK_SFC_NOR_MTD
ret = sfc_nor_mtd_init(sfnor_dev, &g_flash_ops_mutex);
pr_err("%s device register as mtd dev, ret= %d\n", __func__, ret);
break;
#endif
case FLASH_TYPE_SFC_NAND:
#ifdef CONFIG_RK_SFC_NAND_MTD
ret = sfc_nand_mtd_init(sfnand_dev, &g_flash_ops_mutex);
pr_err("%s device register as mtd dev, ret= %d\n", __func__, ret);
break;
#endif
case FLASH_TYPE_NANDC_NAND:
default:
g_flash_type = type;
ret = rkflash_blk_register(&mytr);
pr_err("%s device register as blk dev, ret= %d\n", __func__, ret);
if (ret)
g_flash_type = -1;
break;
}
if (!ret)
rkflash_dev_initialised = 1;
return ret;
}
int rkflash_dev_exit(void)
{
if (rkflash_dev_initialised)
rkflash_dev_initialised = 0;
if (g_flash_type != -1)
rkflash_blk_unregister(&mytr);
pr_info("%s:OK\n", __func__);
return 0;
}
int rkflash_dev_suspend(void)
{
mutex_lock(&g_flash_ops_mutex);
return 0;
}
int rkflash_dev_resume(void __iomem *reg_addr)
{
g_boot_ops->resume(reg_addr);
mutex_unlock(&g_flash_ops_mutex);
return 0;
}
void rkflash_dev_shutdown(void)
{
pr_info("rkflash_shutdown...\n");
if (g_flash_type == FLASH_TYPE_SFC_NAND || g_flash_type == FLASH_TYPE_NANDC_NAND)
kthread_stop(nand_gc_thread);
mutex_lock(&g_flash_ops_mutex);
g_boot_ops->deinit();
mutex_unlock(&g_flash_ops_mutex);
pr_info("rkflash_shutdown:OK\n");
}