OpenCloudOS-Kernel/drivers/mtd/hyperbus/rpc-if.c

180 lines
3.9 KiB
C
Raw Normal View History

// SPDX-License-Identifier: GPL-2.0
/*
* Linux driver for RPC-IF HyperFlash
*
* Copyright (C) 2019-2020 Cogent Embedded, Inc.
*/
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mtd/hyperbus.h>
#include <linux/mtd/mtd.h>
#include <linux/mux/consumer.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/types.h>
#include <memory/renesas-rpc-if.h>
struct rpcif_hyperbus {
struct rpcif rpc;
struct hyperbus_ctlr ctlr;
struct hyperbus_device hbdev;
};
static const struct rpcif_op rpcif_op_tmpl = {
.cmd = {
.buswidth = 8,
.ddr = true,
},
.ocmd = {
.buswidth = 8,
.ddr = true,
},
.addr = {
.nbytes = 1,
.buswidth = 8,
.ddr = true,
},
.data = {
.buswidth = 8,
.ddr = true,
},
};
static void rpcif_hb_prepare_read(struct rpcif *rpc, void *to,
unsigned long from, ssize_t len)
{
struct rpcif_op op = rpcif_op_tmpl;
op.cmd.opcode = HYPERBUS_RW_READ | HYPERBUS_AS_MEM;
op.addr.val = from >> 1;
op.dummy.buswidth = 1;
op.dummy.ncycles = 15;
op.data.dir = RPCIF_DATA_IN;
op.data.nbytes = len;
op.data.buf.in = to;
rpcif_prepare(rpc, &op, NULL, NULL);
}
static void rpcif_hb_prepare_write(struct rpcif *rpc, unsigned long to,
void *from, ssize_t len)
{
struct rpcif_op op = rpcif_op_tmpl;
op.cmd.opcode = HYPERBUS_RW_WRITE | HYPERBUS_AS_MEM;
op.addr.val = to >> 1;
op.data.dir = RPCIF_DATA_OUT;
op.data.nbytes = len;
op.data.buf.out = from;
rpcif_prepare(rpc, &op, NULL, NULL);
}
static u16 rpcif_hb_read16(struct hyperbus_device *hbdev, unsigned long addr)
{
struct rpcif_hyperbus *hyperbus =
container_of(hbdev, struct rpcif_hyperbus, hbdev);
map_word data;
rpcif_hb_prepare_read(&hyperbus->rpc, &data, addr, 2);
rpcif_manual_xfer(&hyperbus->rpc);
return data.x[0];
}
static void rpcif_hb_write16(struct hyperbus_device *hbdev, unsigned long addr,
u16 data)
{
struct rpcif_hyperbus *hyperbus =
container_of(hbdev, struct rpcif_hyperbus, hbdev);
rpcif_hb_prepare_write(&hyperbus->rpc, addr, &data, 2);
rpcif_manual_xfer(&hyperbus->rpc);
}
static void rpcif_hb_copy_from(struct hyperbus_device *hbdev, void *to,
unsigned long from, ssize_t len)
{
struct rpcif_hyperbus *hyperbus =
container_of(hbdev, struct rpcif_hyperbus, hbdev);
rpcif_hb_prepare_read(&hyperbus->rpc, to, from, len);
rpcif_dirmap_read(&hyperbus->rpc, from, len, to);
}
static const struct hyperbus_ops rpcif_hb_ops = {
.read16 = rpcif_hb_read16,
.write16 = rpcif_hb_write16,
.copy_from = rpcif_hb_copy_from,
};
static int rpcif_hb_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct rpcif_hyperbus *hyperbus;
int error;
hyperbus = devm_kzalloc(dev, sizeof(*hyperbus), GFP_KERNEL);
if (!hyperbus)
return -ENOMEM;
error = rpcif_sw_init(&hyperbus->rpc, pdev->dev.parent);
if (error)
return error;
platform_set_drvdata(pdev, hyperbus);
rpcif_enable_rpm(&hyperbus->rpc);
error = rpcif_hw_init(&hyperbus->rpc, true);
if (error)
goto out_disable_rpm;
hyperbus->hbdev.map.size = hyperbus->rpc.size;
hyperbus->hbdev.map.virt = hyperbus->rpc.dirmap;
hyperbus->ctlr.dev = dev;
hyperbus->ctlr.ops = &rpcif_hb_ops;
hyperbus->hbdev.ctlr = &hyperbus->ctlr;
hyperbus->hbdev.np = of_get_next_child(pdev->dev.parent->of_node, NULL);
error = hyperbus_register_device(&hyperbus->hbdev);
if (error)
goto out_disable_rpm;
return 0;
out_disable_rpm:
rpcif_disable_rpm(&hyperbus->rpc);
return error;
}
static int rpcif_hb_remove(struct platform_device *pdev)
{
struct rpcif_hyperbus *hyperbus = platform_get_drvdata(pdev);
hyperbus_unregister_device(&hyperbus->hbdev);
mtd: hyperbus: rpc-if: fix bug in rpcif_hb_remove The following KASAN BUG is observed when testing the rpc-if driver on rcar-gen3: root@rcar-gen3:~# modprobe -r rpc-if [ 101.930146] ================================================================== [ 101.937408] BUG: KASAN: slab-out-of-bounds in __lock_acquire+0x518/0x25d0 [ 101.944240] Read of size 8 at addr ffff0004c5be2750 by task modprobe/664 [ 101.950959] [ 101.952466] CPU: 2 PID: 664 Comm: modprobe Not tainted 5.14.0-rc1-00342-g1a1464d7aa31 #1 [ 101.960578] Hardware name: Renesas H3ULCB board based on r8a77951 (DT) [ 101.967120] Call trace: [ 101.969580] dump_backtrace+0x0/0x2c0 [ 101.973275] show_stack+0x1c/0x30 [ 101.976616] dump_stack_lvl+0x9c/0xd8 [ 101.980301] print_address_description.constprop.0+0x74/0x2b8 [ 101.986071] kasan_report+0x1f4/0x26c [ 101.989757] __asan_load8+0x98/0xd4 [ 101.993266] __lock_acquire+0x518/0x25d0 [ 101.997215] lock_acquire.part.0+0x18c/0x360 [ 102.001506] lock_acquire+0x74/0x90 [ 102.005013] _raw_spin_lock_irq+0x98/0x130 [ 102.009131] __pm_runtime_disable+0x30/0x210 [ 102.013427] rpcif_hb_remove+0x5c/0x70 [rpc_if] [ 102.018001] platform_remove+0x40/0x80 [ 102.021771] __device_release_driver+0x234/0x350 [ 102.026412] driver_detach+0x158/0x20c [ 102.030179] bus_remove_driver+0xa0/0x140 [ 102.034212] driver_unregister+0x48/0x80 [ 102.038153] platform_driver_unregister+0x18/0x24 [ 102.042879] rpcif_platform_driver_exit+0x1c/0x34 [rpc_if] [ 102.048400] __arm64_sys_delete_module+0x210/0x310 [ 102.053212] invoke_syscall+0x60/0x190 [ 102.056986] el0_svc_common+0x12c/0x144 [ 102.060844] do_el0_svc+0x88/0xac [ 102.064181] el0_svc+0x24/0x3c [ 102.067257] el0t_64_sync_handler+0x1a8/0x1b0 [ 102.071634] el0t_64_sync+0x198/0x19c [ 102.075315] [ 102.076815] Allocated by task 628: [ 102.080781] [ 102.082280] Last potentially related work creation: [ 102.087524] [ 102.089022] The buggy address belongs to the object at ffff0004c5be2000 [ 102.089022] which belongs to the cache kmalloc-2k of size 2048 [ 102.101555] The buggy address is located 1872 bytes inside of [ 102.101555] 2048-byte region [ffff0004c5be2000, ffff0004c5be2800) [ 102.113486] The buggy address belongs to the page: [ 102.118409] [ 102.119908] Memory state around the buggy address: [ 102.124711] ffff0004c5be2600: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 102.131947] ffff0004c5be2680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 102.139181] >ffff0004c5be2700: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 102.146412] ^ [ 102.152257] ffff0004c5be2780: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 102.159491] ffff0004c5be2800: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 102.166723] ================================================================== The above bug is caused by use of the wrong pointer in the rpcif_disable_rpm() call. Fix the bug by using the correct pointer. Fixes: 5de15b610f78 ("mtd: hyperbus: add Renesas RPC-IF driver") Signed-off-by: George G. Davis <davis.george@siemens.com> Signed-off-by: Vignesh Raghavendra <vigneshr@ti.com> Link: https://lore.kernel.org/r/20210716204935.25859-1-george_davis@mentor.com
2021-07-17 04:49:35 +08:00
rpcif_disable_rpm(&hyperbus->rpc);
return 0;
}
static struct platform_driver rpcif_platform_driver = {
.probe = rpcif_hb_probe,
.remove = rpcif_hb_remove,
.driver = {
.name = "rpc-if-hyperflash",
},
};
module_platform_driver(rpcif_platform_driver);
MODULE_DESCRIPTION("Renesas RPC-IF HyperFlash driver");
MODULE_LICENSE("GPL v2");