drivers/edac/highbank_mc_edac.c
Source file repositories/reference/linux-study-clean/drivers/edac/highbank_mc_edac.c
File Facts
- System
- Linux kernel
- Corpus path
drivers/edac/highbank_mc_edac.c- Extension
.c- Size
- 7073 bytes
- Lines
- 276
- Domain
- Driver Families
- Bucket
- drivers/edac
- Inferred role
- Driver Families: implementation source
- Status
- source implementation candidate
Why This File Exists
Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.
- Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.
- Touches IRQ or DMA behavior; this matters for the representative real-device path.
- Defines or uses C structs; map object ownership, embedded links, reference counts, and lock ownership.
Dependency Surface
linux/types.hlinux/kernel.hlinux/ctype.hlinux/edac.hlinux/interrupt.hlinux/of.hlinux/of_device.hlinux/platform_device.hlinux/uaccess.hedac_module.h
Detected Declarations
struct hb_mc_drvdatastruct hb_mc_settingsfunction highbank_mc_err_handlerfunction highbank_mc_err_injectfunction highbank_mc_inject_ctrlfunction highbank_mc_probefunction highbank_mc_remove
Annotated Snippet
struct hb_mc_drvdata {
void __iomem *mc_err_base;
void __iomem *mc_int_base;
};
static irqreturn_t highbank_mc_err_handler(int irq, void *dev_id)
{
struct mem_ctl_info *mci = dev_id;
struct hb_mc_drvdata *drvdata = mci->pvt_info;
u32 status, err_addr;
/* Read the interrupt status register */
status = readl(drvdata->mc_int_base + HB_DDR_ECC_INT_STATUS);
if (status & HB_DDR_ECC_INT_STAT_UE) {
err_addr = readl(drvdata->mc_err_base + HB_DDR_ECC_U_ERR_ADDR);
edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
err_addr >> PAGE_SHIFT,
err_addr & ~PAGE_MASK, 0,
0, 0, -1,
mci->ctl_name, "");
}
if (status & HB_DDR_ECC_INT_STAT_CE) {
u32 syndrome = readl(drvdata->mc_err_base + HB_DDR_ECC_C_ERR_STAT);
syndrome = (syndrome >> 8) & 0xff;
err_addr = readl(drvdata->mc_err_base + HB_DDR_ECC_C_ERR_ADDR);
edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
err_addr >> PAGE_SHIFT,
err_addr & ~PAGE_MASK, syndrome,
0, 0, -1,
mci->ctl_name, "");
}
/* clear the error, clears the interrupt */
writel(status, drvdata->mc_int_base + HB_DDR_ECC_INT_ACK);
return IRQ_HANDLED;
}
static void highbank_mc_err_inject(struct mem_ctl_info *mci, u8 synd)
{
struct hb_mc_drvdata *pdata = mci->pvt_info;
u32 reg;
reg = readl(pdata->mc_err_base + HB_DDR_ECC_OPT);
reg &= HB_DDR_ECC_OPT_MODE_MASK;
reg |= (synd << HB_DDR_ECC_OPT_XOR_SHIFT) | HB_DDR_ECC_OPT_FWC;
writel(reg, pdata->mc_err_base + HB_DDR_ECC_OPT);
}
#define to_mci(k) container_of(k, struct mem_ctl_info, dev)
static ssize_t highbank_mc_inject_ctrl(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct mem_ctl_info *mci = to_mci(dev);
u8 synd;
if (kstrtou8(buf, 16, &synd))
return -EINVAL;
highbank_mc_err_inject(mci, synd);
return count;
}
static DEVICE_ATTR(inject_ctrl, S_IWUSR, NULL, highbank_mc_inject_ctrl);
static struct attribute *highbank_dev_attrs[] = {
&dev_attr_inject_ctrl.attr,
NULL
};
ATTRIBUTE_GROUPS(highbank_dev);
struct hb_mc_settings {
int err_offset;
int int_offset;
};
static struct hb_mc_settings hb_settings = {
.err_offset = HB_DDR_ECC_ERR_BASE,
.int_offset = HB_DDR_ECC_INT_BASE,
};
static struct hb_mc_settings mw_settings = {
.err_offset = MW_DDR_ECC_ERR_BASE,
.int_offset = MW_DDR_ECC_INT_BASE,
};
static const struct of_device_id hb_ddr_ctrl_of_match[] = {
Annotation
- Immediate include surface: `linux/types.h`, `linux/kernel.h`, `linux/ctype.h`, `linux/edac.h`, `linux/interrupt.h`, `linux/of.h`, `linux/of_device.h`, `linux/platform_device.h`.
- Detected declarations: `struct hb_mc_drvdata`, `struct hb_mc_settings`, `function highbank_mc_err_handler`, `function highbank_mc_err_inject`, `function highbank_mc_inject_ctrl`, `function highbank_mc_probe`, `function highbank_mc_remove`.
- Atlas domain: Driver Families / drivers/edac.
- Implementation status: source implementation candidate.
- IRQ or DMA behavior appears here, which is relevant to the selected PCIe/NVMe device path.
Implementation Notes
- This generated page is the file-by-file coverage layer; curated subsystem chapters should link here when they synthesize a multi-file control flow.
- Core OS pages should be promoted from atlas-only to deep-reviewed when they explain data structures, invariants, locking, lifecycle, and C implementation snippets.
- Driver-family pages are intentionally pattern-oriented unless they are part of the selected PCIe/NVMe representative device path.