Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH 2/2] ARM: dts: aspeed: Add ASRock Rack B650D4U BMC
From: Andrew Lunn @ 2026-05-12 18:35 UTC (permalink / raw)
  To: Prasanth Kumar Padarthi
  Cc: joel, andrew, robh, krzk+dt, conor+dt, devicetree, linux-aspeed,
	linux-arm-kernel
In-Reply-To: <20260512175019.47548-3-prasanth.padarthi10@gmail.com>

> +/* Dedicated Management LAN */
> +&mac0 {
> +	status = "okay";
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_rgmii1_default &pinctrl_mdio1_default>;

What does this connect to? A PHY? NCSI?

     Andrew


^ permalink raw reply

* Re: [PATCH v3 6/7] gpio: realtek: Add driver for Realtek DHC RTD1625 SoC
From: Andy Shevchenko @ 2026-05-12 18:50 UTC (permalink / raw)
  To: Yu-Chun Lin
  Cc: linusw, brgl, robh, krzk+dt, conor+dt, afaerber, wbg,
	mathieu.dubois-briand, mwalle, lars, Michael.Hennerich, jic23,
	nuno.sa, andy, dlechner, tychang, linux-gpio, devicetree,
	linux-kernel, linux-arm-kernel, linux-realtek-soc, linux-iio,
	cy.huang, stanley_chang, james.tai
In-Reply-To: <20260512033317.1602537-7-eleanor.lin@realtek.com>

On Tue, May 12, 2026 at 11:33:16AM +0800, Yu-Chun Lin wrote:

> Add support for the GPIO controller found on Realtek DHC RTD1625 SoCs.

The below paragraphs are all the implementation details that are not so
important to be in the commit message. They fit the comment block after
the '---' line below, though...

> Unlike the existing Realtek GPIO driver (drivers/gpio/gpio-rtd.c),
> which manages pins via shared bank registers, the RTD1625 introduces
> a per-pin register architecture. Each GPIO line now has its own
> dedicated 32-bit control register to manage configuration independently,
> including direction, output value, input value, interrupt enable, and
> debounce. Therefore, this distinct hardware design requires a separate
> driver.
> 
> The driver leverages the gpio-regmap framework, utilizing the recently
> introduced write-enable and operation-specific mask translation features.
> 
> Additionally, because the controller utilizes multiple independent IRQ
> status registers (assert, de-assert, and level) which cannot be mapped
> via standard regmap_irq_chip, the driver implements a custom irq_domain.
> 
> Signed-off-by: Tzuyi Chang <tychang@realtek.com>
> Co-developed-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> ---

...somewhere here.

...


> +#include <linux/bitfield.h>
> +#include <linux/bitops.h>

Missing cleanup.h, may be more.

> +#include <linux/gpio/driver.h>
> +#include <linux/gpio/regmap.h>
> +#include <linux/interrupt.h>
> +#include <linux/irqchip.h>

> +#include <linux/irqdomain.h>
> +#include <linux/irqchip/chained_irq.h>
> +#include <linux/irqdomain.h>

If you sort headers alphabetically, you will see the duplication.

> +#include <linux/mfd/syscon.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/property.h>
> +#include <linux/regmap.h>
> +#include <linux/spinlock.h>
> +#include <linux/types.h>

...

> +struct rtd1625_gpio {
> +	struct gpio_chip *gpio_chip;
> +	const struct rtd1625_gpio_info *info;

> +	void __iomem *base;

Is it used? Also naming is confusing with unsigned int base in some functions
below.

> +	struct regmap *regmap;
> +	unsigned int irqs[3];

This 3 is also used when assign num_irqs below, perhaps define it with
meaningful name? (The 2 also might need a definition in the same way.)

> +	raw_spinlock_t lock;
> +	struct irq_domain *domain;
> +	unsigned int *save_regs;
> +};

...

> +static int rtd1625_reg_mask_xlate(struct gpio_regmap *gpio, enum gpio_regmap_operation op,
> +				  unsigned int base, unsigned int offset, unsigned int *reg,
> +				  unsigned int *mask)

Use logical split.

static int rtd1625_reg_mask_xlate(struct gpio_regmap *gpio, enum gpio_regmap_operation op,
				  unsigned int base, unsigned int offset,
				  unsigned int *reg, unsigned int *mask)

OR (as suggested earlier)

static int rtd1625_reg_mask_xlate(struct gpio_regmap *gpio,
				  enum gpio_regmap_operation op,
				  unsigned int base, unsigned int offset,
				  unsigned int *reg, unsigned int *mask)

...

> +static unsigned int rtd1625_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset,
> +					      unsigned int debounce)
> +{
> +	struct rtd1625_gpio *data = gpiochip_get_data(chip);
> +	u8 deb_val;
> +	u32 val;
> +
> +	switch (debounce) {
> +	case 1:
> +		deb_val = RTD1625_GPIO_DEBOUNCE_1US;
> +		break;
> +	case 10:
> +		deb_val = RTD1625_GPIO_DEBOUNCE_10US;
> +		break;
> +	case 100:
> +		deb_val = RTD1625_GPIO_DEBOUNCE_100US;
> +		break;
> +	case 1000:
> +		deb_val = RTD1625_GPIO_DEBOUNCE_1MS;
> +		break;
> +	case 10000:
> +		deb_val = RTD1625_GPIO_DEBOUNCE_10MS;
> +		break;
> +	case 20000:
> +		deb_val = RTD1625_GPIO_DEBOUNCE_20MS;
> +		break;
> +	case 30000:
> +		deb_val = RTD1625_GPIO_DEBOUNCE_30MS;
> +		break;
> +	case 50000:
> +		deb_val = RTD1625_GPIO_DEBOUNCE_50MS;
> +		break;
> +	default:
> +		return -ENOTSUPP;
> +	}
> +
> +	val = FIELD_PREP(RTD1625_GPIO_DEBOUNCE, deb_val) | RTD1625_GPIO_DEBOUNCE_WREN;

> +	regmap_write(data->regmap, GPIO_CONTROL(offset), val);

Neither here, nor in some other places the returned value from regmap APIs is
not checked. Is it okay?

> +	return 0;
> +}
> +
> +static int rtd1625_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
> +				   unsigned long config)
> +{
> +	int debounce;

Can it be negative?

> +	if (pinconf_to_config_param(config) == PIN_CONFIG_INPUT_DEBOUNCE) {
> +		debounce = pinconf_to_config_argument(config);
> +		return rtd1625_gpio_set_debounce(chip, offset, debounce);
> +	}
> +
> +	return gpiochip_generic_config(chip, offset, config);
> +}

...

> +static void rtd1625_gpio_irq_handle(struct irq_desc *desc)
> +{
> +	unsigned int (*get_reg_offset)(struct rtd1625_gpio *gpio, unsigned int offset);
> +	struct rtd1625_gpio *data = irq_desc_get_handler_data(desc);
> +	struct irq_chip *chip = irq_desc_get_chip(desc);
> +	unsigned int irq = irq_desc_get_irq(desc);
> +	struct irq_domain *domain = data->domain;
> +	unsigned int reg_offset, i, j, val;
> +	irq_hw_number_t hwirq;
> +	unsigned long status;
> +	unsigned int girq;
> +	u32 irq_type;
> +
> +	if (irq == data->irqs[0])
> +		get_reg_offset = &rtd1625_gpio_gpa_offset;
> +	else if (irq == data->irqs[1])
> +		get_reg_offset = &rtd1625_gpio_gpda_offset;
> +	else if (irq == data->irqs[2])
> +		get_reg_offset = &rtd1625_gpio_level_offset;
> +	else
> +		return;
> +
> +	chained_irq_enter(chip, desc);

> +	for (i = 0; i < data->info->num_gpios; i += 32) {

	for (unsigned int i = 0; i < data->info->num_gpios; i += 32) {

> +		reg_offset = get_reg_offset(data, i);
> +		regmap_read(data->regmap, reg_offset, &val);
> +
> +		status = val;
> +
> +		/* Clear edge interrupts; level interrupts are cleared in ->irq_ack() */
> +		if (irq != data->irqs[2])
> +			regmap_write(data->regmap, reg_offset, status);

This is interesting... Can't we rely on IRQ core to take care of this? (And
replay if required.)

> +		for_each_set_bit(j, &status, 32) {
> +			hwirq = i + j;
> +			girq = irq_find_mapping(domain, hwirq);
> +			irq_type = irq_get_trigger_type(girq);

> +			if (irq == data->irqs[1] && irq_type != IRQ_TYPE_EDGE_BOTH)

Why is the IRQ type check here and not in set_type() callback?
I think we should simply reject to even lock such a configuration as IRQ.

> +				continue;
> +
> +			generic_handle_domain_irq(domain, hwirq);
> +		}
> +	}
> +
> +	chained_irq_exit(chip, desc);
> +}

> +static void rtd1625_gpio_enable_edge_irq(struct rtd1625_gpio *data, irq_hw_number_t hwirq)
> +{
> +	int gpda_reg_offset = rtd1625_gpio_gpda_offset(data, hwirq);
> +	int gpa_reg_offset = rtd1625_gpio_gpa_offset(data, hwirq);
> +	u32 clr_mask = BIT(hwirq % 32);
> +	u32 val;
> +
> +	guard(raw_spinlock_irqsave)(&data->lock);

+ blank line. Same to other cases when guard()() is being used.

> +	regmap_write(data->regmap, gpa_reg_offset, clr_mask);
> +	regmap_write(data->regmap, gpda_reg_offset, clr_mask);
> +	val = RTD1625_GPIO_EDGE_INT_EN | RTD1625_GPIO_WREN(RTD1625_GPIO_EDGE_INT_EN);
> +	regmap_write(data->regmap, data->info->base_offset + GPIO_CONTROL(hwirq), val);
> +}

...

> +static void rtd1625_gpio_enable_irq(struct irq_data *d)
> +{
> +	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
> +	irq_hw_number_t hwirq = irqd_to_hwirq(d);
> +	u32 irq_type = irqd_get_trigger_type(d);
> +	struct rtd1625_gpio *data;
> +	struct gpio_regmap *gpio;

> +	gpio = gpiochip_get_data(gc);
> +	data = gpio_regmap_get_drvdata(gpio);

Why not unify these with the above, we don't validate them anyway...
Same Q to other cases like this.

> +	gpiochip_enable_irq(gc, hwirq);
> +
> +	if (irq_type & IRQ_TYPE_EDGE_BOTH)
> +		rtd1625_gpio_enable_edge_irq(data, hwirq);
> +	else if (irq_type & IRQ_TYPE_LEVEL_MASK)
> +		rtd1625_gpio_enable_level_irq(data, hwirq);
> +}

...

> +static int rtd1625_gpio_irq_set_level_type(struct irq_data *d, bool level)
> +{
> +	u32 val = RTD1625_GPIO_WREN(RTD1625_GPIO_LEVEL_INT_DP);
> +	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
> +	irq_hw_number_t hwirq = irqd_to_hwirq(d);
> +	struct rtd1625_gpio *data;
> +	struct gpio_regmap *gpio;
> +
> +	gpio = gpiochip_get_data(gc);
> +	data = gpio_regmap_get_drvdata(gpio);

+ blank line (and actually see above).

> +	if (!(data->info->irq_type_support & IRQ_TYPE_LEVEL_MASK))
> +		return -EINVAL;

> +	scoped_guard(raw_spinlock_irqsave, &data->lock) {

> +		if (level)
> +			val |= RTD1625_GPIO_LEVEL_INT_DP;

Why this local variable change is under the lock?

> +		regmap_write(data->regmap, data->info->base_offset + GPIO_CONTROL(hwirq), val);
> +	}
> +
> +	irq_set_handler_locked(d, handle_level_irq);
> +
> +	return 0;
> +}

...

> +static int rtd1625_gpio_irq_set_edge_type(struct irq_data *d, bool polarity)

Similar comments as per above.

...

> +static int rtd1625_gpio_irq_set_type(struct irq_data *d, unsigned int type)
> +{
> +	int ret;

Unneeded, just return directly from each of the cases.

> +
> +	switch (type & IRQ_TYPE_SENSE_MASK) {
> +	case IRQ_TYPE_EDGE_RISING:
> +		ret = rtd1625_gpio_irq_set_edge_type(d, 1);
> +		break;
> +	case IRQ_TYPE_EDGE_FALLING:
> +		ret = rtd1625_gpio_irq_set_edge_type(d, 0);
> +		break;
> +	case IRQ_TYPE_EDGE_BOTH:
> +		ret = rtd1625_gpio_irq_set_edge_type(d, 1);
> +		break;
> +	case IRQ_TYPE_LEVEL_HIGH:
> +		ret = rtd1625_gpio_irq_set_level_type(d, 0);
> +		break;
> +	case IRQ_TYPE_LEVEL_LOW:
> +		ret = rtd1625_gpio_irq_set_level_type(d, 1);
> +		break;
> +	default:
> +		ret = -EINVAL;

Missing break, but rather simply

		return -EINVAL;

as mentioned above. In the similar way for the rest of switch-cases.

> +	}
> +
> +	return ret;
> +}

...

> +static int rtd1625_gpio_setup_irq(struct platform_device *pdev, struct rtd1625_gpio *data)
> +{
> +	int num_irqs, irq, i;

Why is 'num_irqs' signed?

> +	irq = platform_get_irq_optional(pdev, 0);
> +	if (irq == -ENXIO)
> +		return 0;

This is strange. You mean that you are only interested in the first IRQ? What
about the case when the first one is not available, while the second is?

> +	if (irq < 0)
> +		return irq;

This partially duplicates the below.

> +	num_irqs = (data->info->irq_type_support & IRQ_TYPE_LEVEL_MASK) ? 3 : 2;

> +	for (i = 0; i < num_irqs; i++) {

The iterator is local to the loop, hence

	for (unsigned int i = 0; i < num_irqs; i++) {

> +		irq = platform_get_irq(pdev, i);
> +		if (irq < 0)
> +			return irq;
> +
> +		data->irqs[i] = irq;
> +		irq_set_chained_handler_and_data(data->irqs[i], rtd1625_gpio_irq_handle, data);
> +	}
> +
> +	return 0;
> +}

...

> +static int rtd1625_gpio_irq_map(struct irq_domain *domain, unsigned int irq,
> +				irq_hw_number_t hwirq)
> +{
> +	struct rtd1625_gpio *data = domain->host_data;
> +
> +	irq_set_chip_data(irq, data->gpio_chip);
> +
> +	irq_set_chip_and_handler(irq, &rtd1625_iso_gpio_irq_chip, handle_bad_irq);
> +
> +	irq_set_noprobe(irq);

Shouldn't you assign a lockdep class?

> +	return 0;
> +}

...

> +static const struct regmap_config rtd1625_gpio_regmap_config = {
> +	.reg_bits = 32,
> +	.reg_stride = 4,
> +	.val_bits = 32,

> +	.disable_locking = true,

Hmm... This effectively drops the debugfs support, perhaps make it depend on
CONFIG_DEBUG_GPIO?

> +};

...

> +static int rtd1625_gpio_probe(struct platform_device *pdev)
> +{
> +	struct gpio_regmap_config config = {0};

'0' is redundant.

> +	struct device *dev = &pdev->dev;
> +	struct gpio_regmap *gpio_reg;
> +	struct rtd1625_gpio *data;
> +	void __iomem *irq_base;
> +	int ret;
> +
> +	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
> +	if (!data)
> +		return -ENOMEM;
> +
> +	data->info = device_get_match_data(dev);
> +	if (!data->info)
> +		return -EINVAL;
> +
> +	irq_base = devm_platform_ioremap_resource(pdev, 0);
> +	if (IS_ERR(irq_base))
> +		return PTR_ERR(irq_base);
> +
> +	data->regmap = devm_regmap_init_mmio(dev, irq_base,
> +					     &rtd1625_gpio_regmap_config);

I would go with a single line

	data->regmap = devm_regmap_init_mmio(dev, irq_base, &rtd1625_gpio_regmap_config);

> +	if (IS_ERR(data->regmap))
> +		return PTR_ERR(data->regmap);
> +
> +	data->save_regs = devm_kzalloc(dev, data->info->num_gpios *
> +				       sizeof(*data->save_regs), GFP_KERNEL);

This is devm_kcalloc().

> +	if (!data->save_regs)
> +		return -ENOMEM;
> +
> +	config.parent = dev;
> +	config.regmap = data->regmap;
> +	config.ngpio = data->info->num_gpios;
> +	config.reg_dat_base = data->info->base_offset;
> +	config.reg_set_base = data->info->base_offset;
> +	config.reg_mask_xlate = rtd1625_reg_mask_xlate;
> +	config.set_config = rtd1625_gpio_set_config;
> +	config.reg_dir_out_base = data->info->base_offset;
> +
> +	data->domain = irq_domain_add_linear(dev->of_node,

No, use fwnode variant from the start.

> +					     data->info->num_gpios,
> +					     &rtd1625_gpio_irq_domain_ops,
> +					     data);
> +	if (!data->domain)
> +		return -ENOMEM;
> +
> +	ret = rtd1625_gpio_setup_irq(pdev, data);
> +	if (ret) {
> +		irq_domain_remove(data->domain);
> +		return ret;
> +	}
> +
> +	config.irq_domain = data->domain;
> +	config.drvdata = data;
> +	platform_set_drvdata(pdev, data);
> +
> +	gpio_reg = devm_gpio_regmap_register(dev, &config);
> +	if (IS_ERR(gpio_reg)) {

> +		irq_domain_remove(data->domain);

This is wrong. The remove will do the opposite order. It means that
irq_domain_create_linear() has to be wrapped to become a managed resource.

> +		return PTR_ERR(gpio_reg);
> +	}
> +
> +	data->gpio_chip = gpio_regmap_get_gpiochip(gpio_reg);
> +
> +	return 0;
> +}
> +
> +static const struct rtd1625_gpio_info rtd1625_iso_gpio_info = {
> +	.num_gpios		= 166,
> +	.irq_type_support	= IRQ_TYPE_EDGE_BOTH,
> +	.base_offset		= 0x100,
> +	.gpa_offset		= 0x0,
> +	.gpda_offset		= 0x20,

Use fixed-width for the register offsets, id est 0x000, 0x020, and so on...

> +	.write_en_all		= RTD1625_ISO_GPIO_WREN_ALL,
> +};
> +
> +static const struct rtd1625_gpio_info rtd1625_isom_gpio_info = {
> +	.num_gpios		= 4,
> +	.irq_type_support	= IRQ_TYPE_EDGE_BOTH | IRQ_TYPE_LEVEL_LOW |
> +				  IRQ_TYPE_LEVEL_HIGH,
> +	.base_offset		= 0x20,
> +	.gpa_offset		= 0x0,
> +	.gpda_offset		= 0x4,
> +	.level_offset		= 0x18,
> +	.write_en_all		= RTD1625_ISOM_GPIO_WREN_ALL,
> +};

...

> +static const struct of_device_id rtd1625_gpio_of_matches[] = {
> +	{ .compatible = "realtek,rtd1625-iso-gpio", .data = &rtd1625_iso_gpio_info },
> +	{ .compatible = "realtek,rtd1625-isom-gpio", .data = &rtd1625_isom_gpio_info },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, rtd1625_gpio_of_matches);

Move the initialiser and respective MODULE_DEVICE_TABLE() closer to its user.

...

> +static int rtd1625_gpio_suspend(struct device *dev)
> +{
> +	struct rtd1625_gpio *data = dev_get_drvdata(dev);
> +	const struct rtd1625_gpio_info *info = data->info;
> +	int i;
> +
> +	for (i = 0; i < info->num_gpios; i++)

	for (unsigned int i = 0; i < info->num_gpios; i++)

> +		regmap_read(data->regmap, data->info->base_offset + GPIO_CONTROL(i),
> +			    &data->save_regs[i]);
> +
> +	return 0;
> +}
> +
> +static int rtd1625_gpio_resume(struct device *dev)
> +{
> +	struct rtd1625_gpio *data = dev_get_drvdata(dev);
> +	const struct rtd1625_gpio_info *info = data->info;
> +	int i;
> +
> +	for (i = 0; i < info->num_gpios; i++)

Ditto.

> +		regmap_write(data->regmap, data->info->base_offset + GPIO_CONTROL(i),
> +			     data->save_regs[i] | info->write_en_all);
> +
> +	return 0;
> +}

...

> +DEFINE_NOIRQ_DEV_PM_OPS(rtd1625_gpio_pm_ops, rtd1625_gpio_suspend, rtd1625_gpio_resume);

Not static? Why?

-- 
With Best Regards,
Andy Shevchenko




^ permalink raw reply

* Re: [PATCH] ARM: OMAP2+: Make OMAP4 finish_suspend callback CFI-safe
From: Andreas Kemnade @ 2026-05-12 19:05 UTC (permalink / raw)
  To: Nathan Chancellor
  Cc: Mithil Bavishi, Aaro Koskinen, Kevin Hilman, Roger Quadros,
	Tony Lindgren, Russell King, Sami Tolvanen, Kees Cook,
	linux-arm-kernel, linux-omap, llvm, linux-kernel
In-Reply-To: <20260512135757.GB570003@ax162>

On Tue, 12 May 2026 22:57:57 +0900
Nathan Chancellor <nathan@kernel.org> wrote:

> On Tue, May 12, 2026 at 10:02:07AM +0200, Andreas Kemnade wrote:
> > On Tue, 12 May 2026 16:34:42 +0900
> > Nathan Chancellor <nathan@kernel.org> wrote:
> >   
> > > On Tue, May 12, 2026 at 12:23:41AM -0400, Mithil Bavishi wrote:  
> > > > With CONFIG_CFI enabled, OMAP4 can trap in omap4_enter_lowpower()
> > > > because omap_pm_ops.finish_suspend points directly to the assembly
> > > > routine omap4_finish_suspend, which lacks the expected KCFI type
> > > > metadata.    
> > > 
> > > It sounds like omap4_finish_suspend() should be defined with
> > > SYM_TYPED_FUNC_START then? Is that the case for all of the other
> > > functions that are added to omap_pm_ops?
> > >   
> > omap_cpu_resume: the address is written to some cpu register and
> > on that way casted to u32. So therefore does not trigger CFI.
> > Same for secondary_startup which is also assembler code.
> > scu_prepare is C.
> > 
> > DO you have a pointer to any documentation:
> > :~/linux$ grep -R SYM_TYPED_FUNC_START Documentation/  
> 
> I don't think we have any formal documentation for SYM_TYPED_FUNC_START
> (it should probably be documented via kernel-doc?) but you can read the
> commit message of the change that added it for more information:
> 
>   e84e008e7b02 ("cfi: Add type helper macros")
> 
Ok, I found what is the missing piece of the puzzle in my head:
"
In order to make this easier, the compiler emits a
    __kcfi_typeid_<function> symbol for each address-taken function
    declaration in C, which contains the expected type identifier that
    we can refer to in assembly code.
"
So time to look into my backyard if anything more is there.

Regards,
Andreas


^ permalink raw reply

* [PATCH v4 0/6] Devicetree support for Glymur GPU
From: Akhil P Oommen @ 2026-05-12 19:21 UTC (permalink / raw)
  To: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Rob Clark, Sean Paul, Dmitry Baryshkov,
	Abhinav Kumar, Jessica Zhang, Marijn Suijten, David Airlie,
	Simona Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Will Deacon, Robin Murphy, Joerg Roedel
  Cc: linux-arm-msm, devicetree, linux-kernel, dri-devel, freedreno,
	linux-arm-kernel, iommu, Akhil P Oommen, Rajendra Nayak,
	Konrad Dybcio, Dmitry Baryshkov, Manaf Meethalavalappu Pallikunhi

This series adds the necessary Device Tree bits to enable GPU support
on the Glymur-based CRD devices. The Adreno X2-85 GPU present in Glymur
chipsets is based on the new Adreno A8x family of GPUs. It features a new
slice architecture with 4 slices, significantly higher bandwidth
throughput compared to mobile counterparts, raytracing support, and the
highest GPU Fmax seen so far on an Adreno GPU (1850 Mhz), among other
improvements.

This series includes patches that updates DT schema, add GPU SMMU &
GPU/GMU support. Keen-eyed readers may notice that the zap shader node
is missing. This is intentional: The Glymur-based laptop platforms
generally allow booting Linux at EL2 (yay!), which means the zap firmware
is not required here.

There is an update to the gxclkctl/drm drivers to properly support the IFPC
feature across all A8x GPUs. That series [1] is necessary to properly
support Glymur GPU:
[1] https://lore.kernel.org/lkml/20260427-gfx-clk-fixes-v2-0-797e54b3d464@oss.qualcomm.com/

Just FYI, on top of the linux-next, I had to pick below series [2] to boot
the device properly. But it is unrelated to GPU or this series:
[2] https://lore.kernel.org/all/20260331-qref_vote-v1-0-3fd7fbf87864@oss.qualcomm.com/

Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
---
Changes in v4:
- Add a new patch for passive cooling support
- Link to v3: https://lore.kernel.org/r/20260512-glymur-gpu-dt-v3-0-84232dc21c03@oss.qualcomm.com

Changes in v3:
- Add a new patch to fix RSCC base vaddr in drm-msm
- Remove interconnect property from adreno smmu dt and the binding doc
- Add a contrait in GPU binding doc to limit the reg entries for Glymur
  (Krzysztof)
- Link to v2: https://lore.kernel.org/r/20260501-glymur-gpu-dt-v2-0-2f128b5596bb@oss.qualcomm.com

Changes in v2:
- Keep GPU/GMU enabled by default and drop the enablement patch (Konrad)
- Drop zap shader node from DT
- A new patch to update GPU SMMU dt schema.
- Adjust reg range in dt nodes to avoid overlap. 
- Removed cx_dbgc range as it is already stable across chipsets. This
  region is now part of kgsl_3d0_reg_memory range.
- Link to v1: https://lore.kernel.org/r/20260405-glymur-gpu-dt-v1-0-2135eb11c562@oss.qualcomm.com

---
Akhil P Oommen (4):
      drm/msm/a8xx: Fix RSCC offset
      dt-bindings: display/msm: gpu: Document Adreno X2-185
      dt-bindings: arm-smmu: Update the description for Glymur GPU SMMU
      arm64: dts: qcom: Add GPU support for Glymur

Manaf Meethalavalappu Pallikunhi (1):
      arm64: dts: qcom: glymur: Add GPU cooling

Rajendra Nayak (1):
      arm64: dts: qcom: glymur: Add GPU smmu node

 .../devicetree/bindings/display/msm/gpu.yaml       |  17 +
 .../devicetree/bindings/iommu/arm,smmu.yaml        |   4 +-
 arch/arm64/boot/dts/qcom/glymur.dtsi               | 461 ++++++++++++++++++---
 drivers/gpu/drm/msm/adreno/a6xx_gmu.c              |   7 +-
 4 files changed, 431 insertions(+), 58 deletions(-)
---
base-commit: c9bd03db3e792a99e9789fde20e91898e3a29e8a
change-id: 20260226-glymur-gpu-dt-339e5092606b
prerequisite-message-id: <20260410-glymur_mmcc_dt_config_v2-v3-0-acce9d106e72@oss.qualcomm.com>
prerequisite-patch-id: f7ab29f2f0241b6536d3b0c0593f0baa0e435221
prerequisite-patch-id: 56c830b7718129323b006e492aed9822d7c30079

Best regards,
-- 
Akhil P Oommen <akhilpo@oss.qualcomm.com>



^ permalink raw reply

* [PATCH v4 1/6] drm/msm/a8xx: Fix RSCC offset
From: Akhil P Oommen @ 2026-05-12 19:21 UTC (permalink / raw)
  To: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Rob Clark, Sean Paul, Dmitry Baryshkov,
	Abhinav Kumar, Jessica Zhang, Marijn Suijten, David Airlie,
	Simona Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Will Deacon, Robin Murphy, Joerg Roedel
  Cc: linux-arm-msm, devicetree, linux-kernel, dri-devel, freedreno,
	linux-arm-kernel, iommu, Akhil P Oommen
In-Reply-To: <20260513-glymur-gpu-dt-v4-0-f83832c3bc9a@oss.qualcomm.com>

In A8xx, the RSCC block is part of GPU's register space. Update the
virtual base address of rscc to point to the correct address.

Fixes: 50e8a557d8d3 ("drm/msm/a8xx: Add support for A8x GMU")
Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
---
 drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
index 1b44b9e21ad8..cab4c46c6cf2 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
@@ -2357,7 +2357,12 @@ int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node)
 			goto err_mmio;
 		}
 	} else if (adreno_is_a8xx(adreno_gpu)) {
-		gmu->rscc = gmu->mmio + 0x19000;
+		/*
+		 * On a8xx , RSCC lives at GPU base + 0x50000, which falls
+		 * inside the GPU's kgsl_3d0_reg_memory range rather than the
+		 * GMU's.
+		 */
+		gmu->rscc = gpu->mmio + 0x50000;
 	} else {
 		gmu->rscc = gmu->mmio + 0x23000;
 	}

-- 
2.51.0



^ permalink raw reply related

* [PATCH v4 2/6] dt-bindings: display/msm: gpu: Document Adreno X2-185
From: Akhil P Oommen @ 2026-05-12 19:21 UTC (permalink / raw)
  To: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Rob Clark, Sean Paul, Dmitry Baryshkov,
	Abhinav Kumar, Jessica Zhang, Marijn Suijten, David Airlie,
	Simona Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Will Deacon, Robin Murphy, Joerg Roedel
  Cc: linux-arm-msm, devicetree, linux-kernel, dri-devel, freedreno,
	linux-arm-kernel, iommu, Akhil P Oommen
In-Reply-To: <20260513-glymur-gpu-dt-v4-0-f83832c3bc9a@oss.qualcomm.com>

Adreno X2-185 GPU found in Glymur chipsets belongs to the A8x family.
It features a new slice architecture with 4 slices, significantly higher
bandwidth throughput compared to mobile counterparts, raytracing support,
and the highest GPU Fmax seen so far on an Adreno GPU (1850 Mhz), among
other improvements. Update the dt bindings documentation to describe this
GPU.

Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
---
 Documentation/devicetree/bindings/display/msm/gpu.yaml | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/Documentation/devicetree/bindings/display/msm/gpu.yaml b/Documentation/devicetree/bindings/display/msm/gpu.yaml
index 04b2328903ca..e67cd708dda2 100644
--- a/Documentation/devicetree/bindings/display/msm/gpu.yaml
+++ b/Documentation/devicetree/bindings/display/msm/gpu.yaml
@@ -411,6 +411,22 @@ allOf:
         - clocks
         - clock-names
 
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: qcom,adreno-44070001
+    then:
+      properties:
+        reg:
+          minItems: 2
+          maxItems: 2
+
+        reg-names:
+          items:
+            - const: kgsl_3d0_reg_memory
+            - const: cx_mem
+
   - if:
       properties:
         compatible:
@@ -434,6 +450,7 @@ allOf:
               - qcom,adreno-43050a01
               - qcom,adreno-43050c01
               - qcom,adreno-43051401
+              - qcom,adreno-44070001
 
     then: # Starting with A6xx, the clocks are usually defined in the GMU node
       properties:

-- 
2.51.0



^ permalink raw reply related

* [PATCH v4 3/6] dt-bindings: arm-smmu: Update the description for Glymur GPU SMMU
From: Akhil P Oommen @ 2026-05-12 19:21 UTC (permalink / raw)
  To: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Rob Clark, Sean Paul, Dmitry Baryshkov,
	Abhinav Kumar, Jessica Zhang, Marijn Suijten, David Airlie,
	Simona Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Will Deacon, Robin Murphy, Joerg Roedel
  Cc: linux-arm-msm, devicetree, linux-kernel, dri-devel, freedreno,
	linux-arm-kernel, iommu, Akhil P Oommen
In-Reply-To: <20260513-glymur-gpu-dt-v4-0-f83832c3bc9a@oss.qualcomm.com>

Add the interconnects property to the common SMMU properties and extend
the sm8750 clock description section to also cover Glymur since it uses
the same single "hlos" vote clock.

Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
---
 Documentation/devicetree/bindings/iommu/arm,smmu.yaml | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.yaml b/Documentation/devicetree/bindings/iommu/arm,smmu.yaml
index 06fb5c8e7547..b811ece722c9 100644
--- a/Documentation/devicetree/bindings/iommu/arm,smmu.yaml
+++ b/Documentation/devicetree/bindings/iommu/arm,smmu.yaml
@@ -566,7 +566,9 @@ allOf:
       properties:
         compatible:
           items:
-            - const: qcom,sm8750-smmu-500
+            - enum:
+                - qcom,glymur-smmu-500
+                - qcom,sm8750-smmu-500
             - const: qcom,adreno-smmu
             - const: qcom,smmu-500
             - const: arm,mmu-500

-- 
2.51.0



^ permalink raw reply related

* [PATCH v4 4/6] arm64: dts: qcom: glymur: Add GPU smmu node
From: Akhil P Oommen @ 2026-05-12 19:21 UTC (permalink / raw)
  To: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Rob Clark, Sean Paul, Dmitry Baryshkov,
	Abhinav Kumar, Jessica Zhang, Marijn Suijten, David Airlie,
	Simona Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Will Deacon, Robin Murphy, Joerg Roedel
  Cc: linux-arm-msm, devicetree, linux-kernel, dri-devel, freedreno,
	linux-arm-kernel, iommu, Akhil P Oommen, Rajendra Nayak,
	Konrad Dybcio, Dmitry Baryshkov
In-Reply-To: <20260513-glymur-gpu-dt-v4-0-f83832c3bc9a@oss.qualcomm.com>

From: Rajendra Nayak <rajendra.nayak@oss.qualcomm.com>

Add the nodes to describe the GPU SMMU node.

Signed-off-by: Rajendra Nayak <rajendra.nayak@oss.qualcomm.com>
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
---
 arch/arm64/boot/dts/qcom/glymur.dtsi | 38 ++++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/glymur.dtsi b/arch/arm64/boot/dts/qcom/glymur.dtsi
index ed9aac42fcbf..5e76a0d53f01 100644
--- a/arch/arm64/boot/dts/qcom/glymur.dtsi
+++ b/arch/arm64/boot/dts/qcom/glymur.dtsi
@@ -3729,6 +3729,44 @@ gpucc: clock-controller@3d90000 {
 			#power-domain-cells = <1>;
 		};
 
+		adreno_smmu: iommu@3da0000 {
+			compatible = "qcom,glymur-smmu-500", "qcom,adreno-smmu",
+				     "qcom,smmu-500", "arm,mmu-500";
+			reg = <0x0 0x03da0000 0x0 0x40000>;
+			#iommu-cells = <2>;
+			#global-interrupts = <1>;
+			interrupts = <GIC_SPI 674 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 678 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 679 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 680 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 681 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 682 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 683 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 684 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 685 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 686 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 687 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 688 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 422 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 476 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 574 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 575 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 576 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 577 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 660 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 662 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 665 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 666 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 667 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 669 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 670 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 700 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&gpucc GPU_CC_GPU_SMMU_VOTE_CLK>;
+			clock-names = "hlos";
+			power-domains = <&gpucc GPU_CC_CX_GDSC>;
+			dma-coherent;
+		};
+
 		ipcc: mailbox@3e04000 {
 			compatible = "qcom,glymur-ipcc", "qcom,ipcc";
 			reg = <0x0 0x03e04000 0x0 0x1000>;

-- 
2.51.0



^ permalink raw reply related

* [PATCH v4 5/6] arm64: dts: qcom: Add GPU support for Glymur
From: Akhil P Oommen @ 2026-05-12 19:21 UTC (permalink / raw)
  To: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Rob Clark, Sean Paul, Dmitry Baryshkov,
	Abhinav Kumar, Jessica Zhang, Marijn Suijten, David Airlie,
	Simona Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Will Deacon, Robin Murphy, Joerg Roedel
  Cc: linux-arm-msm, devicetree, linux-kernel, dri-devel, freedreno,
	linux-arm-kernel, iommu, Akhil P Oommen, Konrad Dybcio
In-Reply-To: <20260513-glymur-gpu-dt-v4-0-f83832c3bc9a@oss.qualcomm.com>

The Adreno X2 series GPU present in Glymur SoC belongs to the A8x
family. It is a new HW IP with architectural improvements as well
as different set of hw configs like GMEM, num SPs, Caches sizes etc.

Add the GPU and GMU nodes to describe this hardware.

Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
---
 arch/arm64/boot/dts/qcom/glymur.dtsi | 183 +++++++++++++++++++++++++++++++++++
 1 file changed, 183 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/glymur.dtsi b/arch/arm64/boot/dts/qcom/glymur.dtsi
index 5e76a0d53f01..01a2e32e503b 100644
--- a/arch/arm64/boot/dts/qcom/glymur.dtsi
+++ b/arch/arm64/boot/dts/qcom/glymur.dtsi
@@ -3701,6 +3701,129 @@ hsc_noc: interconnect@2000000 {
 			#interconnect-cells = <2>;
 		};
 
+		gpu: gpu@3d00000 {
+			compatible = "qcom,adreno-44070001", "qcom,adreno";
+			reg = <0x0 0x03d00000 0x0 0x6c000>,
+			      <0x0 0x03d9e000 0x0 0x2000>;
+			reg-names = "kgsl_3d0_reg_memory",
+				    "cx_mem";
+
+			interrupts = <GIC_SPI 300 IRQ_TYPE_LEVEL_HIGH>;
+
+			iommus = <&adreno_smmu 0 0x0>,
+				 <&adreno_smmu 1 0x0>;
+
+			operating-points-v2 = <&gpu_opp_table>;
+
+			qcom,gmu = <&gmu>;
+			#cooling-cells = <2>;
+
+			interconnects = <&hsc_noc MASTER_GFX3D QCOM_ICC_TAG_ALWAYS
+					 &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>;
+			interconnect-names = "gfx-mem";
+
+			gpu_opp_table: opp-table {
+				compatible = "operating-points-v2-adreno",
+					     "operating-points-v2";
+
+				opp-310000000 {
+					opp-hz = /bits/ 64 <310000000>;
+					opp-level = <RPMH_REGULATOR_LEVEL_LOW_SVS_D1>;
+					opp-peak-kBps = <2136719>;
+					opp-supported-hw = <0xf>;
+					/* ACD is disabled */
+				};
+
+				opp-410000000 {
+					opp-hz = /bits/ 64 <410000000>;
+					opp-level = <RPMH_REGULATOR_LEVEL_LOW_SVS>;
+					opp-peak-kBps = <6074219>;
+					opp-supported-hw = <0xf>;
+					/* ACD is disabled */
+				};
+
+				opp-572000000 {
+					opp-hz = /bits/ 64 <572000000>;
+					opp-level = <RPMH_REGULATOR_LEVEL_SVS>;
+					opp-peak-kBps = <12449219>;
+					opp-supported-hw = <0xf>;
+					qcom,opp-acd-level = <0xe02d5ffd>;
+				};
+
+				opp-760000000 {
+					opp-hz = /bits/ 64 <760000000>;
+					opp-level = <RPMH_REGULATOR_LEVEL_SVS_L1>;
+					opp-peak-kBps = <12449219>;
+					opp-supported-hw = <0xf>;
+					qcom,opp-acd-level = <0xc0285ffd>;
+				};
+
+				opp-820000000 {
+					opp-hz = /bits/ 64 <820000000>;
+					opp-level = <RPMH_REGULATOR_LEVEL_SVS_L2>;
+					opp-peak-kBps = <16500000>;
+					opp-supported-hw = <0xf>;
+					qcom,opp-acd-level = <0xa82e5ffd>;
+				};
+
+				opp-915000000 {
+					opp-hz = /bits/ 64 <915000000>;
+					opp-level = <RPMH_REGULATOR_LEVEL_NOM>;
+					opp-peak-kBps = <16500000>;
+					opp-supported-hw = <0xf>;
+					qcom,opp-acd-level = <0x882d5ffd>;
+				};
+
+				opp-1070000000 {
+					opp-hz = /bits/ 64 <1070000000>;
+					opp-level = <RPMH_REGULATOR_LEVEL_NOM_L1>;
+					opp-peak-kBps = <16500000>;
+					opp-supported-hw = <0xf>;
+					qcom,opp-acd-level = <0x882b5ffd>;
+				};
+
+				opp-1185000000 {
+					opp-hz = /bits/ 64 <1185000000>;
+					opp-level = <RPMH_REGULATOR_LEVEL_TURBO>;
+					opp-peak-kBps = <16500000>;
+					opp-supported-hw = <0xf>;
+					qcom,opp-acd-level = <0x882a5ffd>;
+				};
+
+				opp-1350000000 {
+					opp-hz = /bits/ 64 <1350000000>;
+					opp-level = <RPMH_REGULATOR_LEVEL_TURBO_L1>;
+					opp-peak-kBps = <18597657>;
+					opp-supported-hw = <0xf>;
+					qcom,opp-acd-level = <0x882a5ffd>;
+				};
+
+				opp-1550000000 {
+					opp-hz = /bits/ 64 <1550000000>;
+					opp-level = <RPMH_REGULATOR_LEVEL_TURBO_L3>;
+					opp-peak-kBps = <18597657>;
+					opp-supported-hw = <0x7>;
+					qcom,opp-acd-level = <0xa8295ffd>;
+				};
+
+				opp-1700000000 {
+					opp-hz = /bits/ 64 <1700000000>;
+					opp-level = <RPMH_REGULATOR_LEVEL_TURBO_L4>;
+					opp-peak-kBps = <18597657>;
+					opp-supported-hw = <0x7>;
+					qcom,opp-acd-level = <0x88295ffd>;
+				};
+
+				opp-1850000000 {
+					opp-hz = /bits/ 64 <1850000000>;
+					opp-level = <RPMH_REGULATOR_LEVEL_TURBO_L5>;
+					opp-peak-kBps = <18597657>;
+					opp-supported-hw = <0x3>;
+					qcom,opp-acd-level = <0x88285ffd>;
+				};
+			};
+		};
+
 		gxclkctl: clock-controller@3d64000 {
 			compatible = "qcom,glymur-gxclkctl";
 			reg = <0x0 0x03d64000 0x0 0x6000>;
@@ -3712,6 +3835,66 @@ gxclkctl: clock-controller@3d64000 {
 			#power-domain-cells = <1>;
 		};
 
+		gmu: gmu@3d6c000 {
+			compatible = "qcom,adreno-gmu-x285.1", "qcom,adreno-gmu";
+
+			reg = <0x0 0x03d6c000 0x0 0x32000>;
+			reg-names = "gmu";
+
+			interrupts = <GIC_SPI 304 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "hfi",
+					  "gmu";
+
+			clocks = <&gpucc GPU_CC_AHB_CLK>,
+				 <&gpucc GPU_CC_CX_GMU_CLK>,
+				 <&gpucc GPU_CC_CXO_CLK>,
+				 <&gcc GCC_GPU_GEMNOC_GFX_CLK>,
+				 <&gpucc GPU_CC_HUB_CX_INT_CLK>,
+				 <&gpucc GPU_CC_RSCC_HUB_AON_CLK>;
+			clock-names = "ahb",
+				      "gmu",
+				      "cxo",
+				      "memnoc",
+				      "hub",
+				      "rscc";
+
+			power-domains = <&gpucc GPU_CC_CX_GDSC>,
+					<&gxclkctl GX_CLKCTL_GX_GDSC>;
+			power-domain-names = "cx",
+					     "gx";
+
+			iommus = <&adreno_smmu 5 0x0>;
+
+			qcom,qmp = <&aoss_qmp>;
+
+			operating-points-v2 = <&gmu_opp_table>;
+
+			gmu_opp_table: opp-table {
+				compatible = "operating-points-v2";
+
+				opp-575000000 {
+					opp-hz = /bits/ 64 <575000000>;
+					opp-level = <RPMH_REGULATOR_LEVEL_LOW_SVS>;
+				};
+
+				opp-700000000 {
+					opp-hz = /bits/ 64 <700000000>;
+					opp-level = <RPMH_REGULATOR_LEVEL_SVS>;
+				};
+
+				opp-725000000 {
+					opp-hz = /bits/ 64 <725000000>;
+					opp-level = <RPMH_REGULATOR_LEVEL_SVS_L1>;
+				};
+
+				opp-750000000 {
+					opp-hz = /bits/ 64 <750000000>;
+					opp-level = <RPMH_REGULATOR_LEVEL_NOM>;
+				};
+			};
+		};
+
 		gpucc: clock-controller@3d90000 {
 			compatible = "qcom,glymur-gpucc";
 			reg = <0x0 0x03d90000 0x0 0x9800>;

-- 
2.51.0



^ permalink raw reply related

* [PATCH v4 6/6] arm64: dts: qcom: glymur: Add GPU cooling
From: Akhil P Oommen @ 2026-05-12 19:21 UTC (permalink / raw)
  To: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Rob Clark, Sean Paul, Dmitry Baryshkov,
	Abhinav Kumar, Jessica Zhang, Marijn Suijten, David Airlie,
	Simona Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Will Deacon, Robin Murphy, Joerg Roedel
  Cc: linux-arm-msm, devicetree, linux-kernel, dri-devel, freedreno,
	linux-arm-kernel, iommu, Akhil P Oommen,
	Manaf Meethalavalappu Pallikunhi
In-Reply-To: <20260513-glymur-gpu-dt-v4-0-f83832c3bc9a@oss.qualcomm.com>

From: Manaf Meethalavalappu Pallikunhi <manaf.pallikunhi@oss.qualcomm.com>

The GPU does not throttle its speed automatically when it
reaches high temperatures. Set up GPU cooling by throttling
the GPU speed when it reaches 95°C.

Signed-off-by: Manaf Meethalavalappu Pallikunhi <manaf.pallikunhi@oss.qualcomm.com>
Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
---
 arch/arm64/boot/dts/qcom/glymur.dtsi | 240 +++++++++++++++++++++++++++--------
 1 file changed, 184 insertions(+), 56 deletions(-)

diff --git a/arch/arm64/boot/dts/qcom/glymur.dtsi b/arch/arm64/boot/dts/qcom/glymur.dtsi
index 01a2e32e503b..e109fb5b35a4 100644
--- a/arch/arm64/boot/dts/qcom/glymur.dtsi
+++ b/arch/arm64/boot/dts/qcom/glymur.dtsi
@@ -22,6 +22,7 @@
 #include <dt-bindings/regulator/qcom,rpmh-regulator.h>
 #include <dt-bindings/soc/qcom,rpmh-rsc.h>
 #include <dt-bindings/spmi/spmi.h>
+#include <dt-bindings/thermal/thermal.h>
 
 #include "glymur-ipcc.h"
 
@@ -7149,13 +7150,22 @@ aoss-7-critical {
 		};
 
 		thermal_gpu_0_0: gpu-0-0-thermal {
+			polling-delay-passive = <100>;
+
 			thermal-sensors = <&tsens7 1>;
 
+			cooling-maps {
+				map0 {
+					trip = <&gpu00_alert0>;
+					cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+				};
+			};
+
 			trips {
-				trip-point0 {
-					temperature = <90000>;
-					hysteresis = <5000>;
-					type = "hot";
+				gpu00_alert0: trip-point0 {
+					temperature = <95000>;
+					hysteresis = <1000>;
+					type = "passive";
 				};
 
 				gpu-0-0-critical {
@@ -7164,16 +7174,26 @@ gpu-0-0-critical {
 					type = "critical";
 				};
 			};
+
 		};
 
 		thermal_gpu_0_1: gpu-0-1-thermal {
+			polling-delay-passive = <100>;
+
 			thermal-sensors = <&tsens7 2>;
 
+			cooling-maps {
+				map0 {
+					trip = <&gpu01_alert0>;
+					cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+				};
+			};
+
 			trips {
-				trip-point0 {
-					temperature = <90000>;
-					hysteresis = <5000>;
-					type = "hot";
+				gpu01_alert0: trip-point0 {
+					temperature = <95000>;
+					hysteresis = <1000>;
+					type = "passive";
 				};
 
 				gpu-0-1-critical {
@@ -7185,13 +7205,22 @@ gpu-0-1-critical {
 		};
 
 		thermal_gpu_0_2: gpu-0-2-thermal {
+			polling-delay-passive = <100>;
+
 			thermal-sensors = <&tsens7 3>;
 
+			cooling-maps {
+				map0 {
+					trip = <&gpu02_alert0>;
+					cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+				};
+			};
+
 			trips {
-				trip-point0 {
-					temperature = <90000>;
-					hysteresis = <5000>;
-					type = "hot";
+				gpu02_alert0: trip-point0 {
+					temperature = <95000>;
+					hysteresis = <1000>;
+					type = "passive";
 				};
 
 				gpu-0-2-critical {
@@ -7203,13 +7232,22 @@ gpu-0-2-critical {
 		};
 
 		thermal_gpu_1_0: gpu-1-0-thermal {
+			polling-delay-passive = <100>;
+
 			thermal-sensors = <&tsens7 4>;
 
+			cooling-maps {
+				map0 {
+					trip = <&gpu10_alert0>;
+					cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+				};
+			};
+
 			trips {
-				trip-point0 {
-					temperature = <90000>;
-					hysteresis = <5000>;
-					type = "hot";
+				gpu10_alert0: trip-point0 {
+					temperature = <95000>;
+					hysteresis = <1000>;
+					type = "passive";
 				};
 
 				gpu-1-0-critical {
@@ -7221,13 +7259,22 @@ gpu-1-0-critical {
 		};
 
 		thermal_gpu_1_1: gpu-1-1-thermal {
+			polling-delay-passive = <100>;
+
 			thermal-sensors = <&tsens7 5>;
 
+			cooling-maps {
+				map0 {
+					trip = <&gpu11_alert0>;
+					cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+				};
+			};
+
 			trips {
-				trip-point0 {
-					temperature = <90000>;
-					hysteresis = <5000>;
-					type = "hot";
+				gpu11_alert0: trip-point0 {
+					temperature = <95000>;
+					hysteresis = <1000>;
+					type = "passive";
 				};
 
 				gpu-1-1-critical {
@@ -7239,13 +7286,22 @@ gpu-1-1-critical {
 		};
 
 		thermal_gpu_1_2: gpu-1-2-thermal {
+			polling-delay-passive = <100>;
+
 			thermal-sensors = <&tsens7 6>;
 
+			cooling-maps {
+				map0 {
+					trip = <&gpu12_alert0>;
+					cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+				};
+			};
+
 			trips {
-				trip-point0 {
-					temperature = <90000>;
-					hysteresis = <5000>;
-					type = "hot";
+				gpu12_alert0: trip-point0 {
+					temperature = <95000>;
+					hysteresis = <1000>;
+					type = "passive";
 				};
 
 				gpu-1-2-critical {
@@ -7257,13 +7313,22 @@ gpu-1-2-critical {
 		};
 
 		thermal_gpu_2_0: gpu-2-0-thermal {
+			polling-delay-passive = <100>;
+
 			thermal-sensors = <&tsens7 7>;
 
+			cooling-maps {
+				map0 {
+					trip = <&gpu20_alert0>;
+					cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+				};
+			};
+
 			trips {
-				trip-point0 {
-					temperature = <90000>;
-					hysteresis = <5000>;
-					type = "hot";
+				gpu20_alert0: trip-point0 {
+					temperature = <95000>;
+					hysteresis = <1000>;
+					type = "passive";
 				};
 
 				gpu-2-0-critical {
@@ -7275,13 +7340,22 @@ gpu-2-0-critical {
 		};
 
 		thermal_gpu_2_1: gpu-2-1-thermal {
+			polling-delay-passive = <100>;
+
 			thermal-sensors = <&tsens7 8>;
 
+			cooling-maps {
+				map0 {
+					trip = <&gpu21_alert0>;
+					cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+				};
+			};
+
 			trips {
-				trip-point0 {
-					temperature = <90000>;
-					hysteresis = <5000>;
-					type = "hot";
+				gpu21_alert0: trip-point0 {
+					temperature = <95000>;
+					hysteresis = <1000>;
+					type = "passive";
 				};
 
 				gpu-2-1-critical {
@@ -7293,13 +7367,22 @@ gpu-2-1-critical {
 		};
 
 		thermal_gpu_2_2: gpu-2-2-thermal {
+			polling-delay-passive = <100>;
+
 			thermal-sensors = <&tsens7 9>;
 
+			cooling-maps {
+				map0 {
+					trip = <&gpu22_alert0>;
+					cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+				};
+			};
+
 			trips {
-				trip-point0 {
-					temperature = <90000>;
-					hysteresis = <5000>;
-					type = "hot";
+				gpu22_alert0: trip-point0 {
+					temperature = <95000>;
+					hysteresis = <1000>;
+					type = "passive";
 				};
 
 				gpu-2-2-critical {
@@ -7311,13 +7394,22 @@ gpu-2-2-critical {
 		};
 
 		thermal_gpu_3_0: gpu-3-0-thermal {
+			polling-delay-passive = <100>;
+
 			thermal-sensors = <&tsens7 10>;
 
+			cooling-maps {
+				map0 {
+					trip = <&gpu30_alert0>;
+					cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+				};
+			};
+
 			trips {
-				trip-point0 {
-					temperature = <90000>;
-					hysteresis = <5000>;
-					type = "hot";
+				gpu30_alert0: trip-point0 {
+					temperature = <95000>;
+					hysteresis = <1000>;
+					type = "passive";
 				};
 
 				gpu-3-0-critical {
@@ -7329,13 +7421,22 @@ gpu-3-0-critical {
 		};
 
 		thermal_gpu_3_1: gpu-3-1-thermal {
+			polling-delay-passive = <100>;
+
 			thermal-sensors = <&tsens7 11>;
 
+			cooling-maps {
+				map0 {
+					trip = <&gpu31_alert0>;
+					cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+				};
+			};
+
 			trips {
-				trip-point0 {
-					temperature = <90000>;
-					hysteresis = <5000>;
-					type = "hot";
+				gpu31_alert0: trip-point0 {
+					temperature = <95000>;
+					hysteresis = <1000>;
+					type = "passive";
 				};
 
 				gpu-3-1-critical {
@@ -7347,13 +7448,22 @@ gpu-3-1-critical {
 		};
 
 		thermal_gpu_3_2: gpu-3-2-thermal {
+			polling-delay-passive = <100>;
+
 			thermal-sensors = <&tsens7 12>;
 
+			cooling-maps {
+				map0 {
+					trip = <&gpu32_alert0>;
+					cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+				};
+			};
+
 			trips {
-				trip-point0 {
-					temperature = <90000>;
-					hysteresis = <5000>;
-					type = "hot";
+				gpu32_alert0: trip-point0 {
+					temperature = <95000>;
+					hysteresis = <1000>;
+					type = "passive";
 				};
 
 				gpu-3-2-critical {
@@ -7365,13 +7475,22 @@ gpu-3-2-critical {
 		};
 
 		thermal_gpuss_0: gpuss-0-thermal {
+			polling-delay-passive = <100>;
+
 			thermal-sensors = <&tsens7 13>;
 
+			cooling-maps {
+				map0 {
+					trip = <&gpuss0_alert0>;
+					cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+				};
+			};
+
 			trips {
-				trip-point0 {
-					temperature = <90000>;
-					hysteresis = <5000>;
-					type = "hot";
+				gpuss0_alert0: trip-point0 {
+					temperature = <95000>;
+					hysteresis = <1000>;
+					type = "passive";
 				};
 
 				gpuss-0-critical {
@@ -7383,13 +7502,22 @@ gpuss-0-critical {
 		};
 
 		thermal_gpuss_1: gpuss-1-thermal {
+			polling-delay-passive = <100>;
+
 			thermal-sensors = <&tsens7 14>;
 
+			cooling-maps {
+				map0 {
+					trip = <&gpuss1_alert0>;
+					cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+				};
+			};
+
 			trips {
-				trip-point0 {
-					temperature = <90000>;
-					hysteresis = <5000>;
-					type = "hot";
+				gpuss1_alert0: trip-point0 {
+					temperature = <95000>;
+					hysteresis = <1000>;
+					type = "passive";
 				};
 
 				gpuss-1-critical {

-- 
2.51.0



^ permalink raw reply related

* Re: [PATCH v3] dt-bindings: iio: adc: Convert xilinx-xadc bindings to YAML schema
From: Rob Herring @ 2026-05-12 19:42 UTC (permalink / raw)
  To: David Lechner
  Cc: Jonathan Cameron, Pramod Maurya, Nuno Sá, Andy Shevchenko,
	Krzysztof Kozlowski, Conor Dooley, Michal Simek,
	Lars-Peter Clausen, linux-iio, devicetree, linux-arm-kernel,
	linux-kernel
In-Reply-To: <a4ecfb27-5ef4-4682-b87c-24917f81b4f0@baylibre.com>

On Tue, May 12, 2026 at 8:58 AM David Lechner <dlechner@baylibre.com> wrote:
>
> On 5/12/26 7:14 AM, Rob Herring wrote:
> > On Mon, May 11, 2026 at 11:24 AM David Lechner <dlechner@baylibre.com> wrote:
> >>
> >> On 5/11/26 11:15 AM, Jonathan Cameron wrote:
> >>> On Sun, 10 May 2026 08:01:36 -0400
> >>> Pramod Maurya <pramod.nexgen@gmail.com> wrote:
> >>>
> >>>> Convert the Xilinx XADC and UltraScale System Monitor device tree binding
> >>>> from the legacy plain-text format to a YAML schema, enabling automated
> >>>> validation with dt-schema.
> >>>>
> >>>> The new binding covers the same hardware and compatible strings:
> >>>>   - xlnx,zynq-xadc-1.00.a (ZYNQ hardmacro)
> >>>>   - xlnx,axi-xadc-1.00.a  (AXI softmacro)
> >>>>   - xlnx,system-management-wiz-1.3 (UltraScale System Management Wizard)
> >>>>
> >>>> Signed-off-by: Pramod Maurya <pramod.nexgen@gmail.com>
> >>> Hi Pramod,
> >>>
> >>> Something went wrong with your sending of v3. I have two versions sent
> >>> half a day apart and no idea how they are related.
> >>>
> >>> Anyhow one of them got feedback from Rob's bot so I'll assume we are
> >>> getting a v4 and wait for that.
> >>>
> >>> Jonathan
> >>
> >> I think Rob will have to fix the bot to make an exception for the
> >> legacy bindings. This should have been called out in the commit message
> >> as requested in a previous revision.
> >
> > The bot is not the problem. It just runs validation. The schemas will
> > have to either drop this check (comma's in nodenames) or exclude just
> > this property.
> >
> >
> > Rob
>
> Even though this is an existing text-based schema that has been around
> for 12 years with this name already? Changing it could be a breaking
> change to existing users. Although there aren't any in any .dts in the
> kernel source.

I'm absolutely not suggesting changing the node name.

The common schemas globally disallow commas in nodenames. We can relax
that and allow commas in any nodename. That check is largely from
QCom's amazingly consistent use of 'qcom' prefix in nodenames. We've
finally beat that practice out of them. So maybe it's not needed
anymore.

The other approach is to exclude this nodename and any other we have
to keep. I don't like dtschema having to know about some random name,
but we already have that in a few cases and I don't expect that list
to be too long given this is the first case we've seen.

Rob


^ permalink raw reply

* Re: [PATCH v3] dt-bindings: iio: adc: Convert xilinx-xadc bindings to YAML schema
From: David Lechner @ 2026-05-12 20:03 UTC (permalink / raw)
  To: Rob Herring, Pramod Maurya
  Cc: Jonathan Cameron, Nuno Sá, Andy Shevchenko,
	Krzysztof Kozlowski, Conor Dooley, Michal Simek,
	Lars-Peter Clausen, linux-iio, devicetree, linux-arm-kernel,
	linux-kernel
In-Reply-To: <CAL_JsqKP-C-rA6_19vtMzevVxQiD7bH=k5ObEZZDM3-Zmr_vtg@mail.gmail.com>

On 5/12/26 2:42 PM, Rob Herring wrote:
> On Tue, May 12, 2026 at 8:58 AM David Lechner <dlechner@baylibre.com> wrote:
>>
>> On 5/12/26 7:14 AM, Rob Herring wrote:
>>> On Mon, May 11, 2026 at 11:24 AM David Lechner <dlechner@baylibre.com> wrote:
>>>>
>>>> On 5/11/26 11:15 AM, Jonathan Cameron wrote:
>>>>> On Sun, 10 May 2026 08:01:36 -0400
>>>>> Pramod Maurya <pramod.nexgen@gmail.com> wrote:
>>>>>
>>>>>> Convert the Xilinx XADC and UltraScale System Monitor device tree binding
>>>>>> from the legacy plain-text format to a YAML schema, enabling automated
>>>>>> validation with dt-schema.
>>>>>>
>>>>>> The new binding covers the same hardware and compatible strings:
>>>>>>   - xlnx,zynq-xadc-1.00.a (ZYNQ hardmacro)
>>>>>>   - xlnx,axi-xadc-1.00.a  (AXI softmacro)
>>>>>>   - xlnx,system-management-wiz-1.3 (UltraScale System Management Wizard)
>>>>>>
>>>>>> Signed-off-by: Pramod Maurya <pramod.nexgen@gmail.com>
>>>>> Hi Pramod,
>>>>>
>>>>> Something went wrong with your sending of v3. I have two versions sent
>>>>> half a day apart and no idea how they are related.
>>>>>
>>>>> Anyhow one of them got feedback from Rob's bot so I'll assume we are
>>>>> getting a v4 and wait for that.
>>>>>
>>>>> Jonathan
>>>>
>>>> I think Rob will have to fix the bot to make an exception for the
>>>> legacy bindings. This should have been called out in the commit message
>>>> as requested in a previous revision.
>>>
>>> The bot is not the problem. It just runs validation. The schemas will
>>> have to either drop this check (comma's in nodenames) or exclude just
>>> this property.
>>>
>>>
>>> Rob
>>
>> Even though this is an existing text-based schema that has been around
>> for 12 years with this name already? Changing it could be a breaking
>> change to existing users. Although there aren't any in any .dts in the
>> kernel source.
> 
> I'm absolutely not suggesting changing the node name.
> 
> The common schemas globally disallow commas in nodenames. We can relax
> that and allow commas in any nodename. That check is largely from
> QCom's amazingly consistent use of 'qcom' prefix in nodenames. We've
> finally beat that practice out of them. So maybe it's not needed
> anymore.
> 
> The other approach is to exclude this nodename and any other we have
> to keep. I don't like dtschema having to know about some random name,
> but we already have that in a few cases and I don't expect that list
> to be too long given this is the first case we've seen.
> 
> Rob

Got it. So when I said "fix the bot" earlier, I should have said
"fix dtschema". We went through this before with adi,channels, but
I didn't remember exactly what you did.

I created a pull request for dt-schema [1] for this since it was
easier than trying to explain it for someone else to do.

[1]: https://github.com/devicetree-org/dt-schema/pull/195





^ permalink raw reply

* Re: [PATCH 1/1] dt-bindings: display: imx: add deprecated property 'port' and 'display-timings'
From: Conor Dooley @ 2026-05-12 20:25 UTC (permalink / raw)
  To: Frank Li
  Cc: Philipp Zabel, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam,
	open list:DRM DRIVERS FOR FREESCALE IMX 5/6,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	open list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
	open list
In-Reply-To: <agNvt9RbRFQ395uE@lizhi-Precision-Tower-5810>

[-- Attachment #1: Type: text/plain, Size: 2443 bytes --]

On Tue, May 12, 2026 at 02:21:43PM -0400, Frank Li wrote:
> On Tue, May 12, 2026 at 05:47:11PM +0100, Conor Dooley wrote:
> > On Mon, May 11, 2026 at 06:09:24PM -0400, Frank Li wrote:
> > > Add deprecated property 'port' and 'display-timings' for i.MX5 SoCs (over
> > > 15 years) to fix below CHECK_DTBS warnings:
> > >   arm/boot/dts/nxp/imx/imx51-apf51dev.dtb: disp1 (fsl,imx-parallel-display): 'display-timings', 'port' do not match any of the regexes: '^pinctrl-[0-9]+$'
> > >         from schema $id: http://devicetree.org/schemas/display/imx/fsl,imx-parallel-display.yaml
> >
> > Instead of documenting the deprecated properties, could this
> > device/devicetree be converted to non-deprecated properties?
> 
> Change dts will cause break back compatiblity. This is too old chips and

How would changing the dts impact backwards compatibility? That argument
doesn't make sense to me, I am of course not suggesting removing support
from these properties from the driver.

I do accept that the argument of lacking info on the panel.
Acked-by: Conor Dooley <conor.dooley@microchip.com>
pw-bot: not-applicable

> I have not information panel's detail information.
> 
> Frank
> 
> >
> > >
> > > Signed-off-by: Frank Li <Frank.Li@nxp.com>
> > > ---
> > >  .../display/imx/fsl,imx-parallel-display.yaml         | 11 +++++++++++
> > >  1 file changed, 11 insertions(+)
> > >
> > > diff --git a/Documentation/devicetree/bindings/display/imx/fsl,imx-parallel-display.yaml b/Documentation/devicetree/bindings/display/imx/fsl,imx-parallel-display.yaml
> > > index bbcfe7e2958b7..b0c5869771fae 100644
> > > --- a/Documentation/devicetree/bindings/display/imx/fsl,imx-parallel-display.yaml
> > > +++ b/Documentation/devicetree/bindings/display/imx/fsl,imx-parallel-display.yaml
> > > @@ -42,6 +42,17 @@ properties:
> > >      unevaluatedProperties: false
> > >      description: output port connected to a panel
> > >
> > > +  port:
> > > +    $ref: /schemas/graph.yaml#/properties/port
> > > +    unevaluatedProperties: false
> > > +    deprecated: true
> > > +    description: input port connected to the IPU display interface, see port@0
> > > +
> > > +  display-timings:
> > > +    $ref: /schemas/display/panel/display-timings.yaml#
> > > +    unevaluatedProperties: false
> > > +    deprecated: true
> > > +
> > >  required:
> > >    - compatible
> > >
> > > --
> > > 2.43.0
> > >
> 
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply

* Re: [PATCH net-next v6 02/12] net: airoha: Reserve RX headroom to avoid skb reallocation
From: Lorenzo Bianconi @ 2026-05-12 20:31 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: Christian Marangi, Benjamin Larsson, linux-arm-kernel,
	linux-mediatek, netdev, devicetree, Xuegang Lu
In-Reply-To: <20260511-airoha-eth-multi-serdes-v6-2-c899462c4f75@kernel.org>

[-- Attachment #1: Type: text/plain, Size: 3105 bytes --]

On May 11, Lorenzo Bianconi wrote:
> Reserve NET_SKB_PAD + NET_IP_ALIGN bytes of headroom for received packets
> to avoid skb head reallocation when pushing protocol headers into the skb.
> 
> Tested-by: Xuegang Lu <xuegang.lu@airoha.com>
> Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
> ---
>  drivers/net/ethernet/airoha/airoha_eth.c | 12 ++++++++----
>  drivers/net/ethernet/airoha/airoha_eth.h |  2 ++
>  2 files changed, 10 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
> index f71fb18197ec..3fe2561c85f1 100644
> --- a/drivers/net/ethernet/airoha/airoha_eth.c
> +++ b/drivers/net/ethernet/airoha/airoha_eth.c
> @@ -543,9 +543,10 @@ static int airoha_qdma_fill_rx_queue(struct airoha_queue *q)
>  		q->queued++;
>  		nframes++;
>  
> +		offset += AIROHA_RX_HEADROOM;
>  		e->buf = page_address(page) + offset;
>  		e->dma_addr = page_pool_get_dma_addr(page) + offset;
> -		e->dma_len = SKB_WITH_OVERHEAD(q->buf_size);
> +		e->dma_len = SKB_WITH_OVERHEAD(AIROHA_RX_LEN(q->buf_size));
>  
>  		val = FIELD_PREP(QDMA_DESC_LEN_MASK, e->dma_len);
>  		WRITE_ONCE(desc->ctrl, cpu_to_le32(val));
> @@ -616,8 +617,9 @@ static int airoha_qdma_rx_process(struct airoha_queue *q, int budget)
>  
>  		page = virt_to_head_page(e->buf);
>  		len = FIELD_GET(QDMA_DESC_LEN_MASK, desc_ctrl);
> -		data_len = q->skb ? q->buf_size
> -				  : SKB_WITH_OVERHEAD(q->buf_size);
> +		data_len = q->skb
> +			   ? AIROHA_RX_LEN(q->buf_size)
> +			   : SKB_WITH_OVERHEAD(AIROHA_RX_LEN(q->buf_size));
>  		if (!len || data_len < len)
>  			goto free_frag;
>  
> @@ -627,10 +629,12 @@ static int airoha_qdma_rx_process(struct airoha_queue *q, int budget)
>  
>  		port = eth->ports[p];
>  		if (!q->skb) { /* first buffer */
> -			q->skb = napi_build_skb(e->buf, q->buf_size);
> +			q->skb = napi_build_skb(e->buf - AIROHA_RX_HEADROOM,
> +						q->buf_size);
>  			if (!q->skb)
>  				goto free_frag;
>  
> +			skb_reserve(q->skb, AIROHA_RX_HEADROOM);
>  			__skb_put(q->skb, len);
>  			skb_mark_for_recycle(q->skb);
>  			q->skb->dev = port->dev;
> diff --git a/drivers/net/ethernet/airoha/airoha_eth.h b/drivers/net/ethernet/airoha/airoha_eth.h
> index 58530d096de7..d3781103abb5 100644
> --- a/drivers/net/ethernet/airoha/airoha_eth.h
> +++ b/drivers/net/ethernet/airoha/airoha_eth.h
> @@ -32,6 +32,8 @@
>  #define AIROHA_FE_MC_MAX_VLAN_TABLE	64
>  #define AIROHA_FE_MC_MAX_VLAN_PORT	16
>  #define AIROHA_NUM_TX_IRQ		2
> +#define AIROHA_RX_HEADROOM		(NET_SKB_PAD + NET_IP_ALIGN)
> +#define AIROHA_RX_LEN(_n)		((_n) - AIROHA_RX_HEADROOM)
>  #define HW_DSCP_NUM			2048
>  #define IRQ_QUEUE_LEN(_n)		((_n) ? 1024 : 2048)
>  #define TX_DSCP_NUM			1024
> 
> -- 
> 2.54.0
> 

commenting on sashiko's report:
https://sashiko.dev/#/patchset/20260511-airoha-eth-multi-serdes-v6-0-c899462c4f75%40kernel.org

- Does the length passed to dma_sync_single_for_cpu() also need to be updated
  to match the new DMA length?
  I will fix it in v7.

Regards,
Lorenzo

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply

* [PATCH] PCI: mvebu: Use fixed-width interrupt masks
From: Rosen Penev @ 2026-05-12 20:44 UTC (permalink / raw)
  To: linux-pci
  Cc: Thomas Petazzoni, Pali Rohár, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Manivannan Sadhasivam, Rob Herring,
	Bjorn Helgaas

Use u32-typed BIT and GENMASK helpers for PCIe interrupt register
masks.  This keeps inverted masks in the same width as the registers
and avoids truncation warnings on 64-bit compile-test builds.

Drop the unused sys_to_pcie() helper while touching the same area; it
references stale ARM pci_sys_data glue and has no callers.

Assisted-by: Codex:GPT-5.5
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
 drivers/pci/controller/pci-mvebu.c | 11 +++--------
 1 file changed, 3 insertions(+), 8 deletions(-)

diff --git a/drivers/pci/controller/pci-mvebu.c b/drivers/pci/controller/pci-mvebu.c
index e568528bad85..da43661792e8 100644
--- a/drivers/pci/controller/pci-mvebu.c
+++ b/drivers/pci/controller/pci-mvebu.c
@@ -57,9 +57,9 @@
 #define PCIE_CONF_DATA_OFF	0x18fc
 #define PCIE_INT_CAUSE_OFF	0x1900
 #define PCIE_INT_UNMASK_OFF	0x1910
-#define  PCIE_INT_INTX(i)		BIT(24+i)
-#define  PCIE_INT_PM_PME		BIT(28)
-#define  PCIE_INT_ALL_MASK		GENMASK(31, 0)
+#define  PCIE_INT_INTX(i)		BIT_U32(24 + (i))
+#define  PCIE_INT_PM_PME		BIT_U32(28)
+#define  PCIE_INT_ALL_MASK		GENMASK_U32(31, 0)
 #define PCIE_CTRL_OFF		0x1a00
 #define  PCIE_CTRL_X1_MODE		0x0001
 #define  PCIE_CTRL_RC_MODE		BIT(1)
@@ -950,11 +950,6 @@ static int mvebu_pci_bridge_emul_init(struct mvebu_pcie_port *port)
 	return pci_bridge_emul_init(bridge, bridge_flags);
 }
 
-static inline struct mvebu_pcie *sys_to_pcie(struct pci_sys_data *sys)
-{
-	return sys->private_data;
-}
-
 static struct mvebu_pcie_port *mvebu_pcie_find_port(struct mvebu_pcie *pcie,
 						    struct pci_bus *bus,
 						    int devfn)
-- 
2.54.0



^ permalink raw reply related

* Re: [PATCH v3] dt-bindings: iio: adc: Convert xilinx-xadc bindings to YAML schema
From: Rob Herring @ 2026-05-12 20:48 UTC (permalink / raw)
  To: David Lechner
  Cc: Pramod Maurya, Jonathan Cameron, Nuno Sá, Andy Shevchenko,
	Krzysztof Kozlowski, Conor Dooley, Michal Simek,
	Lars-Peter Clausen, linux-iio, devicetree, linux-arm-kernel,
	linux-kernel
In-Reply-To: <5a02550a-a578-4c0b-a8b0-2056f0248478@baylibre.com>

On Tue, May 12, 2026 at 3:03 PM David Lechner <dlechner@baylibre.com> wrote:
>
> On 5/12/26 2:42 PM, Rob Herring wrote:
> > On Tue, May 12, 2026 at 8:58 AM David Lechner <dlechner@baylibre.com> wrote:
> >>
> >> On 5/12/26 7:14 AM, Rob Herring wrote:
> >>> On Mon, May 11, 2026 at 11:24 AM David Lechner <dlechner@baylibre.com> wrote:
> >>>>
> >>>> On 5/11/26 11:15 AM, Jonathan Cameron wrote:
> >>>>> On Sun, 10 May 2026 08:01:36 -0400
> >>>>> Pramod Maurya <pramod.nexgen@gmail.com> wrote:
> >>>>>
> >>>>>> Convert the Xilinx XADC and UltraScale System Monitor device tree binding
> >>>>>> from the legacy plain-text format to a YAML schema, enabling automated
> >>>>>> validation with dt-schema.
> >>>>>>
> >>>>>> The new binding covers the same hardware and compatible strings:
> >>>>>>   - xlnx,zynq-xadc-1.00.a (ZYNQ hardmacro)
> >>>>>>   - xlnx,axi-xadc-1.00.a  (AXI softmacro)
> >>>>>>   - xlnx,system-management-wiz-1.3 (UltraScale System Management Wizard)
> >>>>>>
> >>>>>> Signed-off-by: Pramod Maurya <pramod.nexgen@gmail.com>
> >>>>> Hi Pramod,
> >>>>>
> >>>>> Something went wrong with your sending of v3. I have two versions sent
> >>>>> half a day apart and no idea how they are related.
> >>>>>
> >>>>> Anyhow one of them got feedback from Rob's bot so I'll assume we are
> >>>>> getting a v4 and wait for that.
> >>>>>
> >>>>> Jonathan
> >>>>
> >>>> I think Rob will have to fix the bot to make an exception for the
> >>>> legacy bindings. This should have been called out in the commit message
> >>>> as requested in a previous revision.
> >>>
> >>> The bot is not the problem. It just runs validation. The schemas will
> >>> have to either drop this check (comma's in nodenames) or exclude just
> >>> this property.
> >>>
> >>>
> >>> Rob
> >>
> >> Even though this is an existing text-based schema that has been around
> >> for 12 years with this name already? Changing it could be a breaking
> >> change to existing users. Although there aren't any in any .dts in the
> >> kernel source.
> >
> > I'm absolutely not suggesting changing the node name.
> >
> > The common schemas globally disallow commas in nodenames. We can relax
> > that and allow commas in any nodename. That check is largely from
> > QCom's amazingly consistent use of 'qcom' prefix in nodenames. We've
> > finally beat that practice out of them. So maybe it's not needed
> > anymore.
> >
> > The other approach is to exclude this nodename and any other we have
> > to keep. I don't like dtschema having to know about some random name,
> > but we already have that in a few cases and I don't expect that list
> > to be too long given this is the first case we've seen.
> >
> > Rob
>
> Got it. So when I said "fix the bot" earlier, I should have said
> "fix dtschema". We went through this before with adi,channels, but
> I didn't remember exactly what you did.

Completely forgot that. That makes picking which one easy...

> I created a pull request for dt-schema [1] for this since it was
> easier than trying to explain it for someone else to do.
>
> [1]: https://github.com/devicetree-org/dt-schema/pull/195

Thank you! Applied.

Rob


^ permalink raw reply

* Re: [PATCH net-next v6 11/12] net: airoha: Support multiple LAN/WAN interfaces for hw MAC address configuration
From: Lorenzo Bianconi @ 2026-05-12 20:58 UTC (permalink / raw)
  To: Benjamin Larsson
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Christian Marangi, linux-arm-kernel, linux-mediatek, netdev,
	devicetree, Madhur Agrawal
In-Reply-To: <f4a11830-8a3f-4cc3-ab82-e6f02ca34ae8@genexis.eu>

[-- Attachment #1: Type: text/plain, Size: 3464 bytes --]

On May 12, Benjamin Larsson wrote:
> Hi.
> 
> On 11/05/2026 12:49, Lorenzo Bianconi wrote:
> > The EN7581 and AN7583 SoCs provide registers to configure hardware LAN/WAN
> > MAC addresses, used to determine whether received traffic is destined for
> > this host or should be forwarded to another device.
> > The SoC hardware design assumes all interfaces configured as LAN (or WAN)
> > share a common upper MAC address, which is programmed into the
> > REG_FE_{LAN,WAN}_MAC_H register. The lower bytes of 'local' addresses can
> > be expressed as a range via the REG_FE_MAC_LMIN and REG_FE_MAC_LMAX
> > registers.
> > Previously, only a single interface was considered when programming these
> > registers. Extend the logic to derive the correct minimum and maximum
> > values for REG_FE_MAC_LMIN/REG_FE_MAC_LMAX when two or more interfaces are
> > configured as LAN or WAN.
> > 
> > Tested-by: Madhur Agrawal <madhur.agrawal@airoha.com>
> > Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
> > ---
> >   drivers/net/ethernet/airoha/airoha_eth.c | 75 +++++++++++++++++++++++++++-----
> >   drivers/net/ethernet/airoha/airoha_eth.h |  2 +-
> >   drivers/net/ethernet/airoha/airoha_ppe.c |  4 +-
> >   3 files changed, 66 insertions(+), 15 deletions(-)
> > 
> > diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
> > index 16c0ff9999da..533ffe20f833 100644
> > --- a/drivers/net/ethernet/airoha/airoha_eth.c
> > +++ b/drivers/net/ethernet/airoha/airoha_eth.c
> > @@ -71,20 +71,67 @@ static void airoha_qdma_irq_disable(struct airoha_irq_bank *irq_bank,
> >   	airoha_qdma_set_irqmask(irq_bank, index, mask, 0);
> >   }
> > -static void airoha_set_macaddr(struct airoha_gdm_dev *dev, const u8 *addr)
> > +static int airoha_set_macaddr(struct airoha_gdm_dev *dev, const u8 *addr)
> >   {
> >   	struct airoha_eth *eth = dev->eth;
> > -	u32 val, reg;
> > +	u8 ref_addr[ETH_ALEN] = {};
> > +	u32 reg, val, lmin, lmax;
> > +	int i;
> > +
> > +	lmin = (addr[3] << 16) | (addr[4] << 8) | addr[5];
> > +	lmax = lmin;
> > +
> > +	for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
> > +		struct airoha_gdm_port *port = eth->ports[i];
> > +		int j;
> > +
> > +		if (!port)
> > +			continue;
> > +
> > +		for (j = 0; j < ARRAY_SIZE(port->devs); j++) {
> > +			struct airoha_gdm_dev *iter_dev;
> > +			struct net_device *netdev;
> > +
> > +			iter_dev = port->devs[j];
> > +			if (!iter_dev || iter_dev == dev)
> > +				continue;
> > +
> > +			if (airoha_is_lan_gdm_dev(iter_dev) !=
> > +			    airoha_is_lan_gdm_dev(dev))
> > +				continue;
> > +
> > +			netdev = iter_dev->dev;
> > +			if (netdev->reg_state != NETREG_REGISTERED)
> > +				continue;
> > +
> > +			ether_addr_copy(ref_addr, netdev->dev_addr);
> > +			val = (netdev->dev_addr[3] << 16) |
> > +			      (netdev->dev_addr[4] << 8) | netdev->dev_addr[5];
> > +			if (val < lmin)
> > +				lmin = val;
> > +			if (val > lmax)
> > +				lmax = val;
> > +		}
> > +	}
> > +
> > +	if (!is_zero_ether_addr(ref_addr) && memcmp(ref_addr, addr, 3)) {
> > +		/* According to the HW design, hw mac address MS bits
> > +		 * must be the same for each net_device with the same
> > +		 * LAN/WAN configuration.
> > +		 */
> > +		return -EINVAL;
> > +	}
> 
> Maybe this information should be relayed to the user somehow?

netdev_err()?

Regards,
Lorenzo

> 
> MvH
> 
> Benjamin Larsson
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply

* Re: [GIT PULL] KVM/arm64 fixes for 7.1, take #2
From: Paolo Bonzini @ 2026-05-12 21:15 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Alexandru Elisei, Catalin Marinas, Fuad Tabba, James Morse,
	Lorenzo Pieralisi, Mark Rutland, Mostafa Saleh, Oliver Upton,
	Sebastian Ott, Steffen Eiden, Sudeep Holla, Vincent Donnefort,
	Wei-Lin Chang, Will Deacon, Yuan Yao, Joey Gouly,
	Suzuki K Poulose, Zenghui Yu, kvmarm, linux-arm-kernel, kvm
In-Reply-To: <20260507154221.2905554-1-maz@kernel.org>

On Thu, May 7, 2026 at 5:42 PM Marc Zyngier <maz@kernel.org> wrote:
>
> Paolo,
>
> Here's the second set of KVM/arm64 fixes for 7.1. Nothing too horrible
> this time, aside from an ARM erratum workaround that has little impact
> on KVM, but relies on some firmware dealing with the problem. Bleh.
>
> The rest is a small collection of bug fixes, mostly affecting the MMU
> (permission fault handling with guest_memfd, 52bit VA with NV), and a
> small set of AI-enhanced fixes from Fuad. I guess I'll have to get
> used to that.
>
> And last but not least, Steffen joins the merry band of KVM/arm64
> reviewers in preparation of s390 and arm64 being joined at the hip...
>
> Please pull,

Done, thanks.

Paolo

>
>         M.
>
> The following changes since commit 7fd2df204f342fc17d1a0bfcd474b24232fb0f32:
>
>   Linux 7.1-rc2 (2026-05-03 14:21:25 -0700)
>
> are available in the Git repository at:
>
>   git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm.git kvmarm-fixes-7.1-2
>
> for you to fetch changes up to effc0a39b8e0f30670fe24f51e44329d4324e566:
>
>   KVM: arm64: Pre-check vcpu memcache for host->guest donate (2026-05-07 14:12:42 +0100)
>
> ----------------------------------------------------------------
> KVM/arm64 fixes for 7.1, take #2
>
> - Add the pKVM side of the workaround for ARM's erratum 4193714, provided
>   that the EL3 firmware does its part of the job. KVM will refuse to
>   initialise otherwise.
>
> - Correctly handle 52bit VAs for guest EL2 stage-1 translations when
>   running under NV with E2H==0.
>
> - Correctly deal with permission faults in guest_memfd memslots.
>
> - Fix the steal-time selftest after the infrastructure was reworked.
>
> - Make sure the host cannot pass a non-sensical clock update to the
>   EL2 tracing infrastructure.
>
> - Appoint Steffen Eiden as a reviewer in anticipation of the KVM/s390
>   ability to run arm64 guests, which will inevitably lead to arm64
>   code being directly used on s390.
>
> - Make sure that EL2 is configured with both exception entry and exit
>   being Context Synchronization Events.
>
> - Handle the current vcpu being NULL on EL2 panic.
>
> - Fix the selftest_vcpu memcache being empty at the point of donation or
>   sharing.
>
> - Check that the memcache has enough capacity before engaging on the
>   share/donate path.
>
> - Fix __deactivate_fgt() to use its parameter rather than a variable
>   in the macro context.
>
> ----------------------------------------------------------------
> Alexandru Elisei (1):
>       KVM: arm64: Handle permission faults with guest_memfd
>
> Fuad Tabba (6):
>       KVM: arm64: Make EL2 exception entry and exit context-synchronization events
>       KVM: arm64: Guard against NULL vcpu on VHE hyp panic path
>       KVM: arm64: Fix __deactivate_fgt macro parameter typo
>       KVM: arm64: Seed pkvm_ownership_selftest vcpu memcache
>       KVM: arm64: Pre-check vcpu memcache for host->guest share
>       KVM: arm64: Pre-check vcpu memcache for host->guest donate
>
> James Morse (1):
>       KVM: arm64: Work around C1-Pro erratum 4193714 for protected guests
>
> Mostafa Saleh (1):
>       KVM: arm64: Remove potential UB on nvhe tracing clock update
>
> Sebastian Ott (1):
>       KVM: selftests: arm64: Fix steal_time test after UAPI refactoring
>
> Steffen Eiden (1):
>       MAINTAINERS: Add Steffen as reviewer for KVM/arm64
>
> Wei-Lin Chang (1):
>       KVM: arm64: nv: Consider the DS bit when translating TCR_EL2
>
>  MAINTAINERS                              |  1 +
>  arch/arm64/include/asm/kvm_nested.h      |  1 +
>  arch/arm64/include/asm/sysreg.h          |  2 +-
>  arch/arm64/kvm/arm.c                     | 21 ++++++++++++++
>  arch/arm64/kvm/hyp/include/hyp/switch.h  |  2 +-
>  arch/arm64/kvm/hyp/nvhe/clock.c          |  3 ++
>  arch/arm64/kvm/hyp/nvhe/mem_protect.c    | 47 +++++++++++++++++++++++++++++++-
>  arch/arm64/kvm/hyp/nvhe/pkvm.c           | 16 ++++++++++-
>  arch/arm64/kvm/hyp/vhe/switch.c          |  3 +-
>  arch/arm64/kvm/mmu.c                     | 29 ++++++++++++++------
>  include/linux/arm-smccc.h                |  6 ++++
>  tools/testing/selftests/kvm/steal_time.c |  2 ++
>  12 files changed, 120 insertions(+), 13 deletions(-)
>



^ permalink raw reply

* Re: [PATCH net-next v6 03/12] net: airoha: Introduce airoha_gdm_dev struct
From: Lorenzo Bianconi @ 2026-05-12 20:55 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: Christian Marangi, Benjamin Larsson, linux-arm-kernel,
	linux-mediatek, netdev, devicetree, Xuegang Lu
In-Reply-To: <20260511-airoha-eth-multi-serdes-v6-3-c899462c4f75@kernel.org>

[-- Attachment #1: Type: text/plain, Size: 31080 bytes --]

On May 11, Lorenzo Bianconi wrote:
> EN7581 and AN7583 SoCs support connecting multiple external SerDes to GDM3
> or GDM4 ports via a hw arbiter that manages the traffic in a TDM manner.
> As a result multiple net_devices can connect to the same GDM{3,4} port
> and there is a theoretical "1:n" relation between GDM port and
> net_devices.
> Introduce airoha_gdm_dev struct to collect net_device related info (e.g.
> net_device and external phy pointer). Please note this is just a
> preliminary patch and we are still supporting a single net_device for
> each GDM port. Subsequent patches will add support for multiple net_devices
> connected to the same GDM port.
> 
> Tested-by: Xuegang Lu <xuegang.lu@airoha.com>
> Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
> ---
>  drivers/net/ethernet/airoha/airoha_eth.c | 309 ++++++++++++++++++-------------
>  drivers/net/ethernet/airoha/airoha_eth.h |  13 +-
>  drivers/net/ethernet/airoha/airoha_ppe.c |  17 +-
>  3 files changed, 203 insertions(+), 136 deletions(-)
> 
> diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
> index 3fe2561c85f1..18a89de4d58a 100644
> --- a/drivers/net/ethernet/airoha/airoha_eth.c
> +++ b/drivers/net/ethernet/airoha/airoha_eth.c
> @@ -600,6 +600,7 @@ static int airoha_qdma_rx_process(struct airoha_queue *q, int budget)
>  		struct airoha_qdma_desc *desc = &q->desc[q->tail];
>  		u32 hash, reason, msg1, desc_ctrl;
>  		struct airoha_gdm_port *port;
> +		struct net_device *netdev;
>  		int data_len, len, p;
>  		struct page *page;
>  
> @@ -628,6 +629,7 @@ static int airoha_qdma_rx_process(struct airoha_queue *q, int budget)
>  			goto free_frag;
>  
>  		port = eth->ports[p];
> +		netdev = port->dev->dev;
>  		if (!q->skb) { /* first buffer */
>  			q->skb = napi_build_skb(e->buf - AIROHA_RX_HEADROOM,
>  						q->buf_size);
> @@ -637,8 +639,8 @@ static int airoha_qdma_rx_process(struct airoha_queue *q, int budget)
>  			skb_reserve(q->skb, AIROHA_RX_HEADROOM);
>  			__skb_put(q->skb, len);
>  			skb_mark_for_recycle(q->skb);
> -			q->skb->dev = port->dev;
> -			q->skb->protocol = eth_type_trans(q->skb, port->dev);
> +			q->skb->dev = netdev;
> +			q->skb->protocol = eth_type_trans(q->skb, netdev);
>  			q->skb->ip_summed = CHECKSUM_UNNECESSARY;
>  			skb_record_rx_queue(q->skb, qid);
>  		} else { /* scattered frame */
> @@ -656,7 +658,7 @@ static int airoha_qdma_rx_process(struct airoha_queue *q, int budget)
>  		if (FIELD_GET(QDMA_DESC_MORE_MASK, desc_ctrl))
>  			continue;
>  
> -		if (netdev_uses_dsa(port->dev)) {
> +		if (netdev_uses_dsa(netdev)) {
>  			/* PPE module requires untagged packets to work
>  			 * properly and it provides DSA port index via the
>  			 * DMA descriptor. Report DSA tag to the DSA stack
> @@ -850,6 +852,7 @@ static void airoha_qdma_wake_netdev_txqs(struct airoha_queue *q)
>  
>  	for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
>  		struct airoha_gdm_port *port = eth->ports[i];
> +		struct airoha_gdm_dev *dev;
>  		int j;
>  
>  		if (!port)
> @@ -858,11 +861,12 @@ static void airoha_qdma_wake_netdev_txqs(struct airoha_queue *q)
>  		if (port->qdma != qdma)
>  			continue;
>  
> -		for (j = 0; j < port->dev->num_tx_queues; j++) {
> +		dev = port->dev;
> +		for (j = 0; j < dev->dev->num_tx_queues; j++) {
>  			if (airoha_qdma_get_txq(qdma, j) != qid)
>  				continue;
>  
> -			netif_wake_subqueue(port->dev, j);
> +			netif_wake_subqueue(dev->dev, j);
>  		}
>  	}
>  	q->txq_stopped = false;
> @@ -1702,19 +1706,20 @@ static void airoha_update_hw_stats(struct airoha_gdm_port *port)
>  	spin_unlock(&port->stats.lock);
>  }
>  
> -static int airoha_dev_open(struct net_device *dev)
> +static int airoha_dev_open(struct net_device *netdev)
>  {
> -	int err, len = ETH_HLEN + dev->mtu + ETH_FCS_LEN;
> -	struct airoha_gdm_port *port = netdev_priv(dev);
> +	int err, len = ETH_HLEN + netdev->mtu + ETH_FCS_LEN;
> +	struct airoha_gdm_dev *dev = netdev_priv(netdev);
> +	struct airoha_gdm_port *port = dev->port;
>  	struct airoha_qdma *qdma = port->qdma;
>  	u32 pse_port = FE_PSE_PORT_PPE1;
>  
> -	netif_tx_start_all_queues(dev);
> +	netif_tx_start_all_queues(netdev);
>  	err = airoha_set_vip_for_gdm_port(port, true);
>  	if (err)
>  		return err;
>  
> -	if (netdev_uses_dsa(dev))
> +	if (netdev_uses_dsa(netdev))
>  		airoha_fe_set(qdma->eth, REG_GDM_INGRESS_CFG(port->id),
>  			      GDM_STAG_EN_MASK);
>  	else
> @@ -1742,16 +1747,17 @@ static int airoha_dev_open(struct net_device *dev)
>  	return 0;
>  }
>  
> -static int airoha_dev_stop(struct net_device *dev)
> +static int airoha_dev_stop(struct net_device *netdev)
>  {
> -	struct airoha_gdm_port *port = netdev_priv(dev);
> +	struct airoha_gdm_dev *dev = netdev_priv(netdev);
> +	struct airoha_gdm_port *port = dev->port;
>  	struct airoha_qdma *qdma = port->qdma;
>  	int i;
>  
> -	netif_tx_disable(dev);
> +	netif_tx_disable(netdev);
>  	airoha_set_vip_for_gdm_port(port, false);
> -	for (i = 0; i < dev->num_tx_queues; i++)
> -		netdev_tx_reset_subqueue(dev, i);
> +	for (i = 0; i < netdev->num_tx_queues; i++)
> +		netdev_tx_reset_subqueue(netdev, i);
>  
>  	airoha_set_gdm_port_fwd_cfg(qdma->eth, REG_GDM_FWD_CFG(port->id),
>  				    FE_PSE_PORT_DROP);
> @@ -1772,16 +1778,17 @@ static int airoha_dev_stop(struct net_device *dev)
>  	return 0;
>  }
>  
> -static int airoha_dev_set_macaddr(struct net_device *dev, void *p)
> +static int airoha_dev_set_macaddr(struct net_device *netdev, void *p)
>  {
> -	struct airoha_gdm_port *port = netdev_priv(dev);
> +	struct airoha_gdm_dev *dev = netdev_priv(netdev);
> +	struct airoha_gdm_port *port = dev->port;
>  	int err;
>  
> -	err = eth_mac_addr(dev, p);
> +	err = eth_mac_addr(netdev, p);
>  	if (err)
>  		return err;
>  
> -	airoha_set_macaddr(port, dev->dev_addr);
> +	airoha_set_macaddr(port, netdev->dev_addr);
>  
>  	return 0;
>  }
> @@ -1845,16 +1852,17 @@ static int airoha_set_gdm2_loopback(struct airoha_gdm_port *port)
>  	return 0;
>  }
>  
> -static int airoha_dev_init(struct net_device *dev)
> +static int airoha_dev_init(struct net_device *netdev)
>  {
> -	struct airoha_gdm_port *port = netdev_priv(dev);
> -	struct airoha_eth *eth = port->eth;
> +	struct airoha_gdm_dev *dev = netdev_priv(netdev);
> +	struct airoha_gdm_port *port = dev->port;
> +	struct airoha_eth *eth = dev->eth;
>  	int i;
>  
>  	/* QDMA0 is used for lan ports while QDMA1 is used for WAN ports */
>  	port->qdma = &eth->qdma[!airoha_is_lan_gdm_port(port)];
> -	port->dev->irq = port->qdma->irq_banks[0].irq;
> -	airoha_set_macaddr(port, dev->dev_addr);
> +	dev->dev->irq = port->qdma->irq_banks[0].irq;
> +	airoha_set_macaddr(port, netdev->dev_addr);
>  
>  	switch (port->id) {
>  	case AIROHA_GDM3_IDX:
> @@ -1879,10 +1887,11 @@ static int airoha_dev_init(struct net_device *dev)
>  	return 0;
>  }
>  
> -static void airoha_dev_get_stats64(struct net_device *dev,
> +static void airoha_dev_get_stats64(struct net_device *netdev,
>  				   struct rtnl_link_stats64 *storage)
>  {
> -	struct airoha_gdm_port *port = netdev_priv(dev);
> +	struct airoha_gdm_dev *dev = netdev_priv(netdev);
> +	struct airoha_gdm_port *port = dev->port;
>  	unsigned int start;
>  
>  	airoha_update_hw_stats(port);
> @@ -1901,36 +1910,39 @@ static void airoha_dev_get_stats64(struct net_device *dev,
>  	} while (u64_stats_fetch_retry(&port->stats.syncp, start));
>  }
>  
> -static int airoha_dev_change_mtu(struct net_device *dev, int mtu)
> +static int airoha_dev_change_mtu(struct net_device *netdev, int mtu)
>  {
> -	struct airoha_gdm_port *port = netdev_priv(dev);
> +	struct airoha_gdm_dev *dev = netdev_priv(netdev);
> +	struct airoha_gdm_port *port = dev->port;
>  	struct airoha_eth *eth = port->qdma->eth;
>  	u32 len = ETH_HLEN + mtu + ETH_FCS_LEN;
>  
>  	airoha_fe_rmw(eth, REG_GDM_LEN_CFG(port->id),
>  		      GDM_LONG_LEN_MASK,
>  		      FIELD_PREP(GDM_LONG_LEN_MASK, len));
> -	WRITE_ONCE(dev->mtu, mtu);
> +	WRITE_ONCE(netdev->mtu, mtu);
>  
>  	return 0;
>  }
>  
> -static u16 airoha_dev_select_queue(struct net_device *dev, struct sk_buff *skb,
> +static u16 airoha_dev_select_queue(struct net_device *netdev,
> +				   struct sk_buff *skb,
>  				   struct net_device *sb_dev)
>  {
> -	struct airoha_gdm_port *port = netdev_priv(dev);
> +	struct airoha_gdm_dev *dev = netdev_priv(netdev);
> +	struct airoha_gdm_port *port = dev->port;
>  	int queue, channel;
>  
>  	/* For dsa device select QoS channel according to the dsa user port
>  	 * index, rely on port id otherwise. Select QoS queue based on the
>  	 * skb priority.
>  	 */
> -	channel = netdev_uses_dsa(dev) ? skb_get_queue_mapping(skb) : port->id;
> +	channel = netdev_uses_dsa(netdev) ? skb_get_queue_mapping(skb) : port->id;
>  	channel = channel % AIROHA_NUM_QOS_CHANNELS;
>  	queue = (skb->priority - 1) % AIROHA_NUM_QOS_QUEUES; /* QoS queue */
>  	queue = channel * AIROHA_NUM_QOS_QUEUES + queue;
>  
> -	return queue < dev->num_tx_queues ? queue : 0;
> +	return queue < netdev->num_tx_queues ? queue : 0;
>  }
>  
>  static u32 airoha_get_dsa_tag(struct sk_buff *skb, struct net_device *dev)
> @@ -1994,9 +2006,10 @@ int airoha_get_fe_port(struct airoha_gdm_port *port)
>  }
>  
>  static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
> -				   struct net_device *dev)
> +				   struct net_device *netdev)
>  {
> -	struct airoha_gdm_port *port = netdev_priv(dev);
> +	struct airoha_gdm_dev *dev = netdev_priv(netdev);
> +	struct airoha_gdm_port *port = dev->port;
>  	struct airoha_qdma *qdma = port->qdma;
>  	u32 nr_frags, tag, msg0, msg1, len;
>  	struct airoha_queue_entry *e;
> @@ -2009,7 +2022,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
>  	u8 fport;
>  
>  	qid = airoha_qdma_get_txq(qdma, skb_get_queue_mapping(skb));
> -	tag = airoha_get_dsa_tag(skb, dev);
> +	tag = airoha_get_dsa_tag(skb, netdev);
>  
>  	msg0 = FIELD_PREP(QDMA_ETH_TXMSG_CHAN_MASK,
>  			  qid / AIROHA_NUM_QOS_QUEUES) |
> @@ -2045,7 +2058,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
>  
>  	spin_lock_bh(&q->lock);
>  
> -	txq = skb_get_tx_queue(dev, skb);
> +	txq = skb_get_tx_queue(netdev, skb);
>  	nr_frags = 1 + skb_shinfo(skb)->nr_frags;
>  
>  	if (q->queued + nr_frags >= q->ndesc) {
> @@ -2069,9 +2082,9 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
>  		dma_addr_t addr;
>  		u32 val;
>  
> -		addr = dma_map_single(dev->dev.parent, data, len,
> +		addr = dma_map_single(netdev->dev.parent, data, len,
>  				      DMA_TO_DEVICE);
> -		if (unlikely(dma_mapping_error(dev->dev.parent, addr)))
> +		if (unlikely(dma_mapping_error(netdev->dev.parent, addr)))
>  			goto error_unmap;
>  
>  		list_move_tail(&e->list, &tx_list);
> @@ -2120,7 +2133,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
>  
>  error_unmap:
>  	list_for_each_entry(e, &tx_list, list) {
> -		dma_unmap_single(dev->dev.parent, e->dma_addr, e->dma_len,
> +		dma_unmap_single(netdev->dev.parent, e->dma_addr, e->dma_len,
>  				 DMA_TO_DEVICE);
>  		e->dma_addr = 0;
>  	}
> @@ -2129,25 +2142,27 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
>  	spin_unlock_bh(&q->lock);
>  error:
>  	dev_kfree_skb_any(skb);
> -	dev->stats.tx_dropped++;
> +	netdev->stats.tx_dropped++;
>  
>  	return NETDEV_TX_OK;
>  }
>  
> -static void airoha_ethtool_get_drvinfo(struct net_device *dev,
> +static void airoha_ethtool_get_drvinfo(struct net_device *netdev,
>  				       struct ethtool_drvinfo *info)
>  {
> -	struct airoha_gdm_port *port = netdev_priv(dev);
> +	struct airoha_gdm_dev *dev = netdev_priv(netdev);
> +	struct airoha_gdm_port *port = dev->port;
>  	struct airoha_eth *eth = port->qdma->eth;
>  
>  	strscpy(info->driver, eth->dev->driver->name, sizeof(info->driver));
>  	strscpy(info->bus_info, dev_name(eth->dev), sizeof(info->bus_info));
>  }
>  
> -static void airoha_ethtool_get_mac_stats(struct net_device *dev,
> +static void airoha_ethtool_get_mac_stats(struct net_device *netdev,
>  					 struct ethtool_eth_mac_stats *stats)
>  {
> -	struct airoha_gdm_port *port = netdev_priv(dev);
> +	struct airoha_gdm_dev *dev = netdev_priv(netdev);
> +	struct airoha_gdm_port *port = dev->port;
>  	unsigned int start;
>  
>  	airoha_update_hw_stats(port);
> @@ -2175,11 +2190,12 @@ static const struct ethtool_rmon_hist_range airoha_ethtool_rmon_ranges[] = {
>  };
>  
>  static void
> -airoha_ethtool_get_rmon_stats(struct net_device *dev,
> +airoha_ethtool_get_rmon_stats(struct net_device *netdev,
>  			      struct ethtool_rmon_stats *stats,
>  			      const struct ethtool_rmon_hist_range **ranges)
>  {
> -	struct airoha_gdm_port *port = netdev_priv(dev);
> +	struct airoha_gdm_dev *dev = netdev_priv(netdev);
> +	struct airoha_gdm_port *port = dev->port;
>  	struct airoha_hw_stats *hw_stats = &port->stats;
>  	unsigned int start;
>  
> @@ -2204,11 +2220,12 @@ airoha_ethtool_get_rmon_stats(struct net_device *dev,
>  	} while (u64_stats_fetch_retry(&port->stats.syncp, start));
>  }
>  
> -static int airoha_qdma_set_chan_tx_sched(struct net_device *dev,
> +static int airoha_qdma_set_chan_tx_sched(struct net_device *netdev,
>  					 int channel, enum tx_sched_mode mode,
>  					 const u16 *weights, u8 n_weights)
>  {
> -	struct airoha_gdm_port *port = netdev_priv(dev);
> +	struct airoha_gdm_dev *dev = netdev_priv(netdev);
> +	struct airoha_gdm_port *port = dev->port;
>  	int i;
>  
>  	for (i = 0; i < AIROHA_NUM_TX_RING; i++)
> @@ -2293,10 +2310,12 @@ static int airoha_qdma_set_tx_ets_sched(struct net_device *dev, int channel,
>  					     ARRAY_SIZE(w));
>  }
>  
> -static int airoha_qdma_get_tx_ets_stats(struct net_device *dev, int channel,
> +static int airoha_qdma_get_tx_ets_stats(struct net_device *netdev, int channel,
>  					struct tc_ets_qopt_offload *opt)
>  {
> -	struct airoha_gdm_port *port = netdev_priv(dev);
> +	struct airoha_gdm_dev *dev = netdev_priv(netdev);
> +	struct airoha_gdm_port *port = dev->port;
> +
>  	u64 cpu_tx_packets = airoha_qdma_rr(port->qdma,
>  					    REG_CNTR_VAL(channel << 1));
>  	u64 fwd_tx_packets = airoha_qdma_rr(port->qdma,
> @@ -2558,11 +2577,12 @@ static int airoha_qdma_set_trtcm_token_bucket(struct airoha_qdma *qdma,
>  					   mode, val);
>  }
>  
> -static int airoha_qdma_set_tx_rate_limit(struct net_device *dev,
> +static int airoha_qdma_set_tx_rate_limit(struct net_device *netdev,
>  					 int channel, u32 rate,
>  					 u32 bucket_size)
>  {
> -	struct airoha_gdm_port *port = netdev_priv(dev);
> +	struct airoha_gdm_dev *dev = netdev_priv(netdev);
> +	struct airoha_gdm_port *port = dev->port;
>  	int i, err;
>  
>  	for (i = 0; i <= TRTCM_PEAK_MODE; i++) {
> @@ -2582,20 +2602,22 @@ static int airoha_qdma_set_tx_rate_limit(struct net_device *dev,
>  	return 0;
>  }
>  
> -static int airoha_tc_htb_alloc_leaf_queue(struct net_device *dev,
> +static int airoha_tc_htb_alloc_leaf_queue(struct net_device *netdev,
>  					  struct tc_htb_qopt_offload *opt)
>  {
>  	u32 channel = TC_H_MIN(opt->classid) % AIROHA_NUM_QOS_CHANNELS;
>  	u32 rate = div_u64(opt->rate, 1000) << 3; /* kbps */
> -	int err, num_tx_queues = dev->real_num_tx_queues;
> -	struct airoha_gdm_port *port = netdev_priv(dev);
> +	int err, num_tx_queues = netdev->real_num_tx_queues;
> +	struct airoha_gdm_dev *dev = netdev_priv(netdev);
> +	struct airoha_gdm_port *port = dev->port;
>  
>  	if (opt->parent_classid != TC_HTB_CLASSID_ROOT) {
>  		NL_SET_ERR_MSG_MOD(opt->extack, "invalid parent classid");
>  		return -EINVAL;
>  	}
>  
> -	err = airoha_qdma_set_tx_rate_limit(dev, channel, rate, opt->quantum);
> +	err = airoha_qdma_set_tx_rate_limit(netdev, channel, rate,
> +					    opt->quantum);
>  	if (err) {
>  		NL_SET_ERR_MSG_MOD(opt->extack,
>  				   "failed configuring htb offload");
> @@ -2605,9 +2627,10 @@ static int airoha_tc_htb_alloc_leaf_queue(struct net_device *dev,
>  	if (opt->command == TC_HTB_NODE_MODIFY)
>  		return 0;
>  
> -	err = netif_set_real_num_tx_queues(dev, num_tx_queues + 1);
> +	err = netif_set_real_num_tx_queues(netdev, num_tx_queues + 1);
>  	if (err) {
> -		airoha_qdma_set_tx_rate_limit(dev, channel, 0, opt->quantum);
> +		airoha_qdma_set_tx_rate_limit(netdev, channel, 0,
> +					      opt->quantum);
>  		NL_SET_ERR_MSG_MOD(opt->extack,
>  				   "failed setting real_num_tx_queues");
>  		return err;
> @@ -2697,11 +2720,12 @@ static int airoha_tc_matchall_act_validate(struct tc_cls_matchall_offload *f)
>  	return 0;
>  }
>  
> -static int airoha_dev_tc_matchall(struct net_device *dev,
> +static int airoha_dev_tc_matchall(struct net_device *netdev,
>  				  struct tc_cls_matchall_offload *f)
>  {
>  	enum trtcm_unit_type unit_type = TRTCM_BYTE_UNIT;
> -	struct airoha_gdm_port *port = netdev_priv(dev);
> +	struct airoha_gdm_dev *dev = netdev_priv(netdev);
> +	struct airoha_gdm_port *port = dev->port;
>  	u32 rate = 0, bucket_size = 0;
>  
>  	switch (f->command) {
> @@ -2736,18 +2760,19 @@ static int airoha_dev_tc_matchall(struct net_device *dev,
>  static int airoha_dev_setup_tc_block_cb(enum tc_setup_type type,
>  					void *type_data, void *cb_priv)
>  {
> -	struct net_device *dev = cb_priv;
> -	struct airoha_gdm_port *port = netdev_priv(dev);
> +	struct net_device *netdev = cb_priv;
> +	struct airoha_gdm_dev *dev = netdev_priv(netdev);
> +	struct airoha_gdm_port *port = dev->port;
>  	struct airoha_eth *eth = port->qdma->eth;
>  
> -	if (!tc_can_offload(dev))
> +	if (!tc_can_offload(netdev))
>  		return -EOPNOTSUPP;
>  
>  	switch (type) {
>  	case TC_SETUP_CLSFLOWER:
>  		return airoha_ppe_setup_tc_block_cb(&eth->ppe->dev, type_data);
>  	case TC_SETUP_CLSMATCHALL:
> -		return airoha_dev_tc_matchall(dev, type_data);
> +		return airoha_dev_tc_matchall(netdev, type_data);
>  	default:
>  		return -EOPNOTSUPP;
>  	}
> @@ -2794,47 +2819,51 @@ static int airoha_dev_setup_tc_block(struct net_device *dev,
>  	}
>  }
>  
> -static void airoha_tc_remove_htb_queue(struct net_device *dev, int queue)
> +static void airoha_tc_remove_htb_queue(struct net_device *netdev, int queue)
>  {
> -	struct airoha_gdm_port *port = netdev_priv(dev);
> +	struct airoha_gdm_dev *dev = netdev_priv(netdev);
> +	struct airoha_gdm_port *port = dev->port;
>  
> -	netif_set_real_num_tx_queues(dev, dev->real_num_tx_queues - 1);
> -	airoha_qdma_set_tx_rate_limit(dev, queue + 1, 0, 0);
> +	netif_set_real_num_tx_queues(netdev, netdev->real_num_tx_queues - 1);
> +	airoha_qdma_set_tx_rate_limit(netdev, queue + 1, 0, 0);
>  	clear_bit(queue, port->qos_sq_bmap);
>  }
>  
> -static int airoha_tc_htb_delete_leaf_queue(struct net_device *dev,
> +static int airoha_tc_htb_delete_leaf_queue(struct net_device *netdev,
>  					   struct tc_htb_qopt_offload *opt)
>  {
>  	u32 channel = TC_H_MIN(opt->classid) % AIROHA_NUM_QOS_CHANNELS;
> -	struct airoha_gdm_port *port = netdev_priv(dev);
> +	struct airoha_gdm_dev *dev = netdev_priv(netdev);
> +	struct airoha_gdm_port *port = dev->port;
>  
>  	if (!test_bit(channel, port->qos_sq_bmap)) {
>  		NL_SET_ERR_MSG_MOD(opt->extack, "invalid queue id");
>  		return -EINVAL;
>  	}
>  
> -	airoha_tc_remove_htb_queue(dev, channel);
> +	airoha_tc_remove_htb_queue(netdev, channel);
>  
>  	return 0;
>  }
>  
> -static int airoha_tc_htb_destroy(struct net_device *dev)
> +static int airoha_tc_htb_destroy(struct net_device *netdev)
>  {
> -	struct airoha_gdm_port *port = netdev_priv(dev);
> +	struct airoha_gdm_dev *dev = netdev_priv(netdev);
> +	struct airoha_gdm_port *port = dev->port;
>  	int q;
>  
>  	for_each_set_bit(q, port->qos_sq_bmap, AIROHA_NUM_QOS_CHANNELS)
> -		airoha_tc_remove_htb_queue(dev, q);
> +		airoha_tc_remove_htb_queue(netdev, q);
>  
>  	return 0;
>  }
>  
> -static int airoha_tc_get_htb_get_leaf_queue(struct net_device *dev,
> +static int airoha_tc_get_htb_get_leaf_queue(struct net_device *netdev,
>  					    struct tc_htb_qopt_offload *opt)
>  {
>  	u32 channel = TC_H_MIN(opt->classid) % AIROHA_NUM_QOS_CHANNELS;
> -	struct airoha_gdm_port *port = netdev_priv(dev);
> +	struct airoha_gdm_dev *dev = netdev_priv(netdev);
> +	struct airoha_gdm_port *port = dev->port;
>  
>  	if (!test_bit(channel, port->qos_sq_bmap)) {
>  		NL_SET_ERR_MSG_MOD(opt->extack, "invalid queue id");
> @@ -2870,8 +2899,8 @@ static int airoha_tc_setup_qdisc_htb(struct net_device *dev,
>  	return 0;
>  }
>  
> -static int airoha_dev_tc_setup(struct net_device *dev, enum tc_setup_type type,
> -			       void *type_data)
> +static int airoha_dev_tc_setup(struct net_device *dev,
> +			       enum tc_setup_type type, void *type_data)
>  {
>  	switch (type) {
>  	case TC_SETUP_QDISC_ETS:
> @@ -2937,25 +2966,81 @@ static void airoha_metadata_dst_free(struct airoha_gdm_port *port)
>  	}
>  }
>  
> -bool airoha_is_valid_gdm_port(struct airoha_eth *eth,
> -			      struct airoha_gdm_port *port)
> +bool airoha_is_valid_gdm_dev(struct airoha_eth *eth,
> +			     struct airoha_gdm_dev *dev)
>  {
>  	int i;
>  
>  	for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
> -		if (eth->ports[i] == port)
> +		struct airoha_gdm_port *port = eth->ports[i];
> +
> +		if (!port)
> +			continue;
> +
> +		if (port->dev == dev)
>  			return true;
>  	}
>  
>  	return false;
>  }
>  
> +static int airoha_alloc_gdm_device(struct airoha_eth *eth,
> +				   struct airoha_gdm_port *port,
> +				   struct device_node *np)
> +{
> +	struct airoha_gdm_dev *dev;
> +	struct net_device *netdev;
> +	int err;
> +
> +	netdev = devm_alloc_etherdev_mqs(eth->dev, sizeof(*dev),
> +					 AIROHA_NUM_NETDEV_TX_RINGS,
> +					 AIROHA_NUM_RX_RING);
> +	if (!netdev) {
> +		dev_err(eth->dev, "alloc_etherdev failed\n");
> +		return -ENOMEM;
> +	}
> +
> +	netdev->netdev_ops = &airoha_netdev_ops;
> +	netdev->ethtool_ops = &airoha_ethtool_ops;
> +	netdev->max_mtu = AIROHA_MAX_MTU;
> +	netdev->watchdog_timeo = 5 * HZ;
> +	netdev->hw_features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM | NETIF_F_TSO6 |
> +			      NETIF_F_IPV6_CSUM | NETIF_F_SG | NETIF_F_TSO |
> +			      NETIF_F_HW_TC;
> +	netdev->features |= netdev->hw_features;
> +	netdev->vlan_features = netdev->hw_features;
> +	netdev->dev.of_node = np;
> +	SET_NETDEV_DEV(netdev, eth->dev);
> +
> +	/* reserve hw queues for HTB offloading */
> +	err = netif_set_real_num_tx_queues(netdev, AIROHA_NUM_TX_RING);
> +	if (err)
> +		return err;
> +
> +	err = of_get_ethdev_address(np, netdev);
> +	if (err) {
> +		if (err == -EPROBE_DEFER)
> +			return err;
> +
> +		eth_hw_addr_random(netdev);
> +		dev_info(eth->dev, "generated random MAC address %pM\n",
> +			 netdev->dev_addr);
> +	}
> +
> +	dev = netdev_priv(netdev);
> +	dev->dev = netdev;
> +	dev->port = port;
> +	port->dev = dev;
> +	dev->eth = eth;
> +
> +	return 0;
> +}
> +
>  static int airoha_alloc_gdm_port(struct airoha_eth *eth,
>  				 struct device_node *np)
>  {
>  	const __be32 *id_ptr = of_get_property(np, "reg", NULL);
>  	struct airoha_gdm_port *port;
> -	struct net_device *dev;
>  	int err, p;
>  	u32 id;
>  
> @@ -2977,53 +3062,22 @@ static int airoha_alloc_gdm_port(struct airoha_eth *eth,
>  		return -EINVAL;
>  	}
>  
> -	dev = devm_alloc_etherdev_mqs(eth->dev, sizeof(*port),
> -				      AIROHA_NUM_NETDEV_TX_RINGS,
> -				      AIROHA_NUM_RX_RING);
> -	if (!dev) {
> -		dev_err(eth->dev, "alloc_etherdev failed\n");
> +	port = devm_kzalloc(eth->dev, sizeof(*port), GFP_KERNEL);
> +	if (!port)
>  		return -ENOMEM;
> -	}
> -
> -	dev->netdev_ops = &airoha_netdev_ops;
> -	dev->ethtool_ops = &airoha_ethtool_ops;
> -	dev->max_mtu = AIROHA_MAX_MTU;
> -	dev->watchdog_timeo = 5 * HZ;
> -	dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM |
> -			   NETIF_F_TSO6 | NETIF_F_IPV6_CSUM |
> -			   NETIF_F_SG | NETIF_F_TSO |
> -			   NETIF_F_HW_TC;
> -	dev->features |= dev->hw_features;
> -	dev->vlan_features = dev->hw_features;
> -	dev->dev.of_node = np;
> -	SET_NETDEV_DEV(dev, eth->dev);
> -
> -	/* reserve hw queues for HTB offloading */
> -	err = netif_set_real_num_tx_queues(dev, AIROHA_NUM_TX_RING);
> -	if (err)
> -		return err;
> -
> -	err = of_get_ethdev_address(np, dev);
> -	if (err) {
> -		if (err == -EPROBE_DEFER)
> -			return err;
> -
> -		eth_hw_addr_random(dev);
> -		dev_info(eth->dev, "generated random MAC address %pM\n",
> -			 dev->dev_addr);
> -	}
>  
> -	port = netdev_priv(dev);
>  	u64_stats_init(&port->stats.syncp);
>  	spin_lock_init(&port->stats.lock);
> -	port->eth = eth;
> -	port->dev = dev;
>  	port->id = id;
>  	/* XXX: Read nbq from DTS */
>  	port->nbq = id == AIROHA_GDM3_IDX && airoha_is_7581(eth) ? 4 : 0;
>  	eth->ports[p] = port;
>  
> -	return airoha_metadata_dst_alloc(port);
> +	err = airoha_metadata_dst_alloc(port);
> +	if (err)
> +		return err;
> +
> +	return airoha_alloc_gdm_device(eth, port, np);
>  }
>  
>  static int airoha_register_gdm_devices(struct airoha_eth *eth)
> @@ -3037,7 +3091,7 @@ static int airoha_register_gdm_devices(struct airoha_eth *eth)
>  		if (!port)
>  			continue;
>  
> -		err = register_netdev(port->dev);
> +		err = register_netdev(port->dev->dev);
>  		if (err)
>  			return err;
>  	}
> @@ -3146,12 +3200,14 @@ static int airoha_probe(struct platform_device *pdev)
>  
>  	for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
>  		struct airoha_gdm_port *port = eth->ports[i];
> +		struct airoha_gdm_dev *dev;
>  
>  		if (!port)
>  			continue;
>  
> -		if (port->dev->reg_state == NETREG_REGISTERED)
> -			unregister_netdev(port->dev);
> +		dev = port->dev;
> +		if (dev && dev->dev->reg_state == NETREG_REGISTERED)
> +			unregister_netdev(dev->dev);
>  		airoha_metadata_dst_free(port);
>  	}
>  	airoha_hw_cleanup(eth);
> @@ -3172,11 +3228,14 @@ static void airoha_remove(struct platform_device *pdev)
>  
>  	for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
>  		struct airoha_gdm_port *port = eth->ports[i];
> +		struct airoha_gdm_dev *dev;
>  
>  		if (!port)
>  			continue;
>  
> -		unregister_netdev(port->dev);
> +		dev = port->dev;
> +		if (dev)
> +			unregister_netdev(dev->dev);
>  		airoha_metadata_dst_free(port);
>  	}
>  	airoha_hw_cleanup(eth);
> diff --git a/drivers/net/ethernet/airoha/airoha_eth.h b/drivers/net/ethernet/airoha/airoha_eth.h
> index d3781103abb5..c78cabbec753 100644
> --- a/drivers/net/ethernet/airoha/airoha_eth.h
> +++ b/drivers/net/ethernet/airoha/airoha_eth.h
> @@ -535,10 +535,15 @@ struct airoha_qdma {
>  	struct airoha_queue q_rx[AIROHA_NUM_RX_RING];
>  };
>  
> +struct airoha_gdm_dev {
> +	struct airoha_gdm_port *port;
> +	struct net_device *dev;
> +	struct airoha_eth *eth;
> +};
> +
>  struct airoha_gdm_port {
>  	struct airoha_qdma *qdma;
> -	struct airoha_eth *eth;
> -	struct net_device *dev;
> +	struct airoha_gdm_dev *dev;
>  	int id;
>  	int nbq;
>  
> @@ -662,8 +667,8 @@ static inline bool airoha_is_7583(struct airoha_eth *eth)
>  }
>  
>  int airoha_get_fe_port(struct airoha_gdm_port *port);
> -bool airoha_is_valid_gdm_port(struct airoha_eth *eth,
> -			      struct airoha_gdm_port *port);
> +bool airoha_is_valid_gdm_dev(struct airoha_eth *eth,
> +			     struct airoha_gdm_dev *dev);
>  
>  void airoha_ppe_set_cpu_port(struct airoha_gdm_port *port, u8 ppe_id,
>  			     u8 fport);
> diff --git a/drivers/net/ethernet/airoha/airoha_ppe.c b/drivers/net/ethernet/airoha/airoha_ppe.c
> index 26da519236bf..af7af4097b98 100644
> --- a/drivers/net/ethernet/airoha/airoha_ppe.c
> +++ b/drivers/net/ethernet/airoha/airoha_ppe.c
> @@ -298,12 +298,12 @@ static void airoha_ppe_foe_set_bridge_addrs(struct airoha_foe_bridge *br,
>  
>  static int airoha_ppe_foe_entry_prepare(struct airoha_eth *eth,
>  					struct airoha_foe_entry *hwe,
> -					struct net_device *dev, int type,
> +					struct net_device *netdev, int type,
>  					struct airoha_flow_data *data,
>  					int l4proto)
>  {
>  	u32 qdata = FIELD_PREP(AIROHA_FOE_SHAPER_ID, 0x7f), ports_pad, val;
> -	int wlan_etype = -EINVAL, dsa_port = airoha_get_dsa_port(&dev);
> +	int wlan_etype = -EINVAL, dsa_port = airoha_get_dsa_port(&netdev);
>  	struct airoha_foe_mac_info_common *l2;
>  	u8 smac_id = 0xf;
>  
> @@ -319,10 +319,11 @@ static int airoha_ppe_foe_entry_prepare(struct airoha_eth *eth,
>  	hwe->ib1 = val;
>  
>  	val = FIELD_PREP(AIROHA_FOE_IB2_PORT_AG, 0x1f);
> -	if (dev) {
> +	if (netdev) {
>  		struct airoha_wdma_info info = {};
>  
> -		if (!airoha_ppe_get_wdma_info(dev, data->eth.h_dest, &info)) {
> +		if (!airoha_ppe_get_wdma_info(netdev, data->eth.h_dest,
> +					      &info)) {
>  			val |= FIELD_PREP(AIROHA_FOE_IB2_NBQ, info.idx) |
>  			       FIELD_PREP(AIROHA_FOE_IB2_PSE_PORT,
>  					  FE_PSE_PORT_CDM4);
> @@ -332,12 +333,14 @@ static int airoha_ppe_foe_entry_prepare(struct airoha_eth *eth,
>  				     FIELD_PREP(AIROHA_FOE_MAC_WDMA_WCID,
>  						info.wcid);
>  		} else {
> -			struct airoha_gdm_port *port = netdev_priv(dev);
> +			struct airoha_gdm_dev *dev = netdev_priv(netdev);
> +			struct airoha_gdm_port *port;
>  			u8 pse_port, channel;
>  
> -			if (!airoha_is_valid_gdm_port(eth, port))
> +			if (!airoha_is_valid_gdm_dev(eth, dev))
>  				return -EINVAL;
>  
> +			port = dev->port;
>  			if (dsa_port >= 0 || eth->ports[1])
>  				pse_port = port->id == 4 ? FE_PSE_PORT_GDM4
>  							 : port->id;
> @@ -1473,7 +1476,7 @@ void airoha_ppe_check_skb(struct airoha_ppe_dev *dev, struct sk_buff *skb,
>  void airoha_ppe_init_upd_mem(struct airoha_gdm_port *port)
>  {
>  	struct airoha_eth *eth = port->qdma->eth;
> -	struct net_device *dev = port->dev;
> +	struct net_device *dev = port->dev->dev;
>  	const u8 *addr = dev->dev_addr;
>  	u32 val;
>  
> 
> -- 
> 2.54.0
> 

Commenting on sashiko's report:
https://sashiko.dev/#/patchset/20260511-airoha-eth-multi-serdes-v6-0-c899462c4f75%40kernel.org

- This problem wasn't introduced by this patch, but does this function call lead
  to out-of-bounds memory accesses?
  - I do not think this is an issue, since airoha_eth driver supports just mtk as
    dsa driver where we actually skb_push() MTK_HDR_LEN bytes in mtk_tag_xmit().

- This problem wasn't introduced by this patch, but does this incorrect bounds
  accounting in HTB offload break QoS?
  - I will fix this issue with a dedicated patch.

- This problem wasn't introduced by this patch, but does this leave the rate
  limit active due to an off-by-one error?
  - I will fix this issue with a dedicated patch.

- This problem wasn't introduced by this patch, but does this lead to a
  use-after-free of the device tree node?
  - This is fixed by a subsequent patch in the series.

Regards,
Lorenzo

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply

* Re: [PATCH v2 6/8] PCI: aardvark: Add 100 ms delay after link training
From: Pali Rohár @ 2026-05-12 21:25 UTC (permalink / raw)
  To: Hans Zhang
  Cc: bhelgaas, lpieralisi, kwilczynski, mani, vigneshr, jingoohan1,
	thomas.petazzoni, ryder.lee, jianjun.wang, claudiu.beznea.uj,
	mpillai, robh, s-vadapalli, linux-omap, linux-arm-kernel,
	linux-mediatek, linux-renesas-soc, linux-pci, linux-kernel
In-Reply-To: <20260506152346.166056-7-18255117159@163.com>

On Wednesday 06 May 2026 23:23:44 Hans Zhang wrote:
> The Aardvark PCIe controller driver waits for the link to come up but
> does not implement the mandatory 100 ms delay after link training
> completes for speeds greater than 5.0 GT/s (PCIe r6.0 sec 6.6.1).
> 
> The driver already maintains a 'link_gen' field that holds the negotiated
> link speed. Use it together with pcie_wait_after_link_train() to insert
> the required delay immediately after confirming that the link is up.
> 
> Signed-off-by: Hans Zhang <18255117159@163.com>
> ---
>  drivers/pci/controller/pci-aardvark.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c
> index e34bea1ff0ac..526351c21c49 100644
> --- a/drivers/pci/controller/pci-aardvark.c
> +++ b/drivers/pci/controller/pci-aardvark.c
> @@ -350,8 +350,10 @@ static int advk_pcie_wait_for_link(struct advk_pcie *pcie)
>  
>  	/* check if the link is up or not */
>  	for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
> -		if (advk_pcie_link_up(pcie))
> +		if (advk_pcie_link_up(pcie)) {
> +			pcie_wait_after_link_train(pcie->link_gen);
>  			return 0;
> +		}
>  
>  		usleep_range(LINK_WAIT_USLEEP_MIN, LINK_WAIT_USLEEP_MAX);
>  	}
> -- 
> 2.34.1
> 

Are you sure that this is correct to do? Have you checked the A3720
Functional Specification which describes how to bring PCIe link up?

A3720 PCIe controller is buggy and needs more timing hacks to make it
behave. Playing with random sleeps can break its internal logic.
I'm not sure if it could be safe without proper testing.

And IIRC A3720 PCIe controller is just PCIe2.0 with 5 GT/s.


^ permalink raw reply

* [PATCH 1/1] dt-bindings: display: imx: Add television encoder (TVE) for imx53
From: Frank Li @ 2026-05-12 22:31 UTC (permalink / raw)
  To: Philipp Zabel, David Airlie, Simona Vetter, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Frank Li, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam,
	open list:DRM DRIVERS FOR FREESCALE IMX 5/6,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	open list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
	open list
  Cc: imx

Add television encoder (TVE) for legacy i.MX53 (over 15 years) to fix below
DTB_CHECK warnings:
  arch/arm/boot/dts/nxp/imx/imx53-ard.dtb: /soc/bus@60000000/tve@63ff0000: failed to match any schema with compatible: ['fsl,imx53-tve']

Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
About cleanup 300 lines warnings for i.MX ARM platform
---
 .../bindings/display/imx/fsl,imx53-tve.yaml   | 102 ++++++++++++++++++
 1 file changed, 102 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/imx/fsl,imx53-tve.yaml

diff --git a/Documentation/devicetree/bindings/display/imx/fsl,imx53-tve.yaml b/Documentation/devicetree/bindings/display/imx/fsl,imx53-tve.yaml
new file mode 100644
index 0000000000000..a7c971be1959b
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/imx/fsl,imx53-tve.yaml
@@ -0,0 +1,102 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/imx/fsl,imx53-tve.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Freescale i.MX53 Television Encoder (TVE)
+
+maintainers:
+  - Frank Li <Frank.Li@nxp.com>
+
+description:
+  The Television Encoder (TVE) is a hardware block in the i.MX53 SoC that
+  converts digital video data into analog TV signals (NTSC/PAL).
+
+properties:
+  compatible:
+    const: fsl,imx53-tve
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: TVE gate clock
+      - description: Display interface selector clock
+
+  clock-names:
+    items:
+      - const: tve
+      - const: di_sel
+
+  ddc-i2c-bus:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description:
+      Phandle to the I2C bus used for DDC (Display Data Channel) communication
+      to read EDID information from the connected display.
+
+  dac-supply:
+    description:
+      Regulator supply for the TVE DAC (Digital-to-Analog Converter).
+
+  fsl,tve-mode:
+    $ref: /schemas/types.yaml#/definitions/string
+    description:
+      TVE output mode selection.
+    enum:
+      - ntsc
+      - pal
+      - vga
+
+  fsl,hsync-pin:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description:
+      Pin number for horizontal sync signal in VGA mode.
+    minimum: 0
+    maximum: 8
+
+  fsl,vsync-pin:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description:
+      Pin number for vertical sync signal in VGA mode.
+    minimum: 0
+    maximum: 8
+
+  port:
+    $ref: /schemas/graph.yaml#/properties/port
+    description:
+      Port node with one endpoint connected to the IPU display interface.
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/imx5-clock.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    tve@63ff0000 {
+        compatible = "fsl,imx53-tve";
+        reg = <0x63ff0000 0x1000>;
+        interrupts = <92>;
+        clocks = <&clks IMX5_CLK_TVE_GATE>,
+                 <&clks IMX5_CLK_IPU_DI1_SEL>;
+        clock-names = "tve", "di_sel";
+
+        port {
+            endpoint {
+                remote-endpoint = <&ipu_di1_tve>;
+            };
+        };
+    };
+
-- 
2.43.0



^ permalink raw reply related

* [PATCH 00/12] crypto: atmel - refactor common i2c support and add SHA256 ahash support
From: Lothar Rubusch @ 2026-05-12 22:43 UTC (permalink / raw)
  To: thorsten.blum, herbert, davem, nicolas.ferre, alexandre.belloni,
	claudiu.beznea
  Cc: linux-crypto, linux-arm-kernel, linux-kernel, l.rubusch

This series restructures the Atmel secure element drivers around a
shared atmel-i2c core and adds SHA256 ahash support for ATSHA204A and
ECC based devices.

The existing drivers duplicated substantial parts of the transport,
RNG, EEPROM and device management logic. This series consolidates the
common functionality into the shared i2c core and converts the client
drivers to capability based allocation.

The series also introduces per-device timing configuration through
match data, moves sanity checks and RNG handling into the core driver,
updates workqueue handling and cleans up internal constants and helper
definitions.

The final patch adds SHA256 ahash support using the hardware SHA engine
provided by the devices.

ATSHA204A devices require software-side SHA256 padding according to
FIPS 180-4, while newer ECC devices provide a dedicated SHA final
command and perform padding internally in hardware.

Supporting the SHA engine also requires changes to the command
transport path. SHA operations must execute as a strict uninterrupted
sequence consisting of SHA INIT, one or more SHA COMPUTE commands and,
for ECC devices, a terminating SHA FINAL command. The device loses its
internal SHA state if it enters sleep mode or if unrelated commands
are interleaved during the transaction.

To satisfy these hardware requirements, the send/receive path is split
into a low-level transfer helper and a higher-level wrapper managing
wakeup, sleep and locking. SHA operations keep the device awake and
hold the i2c lock for the full duration of the hashing transaction.

The series has been tested on ATSHA204A and ATECC508A devices.
Tests are ongoing/pending on ATECC608A and ATECC608B.
---
Lothar Rubusch (12):
  crypto: atmel - introduce shared I2C client management
  crypto: atmel - move capability-based client allocation into i2c core
  crypto: atmel - remove obsolete CONFIG_OF guard
  crypto: atmel - add per-device timing and match-data driven
    configuration
  crypto: atmel - move RNG support into common i2c core
  crypto: atmel - move EEPROM access support into common i2c core
  crypto: atmel - expose CONFIG zone through sysfs
  crypto: atmel - move device sanity check to core driver
  crypto: atmel - check client data in remove callbacks
  crypto: atmel - update workqueue flags and add flush on exit
  crypto: atmel - refactor and localize driver constants
  crypto: atmel - add SHA256 ahash support

 drivers/crypto/atmel-ecc.c     | 252 +++++++-----
 drivers/crypto/atmel-i2c.c     | 679 +++++++++++++++++++++++++++++----
 drivers/crypto/atmel-i2c.h     | 180 +++++----
 drivers/crypto/atmel-sha204a.c | 284 +++++++-------
 4 files changed, 1010 insertions(+), 385 deletions(-)

Signed-off-by: Lothar Rubusch <l.rubusch@gmail.com>

base-commit: f7dd32c5179d7755de18e21d5674b08f9e5cb180
-- 
2.53.0



^ permalink raw reply

* [PATCH 02/12] crypto: atmel - move capability-based client allocation into i2c core
From: Lothar Rubusch @ 2026-05-12 22:43 UTC (permalink / raw)
  To: thorsten.blum, herbert, davem, nicolas.ferre, alexandre.belloni,
	claudiu.beznea
  Cc: linux-crypto, linux-arm-kernel, linux-kernel, l.rubusch
In-Reply-To: <20260512224349.64621-1-l.rubusch@gmail.com>

Move the i2c client allocation logic from atmel-ecc into the shared
atmel-i2c core and extend it to support capability-based client
selection.

Introduce enum atmel_i2c_capability and add capability flags to
struct atmel_i2c_client_priv. Devices now advertise their supported
features during probe, allowing atmel_i2c_client_alloc() to select a
compatible client from the shared i2c client list.

The allocation logic continues to balance crypto transformation usage
across devices by selecting the client with the lowest tfm_count, but
is no longer limited to ECC-capable devices.

This centralizes shared client management in the common atmel-i2c core
and prepares the infrastructure for additional shared crypto features
across compatible Atmel devices.

Signed-off-by: Lothar Rubusch <l.rubusch@gmail.com>
---
 drivers/crypto/atmel-ecc.c     | 39 +++-------------------------------
 drivers/crypto/atmel-i2c.c     | 39 ++++++++++++++++++++++++++++++++++
 drivers/crypto/atmel-i2c.h     |  7 ++++++
 drivers/crypto/atmel-sha204a.c |  2 ++
 4 files changed, 51 insertions(+), 36 deletions(-)

diff --git a/drivers/crypto/atmel-ecc.c b/drivers/crypto/atmel-ecc.c
index cba4238735cc..c63d30947bd7 100644
--- a/drivers/crypto/atmel-ecc.c
+++ b/drivers/crypto/atmel-ecc.c
@@ -200,41 +200,6 @@ static int atmel_ecdh_compute_shared_secret(struct kpp_request *req)
 	return ret;
 }
 
-static struct i2c_client *atmel_ecc_i2c_client_alloc(void)
-{
-	struct atmel_i2c_client_priv *i2c_priv, *min_i2c_priv = NULL;
-	struct i2c_client *client = ERR_PTR(-ENODEV);
-	int min_tfm_cnt = INT_MAX;
-	int tfm_cnt;
-
-	spin_lock(&atmel_i2c_mgmt.i2c_list_lock);
-
-	if (list_empty(&atmel_i2c_mgmt.i2c_client_list)) {
-		spin_unlock(&atmel_i2c_mgmt.i2c_list_lock);
-		return ERR_PTR(-ENODEV);
-	}
-
-	list_for_each_entry(i2c_priv, &atmel_i2c_mgmt.i2c_client_list,
-			    i2c_client_list_node) {
-		tfm_cnt = atomic_read(&i2c_priv->tfm_count);
-		if (tfm_cnt < min_tfm_cnt) {
-			min_tfm_cnt = tfm_cnt;
-			min_i2c_priv = i2c_priv;
-		}
-		if (!min_tfm_cnt)
-			break;
-	}
-
-	if (min_i2c_priv) {
-		atomic_inc(&min_i2c_priv->tfm_count);
-		client = min_i2c_priv->client;
-	}
-
-	spin_unlock(&atmel_i2c_mgmt.i2c_list_lock);
-
-	return client;
-}
-
 static void atmel_ecc_i2c_client_free(struct i2c_client *client)
 {
 	struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client);
@@ -249,7 +214,7 @@ static int atmel_ecdh_init_tfm(struct crypto_kpp *tfm)
 	struct atmel_ecdh_ctx *ctx = kpp_tfm_ctx(tfm);
 
 	ctx->curve_id = ECC_CURVE_NIST_P256;
-	ctx->client = atmel_ecc_i2c_client_alloc();
+	ctx->client = atmel_i2c_client_alloc(ATMEL_CAP_ECDH);
 	if (IS_ERR(ctx->client)) {
 		pr_err("tfm - i2c_client binding failed\n");
 		return PTR_ERR(ctx->client);
@@ -321,6 +286,8 @@ static int atmel_ecc_probe(struct i2c_client *client)
 
 	i2c_priv = i2c_get_clientdata(client);
 
+	i2c_priv->caps = BIT(ATMEL_CAP_ECDH);
+
 	/* add to client list */
 	spin_lock(&atmel_i2c_mgmt.i2c_list_lock);
 	list_add_tail(&i2c_priv->i2c_client_list_node,
diff --git a/drivers/crypto/atmel-i2c.c b/drivers/crypto/atmel-i2c.c
index 861af52d7a88..b7ee2ec37531 100644
--- a/drivers/crypto/atmel-i2c.c
+++ b/drivers/crypto/atmel-i2c.c
@@ -57,6 +57,45 @@ static void atmel_i2c_checksum(struct atmel_i2c_cmd *cmd)
 	*__crc16 = cpu_to_le16(bitrev16(crc16(0, data, len)));
 }
 
+struct i2c_client *atmel_i2c_client_alloc(enum atmel_i2c_capability cap)
+{
+	struct atmel_i2c_client_priv *i2c_priv, *min_i2c_priv = NULL;
+	struct i2c_client *client = ERR_PTR(-ENODEV);
+	int min_tfm_cnt = INT_MAX;
+	int tfm_cnt;
+
+	spin_lock(&atmel_i2c_mgmt.i2c_list_lock);
+
+	if (list_empty(&atmel_i2c_mgmt.i2c_client_list)) {
+		spin_unlock(&atmel_i2c_mgmt.i2c_list_lock);
+		return ERR_PTR(-ENODEV);
+	}
+
+	list_for_each_entry(i2c_priv, &atmel_i2c_mgmt.i2c_client_list,
+			    i2c_client_list_node) {
+		if (!(i2c_priv->caps & BIT(cap)))
+			continue;
+
+		tfm_cnt = atomic_read(&i2c_priv->tfm_count);
+		if (tfm_cnt < min_tfm_cnt) {
+			min_tfm_cnt = tfm_cnt;
+			min_i2c_priv = i2c_priv;
+		}
+		if (!min_tfm_cnt)
+			break;
+	}
+
+	if (min_i2c_priv) {
+		atomic_inc(&min_i2c_priv->tfm_count);
+		client = min_i2c_priv->client;
+	}
+
+	spin_unlock(&atmel_i2c_mgmt.i2c_list_lock);
+
+	return client;
+}
+EXPORT_SYMBOL(atmel_i2c_client_alloc);
+
 void atmel_i2c_init_read_config_cmd(struct atmel_i2c_cmd *cmd)
 {
 	cmd->word_addr = COMMAND;
diff --git a/drivers/crypto/atmel-i2c.h b/drivers/crypto/atmel-i2c.h
index 43a0c1cfcd94..70579b438256 100644
--- a/drivers/crypto/atmel-i2c.h
+++ b/drivers/crypto/atmel-i2c.h
@@ -115,6 +115,10 @@ struct atmel_i2c_cmd {
 #define ECDH_PREFIX_MODE		0x00
 
 /* Used for binding tfm objects to i2c clients. */
+enum atmel_i2c_capability {
+	ATMEL_CAP_ECDH = 0,
+};
+
 struct atmel_i2c_client_mgmt {
 	struct list_head i2c_client_list;
 	spinlock_t i2c_list_lock;
@@ -130,6 +134,7 @@ extern struct atmel_i2c_client_mgmt atmel_i2c_mgmt;
  * @wake_token_sz       : size in bytes of the wake_token
  * @tfm_count           : number of active crypto transformations on i2c client
  * @hwrng               : hold the hardware generated rng
+ * @caps                : feature capability of the particular driver
  *
  * Reads and writes from/to the i2c client are sequential. The first byte
  * transmitted to the device is treated as the byte size. Any attempt to send
@@ -146,6 +151,7 @@ struct atmel_i2c_client_priv {
 	size_t wake_token_sz;
 	atomic_t tfm_count ____cacheline_aligned;
 	struct hwrng hwrng;
+	u32 caps;
 };
 
 /**
@@ -190,6 +196,7 @@ void atmel_i2c_init_genkey_cmd(struct atmel_i2c_cmd *cmd, u16 keyid);
 int atmel_i2c_init_ecdh_cmd(struct atmel_i2c_cmd *cmd,
 			    struct scatterlist *pubkey);
 
+struct i2c_client *atmel_i2c_client_alloc(enum atmel_i2c_capability cap);
 void atmel_i2c_unregister_client(struct atmel_i2c_client_priv *i2c_priv);
 
 #endif /* __ATMEL_I2C_H__ */
diff --git a/drivers/crypto/atmel-sha204a.c b/drivers/crypto/atmel-sha204a.c
index e6808c2bc891..ab758c9cd410 100644
--- a/drivers/crypto/atmel-sha204a.c
+++ b/drivers/crypto/atmel-sha204a.c
@@ -173,6 +173,8 @@ static int atmel_sha204a_probe(struct i2c_client *client)
 
 	i2c_priv = i2c_get_clientdata(client);
 
+	i2c_priv->caps = 0;
+
 	/* add to client list */
 	spin_lock(&atmel_i2c_mgmt.i2c_list_lock);
 	list_add_tail(&i2c_priv->i2c_client_list_node,
-- 
2.53.0



^ permalink raw reply related

* [PATCH 01/12] crypto: atmel - introduce shared I2C client management
From: Lothar Rubusch @ 2026-05-12 22:43 UTC (permalink / raw)
  To: thorsten.blum, herbert, davem, nicolas.ferre, alexandre.belloni,
	claudiu.beznea
  Cc: linux-crypto, linux-arm-kernel, linux-kernel, l.rubusch
In-Reply-To: <20260512224349.64621-1-l.rubusch@gmail.com>

Introduce a shared I2C client management infrastructure in the
atmel-i2c core and convert the atmel-ecc and atmel-sha204a drivers
to use it.

Replace the driver-local atmel_ecc_driver_data structure with the
common atmel_i2c_mgmt instance, providing a shared client list and
locking for compatible Atmel secure element devices. Add a common
atmel_i2c_unregister_client() helper to centralize client removal
handling.

Refactor both drivers to use module_i2c_driver() and move duplicated
client list handling into the shared infrastructure. Probe and remove
paths are updated accordingly, including consistent error unwinding
for client registration failures.

Subsequent patches will build on the shared client infrastructure.

Signed-off-by: Lothar Rubusch <l.rubusch@gmail.com>
---
 drivers/crypto/atmel-ecc.c     | 58 ++++++++++++++--------------------
 drivers/crypto/atmel-i2c.c     | 15 +++++++++
 drivers/crypto/atmel-i2c.h     |  5 ++-
 drivers/crypto/atmel-sha204a.c | 38 ++++++++++++----------
 4 files changed, 65 insertions(+), 51 deletions(-)

diff --git a/drivers/crypto/atmel-ecc.c b/drivers/crypto/atmel-ecc.c
index 3738a4eb8701..cba4238735cc 100644
--- a/drivers/crypto/atmel-ecc.c
+++ b/drivers/crypto/atmel-ecc.c
@@ -23,8 +23,6 @@
 #include <crypto/kpp.h>
 #include "atmel-i2c.h"
 
-static struct atmel_ecc_driver_data driver_data;
-
 /**
  * struct atmel_ecdh_ctx - transformation context
  * @client     : pointer to i2c client device
@@ -209,14 +207,14 @@ static struct i2c_client *atmel_ecc_i2c_client_alloc(void)
 	int min_tfm_cnt = INT_MAX;
 	int tfm_cnt;
 
-	spin_lock(&driver_data.i2c_list_lock);
+	spin_lock(&atmel_i2c_mgmt.i2c_list_lock);
 
-	if (list_empty(&driver_data.i2c_client_list)) {
-		spin_unlock(&driver_data.i2c_list_lock);
+	if (list_empty(&atmel_i2c_mgmt.i2c_client_list)) {
+		spin_unlock(&atmel_i2c_mgmt.i2c_list_lock);
 		return ERR_PTR(-ENODEV);
 	}
 
-	list_for_each_entry(i2c_priv, &driver_data.i2c_client_list,
+	list_for_each_entry(i2c_priv, &atmel_i2c_mgmt.i2c_client_list,
 			    i2c_client_list_node) {
 		tfm_cnt = atomic_read(&i2c_priv->tfm_count);
 		if (tfm_cnt < min_tfm_cnt) {
@@ -232,7 +230,7 @@ static struct i2c_client *atmel_ecc_i2c_client_alloc(void)
 		client = min_i2c_priv->client;
 	}
 
-	spin_unlock(&driver_data.i2c_list_lock);
+	spin_unlock(&atmel_i2c_mgmt.i2c_list_lock);
 
 	return client;
 }
@@ -319,27 +317,34 @@ static int atmel_ecc_probe(struct i2c_client *client)
 
 	ret = atmel_i2c_probe(client);
 	if (ret)
-		return ret;
+		goto done;
 
 	i2c_priv = i2c_get_clientdata(client);
 
-	spin_lock(&driver_data.i2c_list_lock);
+	/* add to client list */
+	spin_lock(&atmel_i2c_mgmt.i2c_list_lock);
 	list_add_tail(&i2c_priv->i2c_client_list_node,
-		      &driver_data.i2c_client_list);
-	spin_unlock(&driver_data.i2c_list_lock);
+		      &atmel_i2c_mgmt.i2c_client_list);
+	spin_unlock(&atmel_i2c_mgmt.i2c_list_lock);
 
+	/* register algorithms */
 	ret = crypto_register_kpp(&atmel_ecdh_nist_p256);
 	if (ret) {
-		spin_lock(&driver_data.i2c_list_lock);
-		list_del(&i2c_priv->i2c_client_list_node);
-		spin_unlock(&driver_data.i2c_list_lock);
-
 		dev_err(&client->dev, "%s alg registration failed\n",
 			atmel_ecdh_nist_p256.base.cra_driver_name);
+		goto err_list_del;
 	} else {
 		dev_info(&client->dev, "atmel ecc algorithms registered in /proc/crypto\n");
 	}
 
+	goto done;
+
+err_list_del:
+	spin_lock(&atmel_i2c_mgmt.i2c_list_lock);
+	list_del(&i2c_priv->i2c_client_list_node);
+	spin_unlock(&atmel_i2c_mgmt.i2c_list_lock);
+
+done:
 	return ret;
 }
 
@@ -361,11 +366,10 @@ static void atmel_ecc_remove(struct i2c_client *client)
 		return;
 	}
 
-	crypto_unregister_kpp(&atmel_ecdh_nist_p256);
+	atmel_i2c_unregister_client(i2c_priv);
+	atmel_i2c_flush_queue();
 
-	spin_lock(&driver_data.i2c_list_lock);
-	list_del(&i2c_priv->i2c_client_list_node);
-	spin_unlock(&driver_data.i2c_list_lock);
+	crypto_unregister_kpp(&atmel_ecdh_nist_p256);
 }
 
 #ifdef CONFIG_OF
@@ -398,21 +402,7 @@ static struct i2c_driver atmel_ecc_driver = {
 	.id_table	= atmel_ecc_id,
 };
 
-static int __init atmel_ecc_init(void)
-{
-	spin_lock_init(&driver_data.i2c_list_lock);
-	INIT_LIST_HEAD(&driver_data.i2c_client_list);
-	return i2c_add_driver(&atmel_ecc_driver);
-}
-
-static void __exit atmel_ecc_exit(void)
-{
-	atmel_i2c_flush_queue();
-	i2c_del_driver(&atmel_ecc_driver);
-}
-
-module_init(atmel_ecc_init);
-module_exit(atmel_ecc_exit);
+module_i2c_driver(atmel_ecc_driver);
 
 MODULE_AUTHOR("Tudor Ambarus");
 MODULE_DESCRIPTION("Microchip / Atmel ECC (I2C) driver");
diff --git a/drivers/crypto/atmel-i2c.c b/drivers/crypto/atmel-i2c.c
index 0e275dbdc8c5..861af52d7a88 100644
--- a/drivers/crypto/atmel-i2c.c
+++ b/drivers/crypto/atmel-i2c.c
@@ -21,6 +21,12 @@
 #include <linux/workqueue.h>
 #include "atmel-i2c.h"
 
+struct atmel_i2c_client_mgmt atmel_i2c_mgmt = {
+	.i2c_list_lock = __SPIN_LOCK_UNLOCKED(atmel_i2c_mgmt.i2c_list_lock),
+	.i2c_client_list = LIST_HEAD_INIT(atmel_i2c_mgmt.i2c_client_list),
+};
+EXPORT_SYMBOL_GPL(atmel_i2c_mgmt);
+
 static const struct {
 	u8 value;
 	const char *error_text;
@@ -348,6 +354,15 @@ static int device_sanity_check(struct i2c_client *client)
 	return ret;
 }
 
+void atmel_i2c_unregister_client(struct atmel_i2c_client_priv *i2c_priv)
+{
+	spin_lock(&atmel_i2c_mgmt.i2c_list_lock);
+	if (!list_empty(&i2c_priv->i2c_client_list_node))
+		list_del_init(&i2c_priv->i2c_client_list_node);
+	spin_unlock(&atmel_i2c_mgmt.i2c_list_lock);
+}
+EXPORT_SYMBOL(atmel_i2c_unregister_client);
+
 int atmel_i2c_probe(struct i2c_client *client)
 {
 	struct atmel_i2c_client_priv *i2c_priv;
diff --git a/drivers/crypto/atmel-i2c.h b/drivers/crypto/atmel-i2c.h
index 72f04c15682f..43a0c1cfcd94 100644
--- a/drivers/crypto/atmel-i2c.h
+++ b/drivers/crypto/atmel-i2c.h
@@ -115,10 +115,11 @@ struct atmel_i2c_cmd {
 #define ECDH_PREFIX_MODE		0x00
 
 /* Used for binding tfm objects to i2c clients. */
-struct atmel_ecc_driver_data {
+struct atmel_i2c_client_mgmt {
 	struct list_head i2c_client_list;
 	spinlock_t i2c_list_lock;
 } ____cacheline_aligned;
+extern struct atmel_i2c_client_mgmt atmel_i2c_mgmt;
 
 /**
  * atmel_i2c_client_priv - i2c_client private data
@@ -189,4 +190,6 @@ void atmel_i2c_init_genkey_cmd(struct atmel_i2c_cmd *cmd, u16 keyid);
 int atmel_i2c_init_ecdh_cmd(struct atmel_i2c_cmd *cmd,
 			    struct scatterlist *pubkey);
 
+void atmel_i2c_unregister_client(struct atmel_i2c_client_priv *i2c_priv);
+
 #endif /* __ATMEL_I2C_H__ */
diff --git a/drivers/crypto/atmel-sha204a.c b/drivers/crypto/atmel-sha204a.c
index ed7d69bf6890..e6808c2bc891 100644
--- a/drivers/crypto/atmel-sha204a.c
+++ b/drivers/crypto/atmel-sha204a.c
@@ -169,10 +169,17 @@ static int atmel_sha204a_probe(struct i2c_client *client)
 
 	ret = atmel_i2c_probe(client);
 	if (ret)
-		return ret;
+		goto done;
 
 	i2c_priv = i2c_get_clientdata(client);
 
+	/* add to client list */
+	spin_lock(&atmel_i2c_mgmt.i2c_list_lock);
+	list_add_tail(&i2c_priv->i2c_client_list_node,
+		      &atmel_i2c_mgmt.i2c_client_list);
+	spin_unlock(&atmel_i2c_mgmt.i2c_list_lock);
+
+	/* register rng */
 	memset(&i2c_priv->hwrng, 0, sizeof(i2c_priv->hwrng));
 
 	i2c_priv->hwrng.name = dev_name(&client->dev);
@@ -183,15 +190,26 @@ static int atmel_sha204a_probe(struct i2c_client *client)
 		i2c_priv->hwrng.quality = *quality;
 
 	ret = devm_hwrng_register(&client->dev, &i2c_priv->hwrng);
-	if (ret)
+	if (ret) {
 		dev_warn(&client->dev, "failed to register RNG (%d)\n", ret);
+		goto err_list_del;
+	}
 
 	ret = sysfs_create_group(&client->dev.kobj, &atmel_sha204a_groups);
 	if (ret) {
 		dev_err(&client->dev, "failed to register sysfs entry\n");
-		return ret;
+		goto err_list_del;
 	}
 
+	goto done;
+
+err_list_del:
+	sysfs_remove_group(&client->dev.kobj, &atmel_sha204a_groups);
+	spin_lock(&atmel_i2c_mgmt.i2c_list_lock);
+	list_del(&i2c_priv->i2c_client_list_node);
+	spin_unlock(&atmel_i2c_mgmt.i2c_list_lock);
+
+done:
 	return ret;
 }
 
@@ -230,19 +248,7 @@ static struct i2c_driver atmel_sha204a_driver = {
 	.driver.of_match_table	= of_match_ptr(atmel_sha204a_dt_ids),
 };
 
-static int __init atmel_sha204a_init(void)
-{
-	return i2c_add_driver(&atmel_sha204a_driver);
-}
-
-static void __exit atmel_sha204a_exit(void)
-{
-	atmel_i2c_flush_queue();
-	i2c_del_driver(&atmel_sha204a_driver);
-}
-
-module_init(atmel_sha204a_init);
-module_exit(atmel_sha204a_exit);
+module_i2c_driver(atmel_sha204a_driver);
 
 MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
 MODULE_DESCRIPTION("Microchip / Atmel SHA204A (I2C) driver");
-- 
2.53.0



^ permalink raw reply related

* [PATCH 03/12] crypto: atmel - remove obsolete CONFIG_OF guard
From: Lothar Rubusch @ 2026-05-12 22:43 UTC (permalink / raw)
  To: thorsten.blum, herbert, davem, nicolas.ferre, alexandre.belloni,
	claudiu.beznea
  Cc: linux-crypto, linux-arm-kernel, linux-kernel, l.rubusch
In-Reply-To: <20260512224349.64621-1-l.rubusch@gmail.com>

Remove the CONFIG_OF preprocessor guard around the OF device match
table in atmel-ecc.

OF match tables are expected to be present unconditionally and the
MODULE_DEVICE_TABLE(of, ...) handling already accounts for
configurations where OF support is disabled. Keeping the additional
guard provides no benefit and only adds unnecessary conditional
compilation.

Also compact the match table formatting while touching the code.

Signed-off-by: Lothar Rubusch <l.rubusch@gmail.com>
---
 drivers/crypto/atmel-ecc.c | 12 +++---------
 1 file changed, 3 insertions(+), 9 deletions(-)

diff --git a/drivers/crypto/atmel-ecc.c b/drivers/crypto/atmel-ecc.c
index c63d30947bd7..0dede3707b73 100644
--- a/drivers/crypto/atmel-ecc.c
+++ b/drivers/crypto/atmel-ecc.c
@@ -339,18 +339,12 @@ static void atmel_ecc_remove(struct i2c_client *client)
 	crypto_unregister_kpp(&atmel_ecdh_nist_p256);
 }
 
-#ifdef CONFIG_OF
 static const struct of_device_id atmel_ecc_dt_ids[] = {
-	{
-		.compatible = "atmel,atecc508a",
-	}, {
-		.compatible = "atmel,atecc608b",
-	}, {
-		/* sentinel */
-	}
+	{ .compatible = "atmel,atecc508a", },
+	{ .compatible = "atmel,atecc608b", },
+	{ }
 };
 MODULE_DEVICE_TABLE(of, atmel_ecc_dt_ids);
-#endif
 
 static const struct i2c_device_id atmel_ecc_id[] = {
 	{ "atecc508a" },
-- 
2.53.0



^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox