cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

fsl_lbc.c (10410B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Freescale LBC and UPM routines.
      4 *
      5 * Copyright © 2007-2008  MontaVista Software, Inc.
      6 * Copyright © 2010 Freescale Semiconductor
      7 *
      8 * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
      9 * Author: Jack Lan <Jack.Lan@freescale.com>
     10 * Author: Roy Zang <tie-fei.zang@freescale.com>
     11 */
     12
     13#include <linux/init.h>
     14#include <linux/export.h>
     15#include <linux/kernel.h>
     16#include <linux/compiler.h>
     17#include <linux/spinlock.h>
     18#include <linux/types.h>
     19#include <linux/io.h>
     20#include <linux/of.h>
     21#include <linux/of_address.h>
     22#include <linux/of_irq.h>
     23#include <linux/slab.h>
     24#include <linux/sched.h>
     25#include <linux/platform_device.h>
     26#include <linux/interrupt.h>
     27#include <linux/mod_devicetable.h>
     28#include <linux/syscore_ops.h>
     29#include <asm/fsl_lbc.h>
     30
     31static DEFINE_SPINLOCK(fsl_lbc_lock);
     32struct fsl_lbc_ctrl *fsl_lbc_ctrl_dev;
     33EXPORT_SYMBOL(fsl_lbc_ctrl_dev);
     34
     35/**
     36 * fsl_lbc_addr - convert the base address
     37 * @addr_base:	base address of the memory bank
     38 *
     39 * This function converts a base address of lbc into the right format for the
     40 * BR register. If the SOC has eLBC then it returns 32bit physical address
     41 * else it converts a 34bit local bus physical address to correct format of
     42 * 32bit address for BR register (Example: MPC8641).
     43 */
     44u32 fsl_lbc_addr(phys_addr_t addr_base)
     45{
     46	struct device_node *np = fsl_lbc_ctrl_dev->dev->of_node;
     47	u32 addr = addr_base & 0xffff8000;
     48
     49	if (of_device_is_compatible(np, "fsl,elbc"))
     50		return addr;
     51
     52	return addr | ((addr_base & 0x300000000ull) >> 19);
     53}
     54EXPORT_SYMBOL(fsl_lbc_addr);
     55
     56/**
     57 * fsl_lbc_find - find Localbus bank
     58 * @addr_base:	base address of the memory bank
     59 *
     60 * This function walks LBC banks comparing "Base address" field of the BR
     61 * registers with the supplied addr_base argument. When bases match this
     62 * function returns bank number (starting with 0), otherwise it returns
     63 * appropriate errno value.
     64 */
     65int fsl_lbc_find(phys_addr_t addr_base)
     66{
     67	int i;
     68	struct fsl_lbc_regs __iomem *lbc;
     69
     70	if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)
     71		return -ENODEV;
     72
     73	lbc = fsl_lbc_ctrl_dev->regs;
     74	for (i = 0; i < ARRAY_SIZE(lbc->bank); i++) {
     75		u32 br = in_be32(&lbc->bank[i].br);
     76		u32 or = in_be32(&lbc->bank[i].or);
     77
     78		if (br & BR_V && (br & or & BR_BA) == fsl_lbc_addr(addr_base))
     79			return i;
     80	}
     81
     82	return -ENOENT;
     83}
     84EXPORT_SYMBOL(fsl_lbc_find);
     85
     86/**
     87 * fsl_upm_find - find pre-programmed UPM via base address
     88 * @addr_base:	base address of the memory bank controlled by the UPM
     89 * @upm:	pointer to the allocated fsl_upm structure
     90 *
     91 * This function fills fsl_upm structure so you can use it with the rest of
     92 * UPM API. On success this function returns 0, otherwise it returns
     93 * appropriate errno value.
     94 */
     95int fsl_upm_find(phys_addr_t addr_base, struct fsl_upm *upm)
     96{
     97	int bank;
     98	u32 br;
     99	struct fsl_lbc_regs __iomem *lbc;
    100
    101	bank = fsl_lbc_find(addr_base);
    102	if (bank < 0)
    103		return bank;
    104
    105	if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)
    106		return -ENODEV;
    107
    108	lbc = fsl_lbc_ctrl_dev->regs;
    109	br = in_be32(&lbc->bank[bank].br);
    110
    111	switch (br & BR_MSEL) {
    112	case BR_MS_UPMA:
    113		upm->mxmr = &lbc->mamr;
    114		break;
    115	case BR_MS_UPMB:
    116		upm->mxmr = &lbc->mbmr;
    117		break;
    118	case BR_MS_UPMC:
    119		upm->mxmr = &lbc->mcmr;
    120		break;
    121	default:
    122		return -EINVAL;
    123	}
    124
    125	switch (br & BR_PS) {
    126	case BR_PS_8:
    127		upm->width = 8;
    128		break;
    129	case BR_PS_16:
    130		upm->width = 16;
    131		break;
    132	case BR_PS_32:
    133		upm->width = 32;
    134		break;
    135	default:
    136		return -EINVAL;
    137	}
    138
    139	return 0;
    140}
    141EXPORT_SYMBOL(fsl_upm_find);
    142
    143/**
    144 * fsl_upm_run_pattern - actually run an UPM pattern
    145 * @upm:	pointer to the fsl_upm structure obtained via fsl_upm_find
    146 * @io_base:	remapped pointer to where memory access should happen
    147 * @mar:	MAR register content during pattern execution
    148 *
    149 * This function triggers dummy write to the memory specified by the io_base,
    150 * thus UPM pattern actually executed. Note that mar usage depends on the
    151 * pre-programmed AMX bits in the UPM RAM.
    152 */
    153int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base, u32 mar)
    154{
    155	int ret = 0;
    156	unsigned long flags;
    157
    158	if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)
    159		return -ENODEV;
    160
    161	spin_lock_irqsave(&fsl_lbc_lock, flags);
    162
    163	out_be32(&fsl_lbc_ctrl_dev->regs->mar, mar);
    164
    165	switch (upm->width) {
    166	case 8:
    167		out_8(io_base, 0x0);
    168		break;
    169	case 16:
    170		out_be16(io_base, 0x0);
    171		break;
    172	case 32:
    173		out_be32(io_base, 0x0);
    174		break;
    175	default:
    176		ret = -EINVAL;
    177		break;
    178	}
    179
    180	spin_unlock_irqrestore(&fsl_lbc_lock, flags);
    181
    182	return ret;
    183}
    184EXPORT_SYMBOL(fsl_upm_run_pattern);
    185
    186static int fsl_lbc_ctrl_init(struct fsl_lbc_ctrl *ctrl,
    187			     struct device_node *node)
    188{
    189	struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
    190
    191	/* clear event registers */
    192	setbits32(&lbc->ltesr, LTESR_CLEAR);
    193	out_be32(&lbc->lteatr, 0);
    194	out_be32(&lbc->ltear, 0);
    195	out_be32(&lbc->lteccr, LTECCR_CLEAR);
    196	out_be32(&lbc->ltedr, LTEDR_ENABLE);
    197
    198	/* Set the monitor timeout value to the maximum for erratum A001 */
    199	if (of_device_is_compatible(node, "fsl,elbc"))
    200		clrsetbits_be32(&lbc->lbcr, LBCR_BMT, LBCR_BMTPS);
    201
    202	return 0;
    203}
    204
    205/*
    206 * NOTE: This interrupt is used to report localbus events of various kinds,
    207 * such as transaction errors on the chipselects.
    208 */
    209
    210static irqreturn_t fsl_lbc_ctrl_irq(int irqno, void *data)
    211{
    212	struct fsl_lbc_ctrl *ctrl = data;
    213	struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
    214	u32 status;
    215	unsigned long flags;
    216
    217	spin_lock_irqsave(&fsl_lbc_lock, flags);
    218	status = in_be32(&lbc->ltesr);
    219	if (!status) {
    220		spin_unlock_irqrestore(&fsl_lbc_lock, flags);
    221		return IRQ_NONE;
    222	}
    223
    224	out_be32(&lbc->ltesr, LTESR_CLEAR);
    225	out_be32(&lbc->lteatr, 0);
    226	out_be32(&lbc->ltear, 0);
    227	ctrl->irq_status = status;
    228
    229	if (status & LTESR_BM)
    230		dev_err(ctrl->dev, "Local bus monitor time-out: "
    231			"LTESR 0x%08X\n", status);
    232	if (status & LTESR_WP)
    233		dev_err(ctrl->dev, "Write protect error: "
    234			"LTESR 0x%08X\n", status);
    235	if (status & LTESR_ATMW)
    236		dev_err(ctrl->dev, "Atomic write error: "
    237			"LTESR 0x%08X\n", status);
    238	if (status & LTESR_ATMR)
    239		dev_err(ctrl->dev, "Atomic read error: "
    240			"LTESR 0x%08X\n", status);
    241	if (status & LTESR_CS)
    242		dev_err(ctrl->dev, "Chip select error: "
    243			"LTESR 0x%08X\n", status);
    244	if (status & LTESR_FCT) {
    245		dev_err(ctrl->dev, "FCM command time-out: "
    246			"LTESR 0x%08X\n", status);
    247		smp_wmb();
    248		wake_up(&ctrl->irq_wait);
    249	}
    250	if (status & LTESR_PAR) {
    251		dev_err(ctrl->dev, "Parity or Uncorrectable ECC error: "
    252			"LTESR 0x%08X\n", status);
    253		smp_wmb();
    254		wake_up(&ctrl->irq_wait);
    255	}
    256	if (status & LTESR_CC) {
    257		smp_wmb();
    258		wake_up(&ctrl->irq_wait);
    259	}
    260	if (status & ~LTESR_MASK)
    261		dev_err(ctrl->dev, "Unknown error: "
    262			"LTESR 0x%08X\n", status);
    263	spin_unlock_irqrestore(&fsl_lbc_lock, flags);
    264	return IRQ_HANDLED;
    265}
    266
    267/*
    268 * fsl_lbc_ctrl_probe
    269 *
    270 * called by device layer when it finds a device matching
    271 * one our driver can handled. This code allocates all of
    272 * the resources needed for the controller only.  The
    273 * resources for the NAND banks themselves are allocated
    274 * in the chip probe function.
    275*/
    276
    277static int fsl_lbc_ctrl_probe(struct platform_device *dev)
    278{
    279	int ret;
    280
    281	if (!dev->dev.of_node) {
    282		dev_err(&dev->dev, "Device OF-Node is NULL");
    283		return -EFAULT;
    284	}
    285
    286	fsl_lbc_ctrl_dev = kzalloc(sizeof(*fsl_lbc_ctrl_dev), GFP_KERNEL);
    287	if (!fsl_lbc_ctrl_dev)
    288		return -ENOMEM;
    289
    290	dev_set_drvdata(&dev->dev, fsl_lbc_ctrl_dev);
    291
    292	spin_lock_init(&fsl_lbc_ctrl_dev->lock);
    293	init_waitqueue_head(&fsl_lbc_ctrl_dev->irq_wait);
    294
    295	fsl_lbc_ctrl_dev->regs = of_iomap(dev->dev.of_node, 0);
    296	if (!fsl_lbc_ctrl_dev->regs) {
    297		dev_err(&dev->dev, "failed to get memory region\n");
    298		ret = -ENODEV;
    299		goto err;
    300	}
    301
    302	fsl_lbc_ctrl_dev->irq[0] = irq_of_parse_and_map(dev->dev.of_node, 0);
    303	if (!fsl_lbc_ctrl_dev->irq[0]) {
    304		dev_err(&dev->dev, "failed to get irq resource\n");
    305		ret = -ENODEV;
    306		goto err;
    307	}
    308
    309	fsl_lbc_ctrl_dev->dev = &dev->dev;
    310
    311	ret = fsl_lbc_ctrl_init(fsl_lbc_ctrl_dev, dev->dev.of_node);
    312	if (ret < 0)
    313		goto err;
    314
    315	ret = request_irq(fsl_lbc_ctrl_dev->irq[0], fsl_lbc_ctrl_irq, 0,
    316				"fsl-lbc", fsl_lbc_ctrl_dev);
    317	if (ret != 0) {
    318		dev_err(&dev->dev, "failed to install irq (%d)\n",
    319			fsl_lbc_ctrl_dev->irq[0]);
    320		ret = fsl_lbc_ctrl_dev->irq[0];
    321		goto err;
    322	}
    323
    324	fsl_lbc_ctrl_dev->irq[1] = irq_of_parse_and_map(dev->dev.of_node, 1);
    325	if (fsl_lbc_ctrl_dev->irq[1]) {
    326		ret = request_irq(fsl_lbc_ctrl_dev->irq[1], fsl_lbc_ctrl_irq,
    327				IRQF_SHARED, "fsl-lbc-err", fsl_lbc_ctrl_dev);
    328		if (ret) {
    329			dev_err(&dev->dev, "failed to install irq (%d)\n",
    330					fsl_lbc_ctrl_dev->irq[1]);
    331			ret = fsl_lbc_ctrl_dev->irq[1];
    332			goto err1;
    333		}
    334	}
    335
    336	/* Enable interrupts for any detected events */
    337	out_be32(&fsl_lbc_ctrl_dev->regs->lteir, LTEIR_ENABLE);
    338
    339	return 0;
    340
    341err1:
    342	free_irq(fsl_lbc_ctrl_dev->irq[0], fsl_lbc_ctrl_dev);
    343err:
    344	iounmap(fsl_lbc_ctrl_dev->regs);
    345	kfree(fsl_lbc_ctrl_dev);
    346	fsl_lbc_ctrl_dev = NULL;
    347	return ret;
    348}
    349
    350#ifdef CONFIG_SUSPEND
    351
    352/* save lbc registers */
    353static int fsl_lbc_syscore_suspend(void)
    354{
    355	struct fsl_lbc_ctrl *ctrl;
    356	struct fsl_lbc_regs __iomem *lbc;
    357
    358	ctrl = fsl_lbc_ctrl_dev;
    359	if (!ctrl)
    360		goto out;
    361
    362	lbc = ctrl->regs;
    363	if (!lbc)
    364		goto out;
    365
    366	ctrl->saved_regs = kmalloc(sizeof(struct fsl_lbc_regs), GFP_KERNEL);
    367	if (!ctrl->saved_regs)
    368		return -ENOMEM;
    369
    370	_memcpy_fromio(ctrl->saved_regs, lbc, sizeof(struct fsl_lbc_regs));
    371
    372out:
    373	return 0;
    374}
    375
    376/* restore lbc registers */
    377static void fsl_lbc_syscore_resume(void)
    378{
    379	struct fsl_lbc_ctrl *ctrl;
    380	struct fsl_lbc_regs __iomem *lbc;
    381
    382	ctrl = fsl_lbc_ctrl_dev;
    383	if (!ctrl)
    384		goto out;
    385
    386	lbc = ctrl->regs;
    387	if (!lbc)
    388		goto out;
    389
    390	if (ctrl->saved_regs) {
    391		_memcpy_toio(lbc, ctrl->saved_regs,
    392				sizeof(struct fsl_lbc_regs));
    393		kfree(ctrl->saved_regs);
    394		ctrl->saved_regs = NULL;
    395	}
    396
    397out:
    398	return;
    399}
    400#endif /* CONFIG_SUSPEND */
    401
    402static const struct of_device_id fsl_lbc_match[] = {
    403	{ .compatible = "fsl,elbc", },
    404	{ .compatible = "fsl,pq3-localbus", },
    405	{ .compatible = "fsl,pq2-localbus", },
    406	{ .compatible = "fsl,pq2pro-localbus", },
    407	{},
    408};
    409
    410#ifdef CONFIG_SUSPEND
    411static struct syscore_ops lbc_syscore_pm_ops = {
    412	.suspend = fsl_lbc_syscore_suspend,
    413	.resume = fsl_lbc_syscore_resume,
    414};
    415#endif
    416
    417static struct platform_driver fsl_lbc_ctrl_driver = {
    418	.driver = {
    419		.name = "fsl-lbc",
    420		.of_match_table = fsl_lbc_match,
    421	},
    422	.probe = fsl_lbc_ctrl_probe,
    423};
    424
    425static int __init fsl_lbc_init(void)
    426{
    427#ifdef CONFIG_SUSPEND
    428	register_syscore_ops(&lbc_syscore_pm_ops);
    429#endif
    430	return platform_driver_register(&fsl_lbc_ctrl_driver);
    431}
    432subsys_initcall(fsl_lbc_init);