lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID:
 <OS8PR06MB7541516DD4FDEBD72A764042F25FA@OS8PR06MB7541.apcprd06.prod.outlook.com>
Date: Wed, 23 Jul 2025 06:02:20 +0000
From: Ryan Chen <ryan_chen@...eedtech.com>
To: Thomas Gleixner <tglx@...utronix.de>, Rob Herring <robh@...nel.org>,
	Krzysztof Kozlowski <krzk+dt@...nel.org>, Conor Dooley <conor+dt@...nel.org>,
	Joel Stanley <joel@....id.au>, Andrew Jeffery <andrew@...econstruct.com.au>,
	Kevin Chen <kevin_chen@...eedtech.com>, "linux-kernel@...r.kernel.org"
	<linux-kernel@...r.kernel.org>, "devicetree@...r.kernel.org"
	<devicetree@...r.kernel.org>, "linux-arm-kernel@...ts.infradead.org"
	<linux-arm-kernel@...ts.infradead.org>, "linux-aspeed@...ts.ozlabs.org"
	<linux-aspeed@...ts.ozlabs.org>
Subject: RE: [PATCH v3 2/2] irqchip: aspeed: add debugfs support and AST2700
 INTC0/INTC1 routing/protection display

> Subject: Re: [PATCH v3 2/2] irqchip: aspeed: add debugfs support and AST2700
> INTC0/INTC1 routing/protection display
> 
> On Tue, Jul 22 2025 at 17:51, Ryan Chen wrote:
> 
> The subsystem prefix is made up. See:
> 
> https://www.kernel.org/doc/html/latest/process/maintainer-tip.html#patch-su
> bmission-notes

Will prefix update to
Irqchip/aspeed-intc: add debugfs support and AST2700 INTC0/INTC1 routing/protection display

> 
> > AST2700 INTC0/INTC1 nodes ("aspeed,ast2700-intc0/1") not only include
> > the interrupt controller child node ("aspeed,ast2700-intc-ic"), but
> > also provide interrupt routing and register protection features.
> 
> > This patch adds debugfs entries for interrupt routing and protection
> 
> # git grep 'This patch' Documentation/process

Modify to
Adds debugfs entries for interrupt routing and protection status for AST2700 INTC0/INTC1.
> 
> > status for AST2700 INTC0/INTC1.
> >
> > - Register platform driver for "aspeed,ast2700-intc0" and
> > "aspeed,ast2700-intc1" compatible nodes.
> > - Add show_routing/show_prot callbacks for both intc0 and intc1,
> > displaying current interrupt routing and protection register status.
> > - Expose routing/protection information via debugfs for debugging  and
> > validation.
> > +
> > +struct aspeed_intc {
> > +	void __iomem *base;
> > +	struct device *dev;
> > +	struct dentry *dbg_root;
> > +	int (*show_routing)(struct seq_file *s, void *unused);
> > +	int (*show_prot)(struct seq_file *s, void *unused); };
> 
> See the chapter about struct declarations and initializers in the documentation
> I linked to above.

Sorry, I don't see the struct "> > +	int (*show_prot)(struct seq_file *s, void *unused); };"
My original submit is following, it should ok. Am I right?

+struct aspeed_intc {
+	void __iomem *base;
+	struct device *dev;
+	struct dentry *dbg_root;
+	int (*show_routing)(struct seq_file *s, void *unused);
+	int (*show_prot)(struct seq_file *s, void *unused);
+};
https://www.spinics.net/lists/kernel/msg5776957.html
> 
> > +static int aspeed_intc1_show_prot(struct seq_file *s, void *unused) {
> > +	struct aspeed_intc *intc = s->private;
> > +	u32 prot = readl(intc->base);
> > +
> > +	seq_printf(s, "INTC1: 0x%08x\n", prot);
> > +
> > +	static const char * const prot_bits[] = {
> > +		"pprot_ca35: Protect INTC100~150,280~2D0,300~350 write by PSP
> only",
> > +		"pprot_ssp: Protect INTC180~1D0 write by SSP only",
> > +		"pprot_tsp: Protect INTC200~250 write by TSP only",
> > +		"pprot_reg_prot: Protect INTC080~0D4 to be read only",
> > +		"pprot_regrd: Protect INTC080~0D4 to be read protected",
> > +		"pprot_regrd2: Protect INTC100~150,280~2D0,300~350 read by PSP
> only",
> > +		"pprot_regrd3: Protect INTC180~1D0 read by SSP only",
> > +		"pprot_regrd4: Protect INTC200~250 read by TSP only",
> > +		"pprot_mcu0: Protect INTC010,014 write by MCU0 only",
> > +		"pprot_regrd5: Protect INTC010,014 read by MCU0 only",
> > +		"pprot_treg: Protect INTC040~054 to be read protected"
> > +	};
> > +
> > +	for (int i = 0; i < 11; i++)
> > +		seq_printf(s, "  [%2d] %s: %s\n", i, prot_bits[i],
> > +			   (prot & BIT(i)) ? "Enable" : "Disable");
> > +	return 0;
> > +}
> 
> I really have to ask, what the value of this metric ton of string constants and
> decoding is. This is a debug interface, which is intended for developers and
> experts. As these are hardware bits, which are immutable, it's completely
> sufficient to print out the raw values here and let the engineer decode it, no?

The reason for the string decoding was to make debug output more friendly for quick diagnosis during bring-up,
If it is not accepted, I will revise the patch to remove the extra string decoding and only output the raw values.

> 
> > +static int aspeed_intc_probe(struct platform_device *pdev) {
> > +	struct aspeed_intc *intc;
> > +	struct resource *res;
> > +
> > +	intc = devm_kzalloc(&pdev->dev, sizeof(*intc), GFP_KERNEL);
> > +	if (!intc)
> > +		return -ENOMEM;
> > +	intc->dev = &pdev->dev;
> 
> intc->dev is not used anywhere.

Will remove it. 

> 
> > +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > +	intc->base = devm_ioremap_resource(&pdev->dev, res);
> > +	if (IS_ERR(intc->base))
> > +		return PTR_ERR(intc->base);
> > +
> > +	if (of_device_is_compatible(pdev->dev.of_node, "aspeed,ast2700-intc0"))
> {
> > +		intc->show_routing = aspeed_intc0_show_routing;
> > +		intc->show_prot    = aspeed_intc0_show_prot;
> > +	} else if (of_device_is_compatible(pdev->dev.of_node,
> "aspeed,ast2700-intc1")) {
> > +		intc->show_routing = aspeed_intc1_show_routing;
> > +		intc->show_prot    = aspeed_intc1_show_prot;
> > +	} else {
> > +		intc->show_routing = NULL;
> > +		intc->show_prot = NULL;
> 
> What's the point of creating the debugfs entry instead of bailing out?

Yes, will update to
return -ENODEV;
> 
> > +	}
> > +
> > +	platform_set_drvdata(pdev, intc);
> > +
> > +	intc->dbg_root = debugfs_create_dir(dev_name(&pdev->dev), NULL);
> 
> Why storing this? It's just used for setting up the debugfs entry, no?

I'll update the code to use a local variable, by following.

struct dentry *dbg_root;
dbg_root = debugfs_create_dir(dev_name(&pdev->dev), NULL);
if (dbg_root) {
    debugfs_create_file("routing", 0400, dbg_root, intc, &aspeed_intc_routing_fops);
    debugfs_create_file("protection", 0400, dbg_root, intc, &aspeed_intc_prot_fops);
}
> 
> > +	if (intc->dbg_root) {
> > +		debugfs_create_file("routing", 0400, intc->dbg_root, intc,
> > +				    &aspeed_intc_routing_fops);
> > +		debugfs_create_file("protection", 0400, intc->dbg_root, intc,
> > +				    &aspeed_intc_prot_fops);
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static const struct of_device_id aspeed_intc_of_match[] = {
> > +	{ .compatible = "aspeed,ast2700-intc0", },
> > +	{ .compatible = "aspeed,ast2700-intc1", },
> > +	{},
> > +};
> > +
> > +static struct platform_driver aspeed_intc_driver = {
> > +	.probe  = aspeed_intc_probe,
> > +	.driver = {
> > +		.name = "ast2700-intc",
> > +		.of_match_table = aspeed_intc_of_match,
> > +	},
> > +};
> > +builtin_platform_driver(aspeed_intc_driver);
> 
> Why has this to be builtin and not a module? It has zero dependencies on the
> existing code in this file, right?
> Just stick it into a seperate source file and make it modular with a seperate
> Kconfig switch. No point in carrying this code as built-in in multi-platform
> builds.
> 
> This whole platform driver muck is just there to expose the routing and
> protection registers in debugfs even if debugfs is disabled. Seriously?
> 
OK. I will do it in separate source c file and make it modular with Kconfig.
And also depends on DEBUG_FS
Thanks for guidance.


> It's completely disconnected from the interrupt delivery chain as far as the
> kernel is concerned, i.e. it does not provide a interrupt domain/chip. So that
> interface dumps just some register values with a lot of effort and leaves it to
> the user to decode which actual linux interrupt in the real intc-ic interrupt
> domains is affected, right?
> 
> I'm still failing to see the value of all of this. As the kernel does not even
> modify these registers, you are basically implementing a dump facility for
> decoding what the firmware put into those registers, right?
> 
> I don't have a strong opinion about it, but if it has a value, then all of this can
> be done with way smaller code by just dumping the raw register values all in
> one go. No need for two files and string encoding. That's what user space is
> for.
> 
Thanks, I will send a new version with a modular driver and a simplified debugfs interface as you suggested.

> Something like the completely uncompiled below, which I cobbled together
> quickly for illustration. You get the idea.
> 
> Thanks,
> 
>         tglx
> ---
> 
> #define INTC_TYPE_C0	0
> #define INTC_TYPE_C1	1
> 
> struct aspeed_intc {
> 	void __iomem	*base;
> 	unsigned int	type;
> };
> 
> const struct aspeed_intc_data {
> 	char		*name;
> 	unsigned int	groups;
> 	unsigned int	prot_offs;
> 	unsigned int	rout_offs;
> 	unsigned int	rout_gap;
> } aspeed_intc_data[2] = {
> 	{
> 		.name		= "INTC0",
> 		.groups		= 4,
> 		.prot_offs	= 0x40,
> 		.rout_offs	= 0x200,
> 		.rout_gap	= 0x100,
> 	},
> 	{
> 		.name		= "INTC1",
> 		.groups		= 6,
> 		.prot_offs	= 0x0,
> 		.rout_offs	= 0x80,
> 		.rout_gap	= 0x20,
> 	},
> };
> 
> static int aspeed_intc_show(struct seq_file *m, void *unused) {
> 	struct aspeed_intc *intc = m->private;
> 	const struct aspeed_intc_data *d = &aspeed_intc_data[intc->type];
> 	void __iomem *base = intc->base;
> 
> 	seq_printf(m, "%s\n", d->name)
> 	seq_printf(m, "P: 0x%08x\n", readl(base + d->prot_offs));
> 
> 	base += d->rout_offs;
> 	for (unsigned int i = 0; i < d->groups; i++, base += 4) {
> 		seq_printf(m, "R%d: 0x%08x 0x%08x 0x%08x\n", i, readl(base),
> 			   readl(base + d->rout_gap), readl(base + 2 * d->rout_gap));
> 	}
> 	return 0;
> }
> DEFINE_SHOW_ATTRIBUTE(aspeed_intc);
> 
> static int aspeed_intc_probe(struct platform_device *pdev) {
> 	struct aspeed_intc *intc;
> 	struct resource *res;
> 	struct dentry *dir;
> 
> 	intc = devm_kzalloc(&pdev->dev, sizeof(*intc), GFP_KERNEL);
> 	if (!intc)
> 		return -ENOMEM;
> 
> 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> 	intc->base = devm_ioremap_resource(&pdev->dev, res);
> 	if (IS_ERR(intc->base))
> 		return PTR_ERR(intc->base);
> 
> 	if (of_device_is_compatible(pdev->dev.of_node, "aspeed,ast2700-intc0"))
> 		intc->type = INTC_TYPE_C0;
> 	else if (of_device_is_compatible(pdev->dev.of_node,
> "aspeed,ast2700-intc1"))
> 		intc->type = INTC_TYPE_C1;
> 	else
> 		return -ENOTSUPP;
> 
> 	platform_set_drvdata(pdev, intc);
> 
> 	dir = debugfs_create_dir(dev_name(&pdev->dev), NULL);
> 	debugfs_create_file("intc_regs", 0400, dir, intc, &aspeed_intc_fops);
> 	return 0;
> }
> 
> static const struct of_device_id aspeed_intc_of_match[] = {
> 	{ .compatible	= "aspeed,ast2700-intc0", },
> 	{ .compatible	= "aspeed,ast2700-intc1", },
> 	{ },
> };
> MODULE_DEVICE_TABLE(of, aspeed_intc_of_match);
> 
> static struct platform_driver aspeed_intc_driver = {
> 	.probe  = aspeed_intc_probe,
> 	.driver = {
> 		.name		= "ast2700-intc",
> 		.of_match_table	= aspeed_intc_of_match,
> 	},
> };
> module_platform_driver(aspeed_intc_driver);

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ