// SPDX-License-Identifier: GPL-2.0
/*
* Driver for Xilinx TMR Manager IP .
*
* Copyright ( C ) 2022 Advanced Micro Devices , Inc .
*
* Description :
* This driver is developed for TMR Manager , The Triple Modular Redundancy ( TMR )
* Manager is responsible for handling the TMR subsystem state , including
* fault detection and error recovery . The core is triplicated in each of
* the sub - blocks in the TMR subsystem , and provides majority voting of
* its internal state provides soft error detection , correction and
* recovery .
*/
#include <asm /xilinx_mb_manager.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
/* TMR Manager Register offsets */
#define XTMR_MANAGER_CR_OFFSET 0 x0
#define XTMR_MANAGER_FFR_OFFSET 0 x4
#define XTMR_MANAGER_CMR0_OFFSET 0 x8
#define XTMR_MANAGER_CMR1_OFFSET 0 xC
#define XTMR_MANAGER_BDIR_OFFSET 0 x10
#define XTMR_MANAGER_SEMIMR_OFFSET 0 x1C
/* Register Bitmasks/shifts */
#define XTMR_MANAGER_CR_MAGIC1_MASK GENMASK(7 , 0 )
#define XTMR_MANAGER_CR_MAGIC2_MASK GENMASK(15 , 8 )
#define XTMR_MANAGER_CR_RIR_MASK BIT(16 )
#define XTMR_MANAGER_FFR_LM12_MASK BIT(0 )
#define XTMR_MANAGER_FFR_LM13_MASK BIT(1 )
#define XTMR_MANAGER_FFR_LM23_MASK BIT(2 )
#define XTMR_MANAGER_CR_MAGIC2_SHIFT 4
#define XTMR_MANAGER_CR_RIR_SHIFT 16
#define XTMR_MANAGER_CR_BB_SHIFT 18
#define XTMR_MANAGER_MAGIC1_MAX_VAL 255
/**
* struct xtmr_manager_dev - Driver data for TMR Manager
* @ regs : device physical base address
* @ cr_val : control register value
* @ magic1 : Magic 1 hardware configuration value
* @ err_cnt : error statistics count
* @ phys_baseaddr : Physical base address
*/
struct xtmr_manager_dev {
void __iomem *regs;
u32 cr_val;
u32 magic1;
u32 err_cnt;
resource_size_t phys_baseaddr;
};
/* IO accessors */
static inline void xtmr_manager_write(struct xtmr_manager_dev *xtmr_manager,
u32 addr, u32 value)
{
iowrite32(value, xtmr_manager->regs + addr);
}
static inline u32 xtmr_manager_read(struct xtmr_manager_dev *xtmr_manager,
u32 addr)
{
return ioread32(xtmr_manager->regs + addr);
}
static void xmb_manager_reset_handler(struct xtmr_manager_dev *xtmr_manager)
{
/* Clear the FFR Register contents as a part of recovery process. */
xtmr_manager_write(xtmr_manager, XTMR_MANAGER_FFR_OFFSET, 0 );
}
static void xmb_manager_update_errcnt(struct xtmr_manager_dev *xtmr_manager)
{
xtmr_manager->err_cnt++;
}
static ssize_t errcnt_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct xtmr_manager_dev *xtmr_manager = dev_get_drvdata(dev);
return sysfs_emit(buf, "%x\n" , xtmr_manager->err_cnt);
}
static DEVICE_ATTR_RO(errcnt);
static ssize_t dis_block_break_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
struct xtmr_manager_dev *xtmr_manager = dev_get_drvdata(dev);
int ret;
long value;
ret = kstrtoul(buf, 16 , &value);
if (ret)
return ret;
/* unblock the break signal*/
xtmr_manager->cr_val &= ~(1 << XTMR_MANAGER_CR_BB_SHIFT);
xtmr_manager_write(xtmr_manager, XTMR_MANAGER_CR_OFFSET,
xtmr_manager->cr_val);
return size;
}
static DEVICE_ATTR_WO(dis_block_break);
static struct attribute *xtmr_manager_dev_attrs[] = {
&dev_attr_dis_block_break.attr,
&dev_attr_errcnt.attr,
NULL,
};
ATTRIBUTE_GROUPS(xtmr_manager_dev);
static void xtmr_manager_init(struct xtmr_manager_dev *xtmr_manager)
{
/* Clear the SEM interrupt mask register to disable the interrupt */
xtmr_manager_write(xtmr_manager, XTMR_MANAGER_SEMIMR_OFFSET, 0 );
/* Allow recovery reset by default */
xtmr_manager->cr_val = (1 << XTMR_MANAGER_CR_RIR_SHIFT) |
xtmr_manager->magic1;
xtmr_manager_write(xtmr_manager, XTMR_MANAGER_CR_OFFSET,
xtmr_manager->cr_val);
/*
* Configure Break Delay Initialization Register to zero so that
* break occurs immediately
*/
xtmr_manager_write(xtmr_manager, XTMR_MANAGER_BDIR_OFFSET, 0 );
/*
* To come out of break handler need to block the break signal
* in the tmr manager , update the xtmr_manager cr_val for the same
*/
xtmr_manager->cr_val |= (1 << XTMR_MANAGER_CR_BB_SHIFT);
/*
* When the break vector gets asserted because of error injection ,
* the break signal must be blocked before exiting from the
* break handler , Below api updates the TMR manager address and
* control register and error counter callback arguments ,
* which will be used by the break handler to block the
* break and call the callback function .
*/
xmb_manager_register(xtmr_manager->phys_baseaddr, xtmr_manager->cr_val,
(void *)xmb_manager_update_errcnt,
xtmr_manager, (void *)xmb_manager_reset_handler);
}
/**
* xtmr_manager_probe - Driver probe function
* @ pdev : Pointer to the platform_device structure
*
* This is the driver probe routine . It does all the memory
* allocation for the device .
*
* Return : 0 on success and failure value on error
*/
static int xtmr_manager_probe(struct platform_device *pdev)
{
struct xtmr_manager_dev *xtmr_manager;
struct resource *res;
int err;
xtmr_manager = devm_kzalloc(&pdev->dev, sizeof (*xtmr_manager),
GFP_KERNEL);
if (!xtmr_manager)
return -ENOMEM;
xtmr_manager->regs = devm_platform_get_and_ioremap_resource(pdev, 0 , &res);
if (IS_ERR(xtmr_manager->regs))
return PTR_ERR(xtmr_manager->regs);
xtmr_manager->phys_baseaddr = res->start;
err = of_property_read_u32(pdev->dev.of_node, "xlnx,magic1" ,
&xtmr_manager->magic1);
if (err < 0 ) {
dev_err(&pdev->dev, "unable to read xlnx,magic1 property" );
return err;
}
if (xtmr_manager->magic1 > XTMR_MANAGER_MAGIC1_MAX_VAL) {
dev_err(&pdev->dev, "invalid xlnx,magic1 property value" );
return -EINVAL;
}
/* Initialize TMR Manager */
xtmr_manager_init(xtmr_manager);
platform_set_drvdata(pdev, xtmr_manager);
return 0 ;
}
static const struct of_device_id xtmr_manager_of_match[] = {
{
.compatible = "xlnx,tmr-manager-1.0" ,
},
{ /* end of table */ }
};
MODULE_DEVICE_TABLE(of, xtmr_manager_of_match);
static struct platform_driver xtmr_manager_driver = {
.driver = {
.name = "xilinx-tmr_manager" ,
.of_match_table = xtmr_manager_of_match,
.dev_groups = xtmr_manager_dev_groups,
},
.probe = xtmr_manager_probe,
};
module_platform_driver(xtmr_manager_driver);
MODULE_AUTHOR("Advanced Micro Devices, Inc" );
MODULE_DESCRIPTION("Xilinx TMR Manager Driver" );
MODULE_LICENSE("GPL" );
Messung V0.5 in Prozent C=93 H=97 G=94
¤ Dauer der Verarbeitung: 0.8 Sekunden
(vorverarbeitet am 2026-09-29)
¤
*© Formatika GbR, Deutschland