Skip to contentSkip to conversation

soc: aspeed: Add BMC and host driver for PCIe BMC device

PATCH Superseded Grégoire Layet 5 participants 44 messages Jun 2 – Jun 25

Subsystems (3)

v1 of 6 Superseded Latest is v6 →

lore
Share & tools
lore
#0 lore raw

cover soc: aspeed: Add BMC and host driver for PCIe BMC device

This series upstreams the PCIe BMC device driver from the ASPEED kernel SDK (branch master-v6.18) [1]. There are two drivers: a BMC-side driver and a host-side driver.
Together they enable host<->BMC communication via PCIe.
This includes : shared memory, doorbell interrupt communication and two VUARTs.

This driver can be used on AST2600/AST2700 based PCIe extension cards, such as Asus IPMI Kommando Card. The virtual UART support can be used for Serial over LAN.
The shared memory can be claimed by userspace programs.

Tested on :
BMC :
- Asus IPMI Kommando Card R1.01, AST2600 A3.
- OpenBMC
Host:
- Linux kernel v7.0.0

I tested VUART communication with interrupt.
No driver modifications were required.

Not tested on AST2700.

Provenance:

I did zero modifications to the ASPEED code, this is only an upstream patch. The driver files match the ASPEED SDK tree at :
drivers/soc/aspeed/aspeed-bmc-dev.c
1815546a54f5f89bc9d3bd8f5658f0a573927509 [2]
"soc: aspeed: remove MMBI implement in host bmc dev"

drivers/soc/aspeed/aspeed-host-bmc-dev.c
7217e3c872166d56389a97e1b81996f73a3e76d5 [3]
"soc: aspeed: remove iounmap"

The driver code build cleanly against Linux 7.0 without any modification. No fix were required.
I built both the BMC side and Host side with KCFLAGS=-W and no warning apperead. Original authors are credited via Signed-off-by in the individual patches.

checkpatch.pl --strict reports 1 warning for BMC side driver and 2 warnings for host side driver.
These are unchanged to keep zero diff against the ASPEED SDK tree. I can clean them in a v2 if needed.

The host side driver had a submission from Ninad Palsule :
"soc/aspeed: Add host side BMC device driver" in August 2023 [4]. This submission stalled and did not make it into the mainline kernel. Since then, the host drivers have changed a lot on the ASPEED SDK. I decided not to base this patch on Ninad's one
but rather to simply upstream the new host driver from ASPEED.

[1]: https://github.com/AspeedTech-BMC/linux/tree/aspeed-master-v6.18/drivers/soc/aspeed
[2]: https://github.com/AspeedTech-BMC/linux/commit/1815546a54f5f89bc9d3bd8f5658f0a573927509
[3]: https://github.com/AspeedTech-BMC/linux/commit/7217e3c872166d56389a97e1b81996f73a3e76d5
[4]: https://lore.kernel.org/linux-aspeed/[email protected]/

Grégoire Layet (2):
soc: aspeed: add BMC-side PCIe BMC device driver
soc: aspeed: add host-side PCIe BMC device driver

 drivers/soc/aspeed/Kconfig               |  22 +
 drivers/soc/aspeed/Makefile              |   2 +
 drivers/soc/aspeed/aspeed-bmc-dev.c      | 701 +++++++++++++++++++++++
 drivers/soc/aspeed/aspeed-host-bmc-dev.c | 664 +++++++++++++++++++++
 4 files changed, 1389 insertions(+)
 create mode 100644 drivers/soc/aspeed/aspeed-bmc-dev.c
 create mode 100644 drivers/soc/aspeed/aspeed-host-bmc-dev.c
Signature · 1 line
2.51.2
#1 lore raw

PATCH 1/2 soc: aspeed: add BMC-side PCIe BMC device driver

Taken from ASPEED 6.18 Kernel SDK

Add support for PCIe communication BMC<->host.
This add BMC side driver.

---
 drivers/soc/aspeed/Kconfig          |   9 +
 drivers/soc/aspeed/Makefile         |   1 +
 drivers/soc/aspeed/aspeed-bmc-dev.c | 701 ++++++++++++++++++++++++++++
 3 files changed, 711 insertions(+)
 create mode 100644 drivers/soc/aspeed/aspeed-bmc-dev.c
drivers/soc/aspeed/Kconfig +9 -0
index f579ee0b5afa..341728df07b3 100644
@@ -4,6 +4,15 @@ if ARCH_ASPEED || COMPILE_TEST
 
 menu "ASPEED SoC drivers"
 
+config ASPEED_BMC_DEV
+	tristate "ASPEED BMC Device"
+	default n
+	help
+	  Enable support for the ASPEED AST2600/AST2700 BMC Device.
+	  This exposes the BMC to the host over PCIe,
+	  providing a shared-memory BAR, host-to-BMC and BMC-to-host
+	  message queues with doorbell interrupts and PCIe-to-LPC bridge.
+
 config ASPEED_LPC_CTRL
 	tristate "ASPEED LPC firmware cycle control"
 	select REGMAP
drivers/soc/aspeed/Makefile +1 -0
index b35d74592964..fab0d247df66 100644
@@ -1,4 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_ASPEED_BMC_DEV)		+= aspeed-bmc-dev.o
 obj-$(CONFIG_ASPEED_LPC_CTRL)		+= aspeed-lpc-ctrl.o
 obj-$(CONFIG_ASPEED_LPC_SNOOP)		+= aspeed-lpc-snoop.o
 obj-$(CONFIG_ASPEED_UART_ROUTING)	+= aspeed-uart-routing.o
drivers/soc/aspeed/aspeed-bmc-dev.c new file +701 -0

702 lines not on this page · raw message

Signature · 1 line
2.51.2
#2 lore raw

PATCH 2/2 soc: aspeed: add host-side PCIe BMC device driver

In reply to Grégoire Layet

Taken from ASPEED 6.18 Kernel SDK

Add support for PCIe communication BMC<->host.
This add Host side driver.

---
 drivers/soc/aspeed/Kconfig               |  13 +
 drivers/soc/aspeed/Makefile              |   1 +
 drivers/soc/aspeed/aspeed-host-bmc-dev.c | 664 +++++++++++++++++++++++
 3 files changed, 678 insertions(+)
 create mode 100644 drivers/soc/aspeed/aspeed-host-bmc-dev.c
drivers/soc/aspeed/Kconfig +13 -0
index 341728df07b3..e8670dfef1e6 100644
@@ -13,6 +13,19 @@ config ASPEED_BMC_DEV
 	  providing a shared-memory BAR, host-to-BMC and BMC-to-host
 	  message queues with doorbell interrupts and PCIe-to-LPC bridge.
 
+config ASPEED_HOST_BMC_DEV
+	tristate "ASPEED Host BMC Device"
+	depends on PCI
+	depends on SERIAL_8250
+	help
+	  Enable support for the ASPEED AST2600/AST2700 BMC Device on the Host.
+	  This configure the PCIe and setup:
+	  - Two 8250 compatible VUART ports.
+	  - A character device exposing the BMC's shared memory
+	    region for host<->BMC data exchange.
+	  - A mailbox interrupt path and BMC message queue handler for
+		doorbell-style host<->BMC signaling.
+
 config ASPEED_LPC_CTRL
 	tristate "ASPEED LPC firmware cycle control"
 	select REGMAP
drivers/soc/aspeed/Makefile +1 -0
index fab0d247df66..3fd3f6d8d36e 100644
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-$(CONFIG_ASPEED_BMC_DEV)		+= aspeed-bmc-dev.o
+obj-$(CONFIG_ASPEED_HOST_BMC_DEV)	+= aspeed-host-bmc-dev.o
 obj-$(CONFIG_ASPEED_LPC_CTRL)		+= aspeed-lpc-ctrl.o
 obj-$(CONFIG_ASPEED_LPC_SNOOP)		+= aspeed-lpc-snoop.o
 obj-$(CONFIG_ASPEED_UART_ROUTING)	+= aspeed-uart-routing.o
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +664 -0

665 lines not on this page · raw message

Signature · 1 line
2.51.2
#3 lore raw

Re: [PATCH v1 2/2] soc: aspeed: add host-side PCIe BMC device driver

Quoted 9 lines
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +9 -0
+static int aspeed_pci_bmc_device_setup_vuart(struct pci_dev *pdev)
+{
+	struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev);
+	struct device *dev = &pdev->dev;
+	u16 vuart_ioport;
+	int ret, i;
+
+	for (i = 0; i < VUART_MAX_PARMS; i++) {
+		/* Assign the line to non-exist device */

drivers/soc/aspeed/aspeed-host-bmc-dev.c line 352

Quoted 10 lines
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +10 -0
+		pci_bmc_dev->uart_line[i] = -ENOENT;
+		vuart_ioport = 0x3F8 - (i * 0x100);
+		pci_bmc_dev->uart[i].port.flags =
+			UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
+		pci_bmc_dev->uart[i].port.uartclk = 115200 * 16;
+		pci_bmc_dev->uart[i].port.irq = pci_irq_vector(
+			pdev, pci_bmc_dev->msi_idx_table[VUART0_MSI + i]);
+		pci_bmc_dev->uart[i].port.dev = dev;
+		pci_bmc_dev->uart[i].port.iotype = UPIO_MEM32;
+		pci_bmc_dev->uart[i].port.iobase = 0;

How virtual is this? Is this directly accessing the hardware via shared memory? Or is there software on the BMC which traps these reads/writes and responds?

But first we need to decide if this is the correct architecture. The alternative is rpmsg or virtio. There is already tty/rpmsg_tty.c. A gpio driver over rpmsg is on the way. I2C has been discussed. There are plenty of virtio drivers, console, i2c, spi, gpio. virtio has higher performance, but also requires more memory. rpmsg is more suited to slower devices where memory is tight.

Either of these seem like a better way to expose resources of the BMC to the host.

Andrew

#4 lore raw

Re: [PATCH v1 2/2] soc: aspeed: add host-side PCIe BMC device driver

Quoted 3 lines

How virtual is this? Is this directly accessing the hardware via shared memory? Or is there software on the BMC which traps these reads/writes and responds?

The VUART is virtual because there is no physical UART link between the host and the BMC.
Instead, the AST2600 exposes a 16550-compatible register set on both sides (BMC APB and PCIe host MMIO).
The data flows using an internal 16 byte FIFO shared between the two register views.
So it's hardware emulated and there is no software in the data path.

The AST2600 has four VUARTs, two of which are accessible via PCIe MMIO. This is based on the following section of the AST2600 datasheet:
III.48 VUART and III.64 PCI2VUART.

Because the silicon presents a standard 16550A interface in hardware, the existing 8250 driver works without modification.

Quoted 5 lines

But first we need to decide if this is the correct architecture. The alternative is rpmsg or virtio.

Either of these seem like a better way to expose resources of the BMC to the host.

For the rest of the driver (shared memory, doorbell and mailbox), you are right, it makes more sense to implement rpmsg or virtio than just raw shared memory binding.
These are software-defined communication channels and not hardware-emulated, so they would fit better as rpmsg or virtio drivers.
I took the SDK driver as a starting point without questioning its structure. I have verified the VUART was working correctly with the shared memory, doorbell and mailbox setup removed.
I can split this into VUART only and defer the rest for a separate rpmsg/virtio work.

So I propose for v2:
- Remove the shared memory device, the sysfs doorbell and the mailbox from this series.
- Retain only the required configuration and initialisation on the BMC side driver.
This should mainly be SCU and PCIe device configuration but other
initialisation will be reviewed to determine what is required.
- The shared memory, doorbell and mailbox features could then be addressed in a separate future series, likely as virtio based driver.

Would that be acceptable?

Thanks,
Grégoire

#5 lore raw

Re: [PATCH v1 2/2] soc: aspeed: add host-side PCIe BMC device driver

Quoted 12 lines · Grégoire Layet
Quoted 3 lines

How virtual is this? Is this directly accessing the hardware via shared memory? Or is there software on the BMC which traps these reads/writes and responds?

The VUART is virtual because there is no physical UART link between the host and the BMC.
Instead, the AST2600 exposes a 16550-compatible register set on both sides (BMC APB and PCIe host MMIO).
The data flows using an internal 16 byte FIFO shared between the two register views.
So it's hardware emulated and there is no software in the data path.

Quoted 6 lines

The AST2600 has four VUARTs, two of which are accessible via PCIe MMIO. This is based on the following section of the AST2600 datasheet:
III.48 VUART and III.64 PCI2VUART.

Because the silicon presents a standard 16550A interface in hardware, the existing 8250 driver works without modification.

So tell us about security.

Is only this UART exposed in the shared memory? So the memory window is 8 bytes wide? Or are there other peripherals also exposed? How do we know the aspeed is not using the UART itself? If two drivers are using it, are we going to crash one or the other system?

https://en.wikipedia.org/wiki/Core_War

The advantage of rpmsg is that the aspeed would advertise what services it is willing to expose. The security issues are different, implementation bugs vs exposing bits of hardware to an attacker.

Andrew

maintainer
#6 lore raw

Re: [PATCH v1 2/2] soc: aspeed: add host-side PCIe BMC device driver

Quoted 17 lines · Andrew Lunn
Quoted 16 lines · Grégoire Layet
Quoted 3 lines

How virtual is this? Is this directly accessing the hardware via shared memory? Or is there software on the BMC which traps these reads/writes and responds?

The VUART is virtual because there is no physical UART link between the host and the BMC.
Instead, the AST2600 exposes a 16550-compatible register set on both sides (BMC APB and PCIe host MMIO).
The data flows using an internal 16 byte FIFO shared between the two register views.
So it's hardware emulated and there is no software in the data path.

The AST2600 has four VUARTs, two of which are accessible via PCIe MMIO. This is based on the following section of the AST2600 datasheet:
III.48 VUART and III.64 PCI2VUART.

Quoted 7 lines
Quoted 2 lines

Because the silicon presents a standard 16550A interface in hardware, the existing 8250 driver works without modification.

So tell us about security.

Is only this UART exposed in the shared memory?

No, however the BMC PCI interface provides a PCI-to-LPC bridge, so PCI accesses can drive cycles in to e.g LPC IO devices exposed by the BMC.

Quoted 4 lines

So the memory window
is 8 bytes wide? Or are there other peripherals also exposed? How do we know the aspeed is not using the UART itself?

For the "regular" SuperIO-controlled UARTs this is a concern, but it's not a concern for the VUARTs. Each VUART has a pair of 8250 register sets, one accessible from the BMC, the other accessible to the host, where both interfaces share the FIFOs to propagate data.

Quoted 2 lines

If two drivers are
using it, are we going to crash one or the other system?

By the above, not for the VUARTs.

Quoted 6 lines

https://en.wikipedia.org/wiki/Core_War

The advantage of rpmsg is that the aspeed would advertise what services it is willing to expose. The security issues are different, implementation bugs vs exposing bits of hardware to an attacker.

From my understanding rpmsg seems like a reasonable fit for the mailbox functionality.

Andrew

maintainer
#7 lore raw

Re: [PATCH v1 2/2] soc: aspeed: add host-side PCIe BMC device driver

In reply to Grégoire Layet
Quoted 22 lines · Grégoire Layet

For the rest of the driver (shared memory, doorbell and mailbox), you are right, it makes more sense to implement rpmsg or virtio than just raw shared memory binding.
These are software-defined communication channels and not hardware-emulated, so they would fit better as rpmsg or virtio drivers.
I took the SDK driver as a starting point without questioning its structure. I have verified the VUART was working correctly with the shared memory, doorbell and mailbox setup removed.
I can split this into VUART only and defer the rest for a separate rpmsg/virtio work.

So I propose for v2:
- Remove the shared memory device, the sysfs doorbell and the mailbox from this series.
- Retain only the required configuration and initialisation on the BMC side driver.
  This should mainly be SCU and PCIe device configuration but other initialisation will be reviewed to determine what is required.
- The shared memory, doorbell and mailbox features could then be addressed in a separate future series, likely as virtio based driver.

Quoted 1 line

Would that be acceptable?

That sounds good to me.

From a brief inspection the driver also had support for both the 2600 and 2700. Something to consider is just supporting one of those for now, and adding support for the other in later patches.

Andrew

#8 lore raw

v2 cover soc: aspeed: Add BMC and host driver for PCIe BMC device

In reply to Grégoire Layet

This is a v2 for upstreaming the VUART over PCIe BMC device driver from the ASPEED kernel SDK (branch master-v6.18) [1]. There are two drivers: a BMC-side driver and a host-side driver.
Together they enable host<->BMC VUART communication via PCIe.

This v2 narrows down the scope to VUART support only, to address review feedback on v1 [2] that the additional subsystems (shared memory, doorbell and mailbox) were software-defined IPC channels better used with rpmsg or virtio.
Those subsystems are deferred to a separate future series.

VUART data flow and MSI interrupts have been verified working on the test hardware.

Tested on:
BMC:
- Asus IPMI Kommando Card R1.01, AST2600 A3.
- OpenBMC
Host:
- Linux kernel v7.0.0

This v2 only supports AST2600; the AST2700 is untested and not supported by this patch.

Changes since v1 [2]:
- BMC driver: trimmed down to only SCU and PCIe initialization
- Host driver: removed shared memory misc device, sysfs doorbell, mailbox setup and message queue handler. Driver now only supports VUART registration.
- Host driver: Fixed cleanup path: removed pci_release_regions() call as there was no matching pci_request_regions call

[1]: https://github.com/AspeedTech-BMC/linux/tree/aspeed-master-v6.18/drivers/soc/aspeed
[2]: https://lore.kernel.org/linux-aspeed/[email protected]/

Grégoire Layet (2):
soc: aspeed: add BMC-side PCIe BMC device driver
soc: aspeed: add host-side PCIe BMC device driver

 drivers/soc/aspeed/Kconfig               |  15 ++
 drivers/soc/aspeed/Makefile              |   2 +
 drivers/soc/aspeed/aspeed-bmc-dev.c      | 187 +++++++++++++++++
 drivers/soc/aspeed/aspeed-host-bmc-dev.c | 249 +++++++++++++++++++++++
 4 files changed, 453 insertions(+)
 create mode 100644 drivers/soc/aspeed/aspeed-bmc-dev.c
 create mode 100644 drivers/soc/aspeed/aspeed-host-bmc-dev.c
Signature · 1 line
2.51.2
#9 lore raw

PATCH v2 1/2 soc: aspeed: add BMC-side PCIe BMC device driver

Taken from ASPEED 6.18 Kernel SDK

Add support for VUART over PCIe between BMC and host. This add BMC side driver.

---
 drivers/soc/aspeed/Kconfig          |   7 ++
 drivers/soc/aspeed/Makefile         |   1 +
 drivers/soc/aspeed/aspeed-bmc-dev.c | 187 ++++++++++++++++++++++++++++
 3 files changed, 195 insertions(+)
 create mode 100644 drivers/soc/aspeed/aspeed-bmc-dev.c
drivers/soc/aspeed/Kconfig +7 -0
index f579ee0b5afa..3e1fcf3c3268 100644
@@ -4,6 +4,13 @@ if ARCH_ASPEED || COMPILE_TEST
 
 menu "ASPEED SoC drivers"
 
+config ASPEED_BMC_DEV
+	tristate "ASPEED BMC Device"
+	default n
+	help
+	  Enable support for the ASPEED AST2600 BMC Device.
+	  This exposes the PCIe-to-LPC bridge of the BMC to the host over PCIe.
+
 config ASPEED_LPC_CTRL
 	tristate "ASPEED LPC firmware cycle control"
 	select REGMAP
drivers/soc/aspeed/Makefile +1 -0
index b35d74592964..fab0d247df66 100644
@@ -1,4 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_ASPEED_BMC_DEV)		+= aspeed-bmc-dev.o
 obj-$(CONFIG_ASPEED_LPC_CTRL)		+= aspeed-lpc-ctrl.o
 obj-$(CONFIG_ASPEED_LPC_SNOOP)		+= aspeed-lpc-snoop.o
 obj-$(CONFIG_ASPEED_UART_ROUTING)	+= aspeed-uart-routing.o
drivers/soc/aspeed/aspeed-bmc-dev.c new file +187 -0

188 lines not on this page · raw message

Signature · 1 line
2.51.2
maintainer
#10 lore raw

Re: [PATCH v2 1/2] soc: aspeed: add BMC-side PCIe BMC device driver

Hello Grégoire,

Quoted 1 line · Grégoire Layet

Taken from ASPEED 6.18 Kernel SDK

It's probably best to use ASPEED's SDK as a source of inspiration for fixing obscure bugs, but not send drivers directly extracted from it.

Quoted 4 lines

Add support for VUART over PCIe between BMC and host. This add BMC side driver.

Quoted 8 lines

---
 drivers/soc/aspeed/Kconfig          |   7 ++ drivers/soc/aspeed/Makefile         |   1 + drivers/soc/aspeed/aspeed-bmc-dev.c | 187 ++++++++++++++++++++++++++++

We should avoid adding more drivers in drivers/soc/aspeed where we can.

Is this really necessary?

Quoted 49 lines
 3 files changed, 195 insertions(+)

 create mode 100644 drivers/soc/aspeed/aspeed-bmc-dev.c

drivers/soc/aspeed/Kconfig +0 -0
index f579ee0b5afa..3e1fcf3c3268 100644
@@ -4,6 +4,13 @@ if ARCH_ASPEED || COMPILE_TEST


 menu "ASPEED SoC drivers"

drivers/soc/aspeed/Kconfig +7 -0
+config ASPEED_BMC_DEV
+	tristate "ASPEED BMC Device"
+	default n
+	help
+	  Enable support for the ASPEED AST2600 BMC Device.
+	  This exposes the PCIe-to-LPC bridge of the BMC to the host over PCIe.
+

 config ASPEED_LPC_CTRL
  tristate "ASPEED LPC firmware cycle control" select REGMAP

drivers/soc/aspeed/Makefile +1 -0
index b35d74592964..fab0d247df66 100644
@@ -1,4 +1,5 @@
  # SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_ASPEED_BMC_DEV)		+= aspeed-bmc-dev.o

 obj-$(CONFIG_ASPEED_LPC_CTRL) += aspeed-lpc-ctrl.o
 obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o
 obj-$(CONFIG_ASPEED_UART_ROUTING) += aspeed-uart-routing.o

drivers/soc/aspeed/aspeed-bmc-dev.c new file +12 -0
new file mode 100644
index 000000000000..7a204b543c97
@@ -0,0 +1,187 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// Copyright (C) ASPEED Technology Inc.
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+
+#include <linux/regmap.h>

drivers/soc/aspeed/aspeed-bmc-dev.c line 22

Quoted 10 lines
drivers/soc/aspeed/aspeed-bmc-dev.c new file +10 -0
+#include <linux/interrupt.h>
+#include <linux/mfd/syscon.h>
+
+#define SCU_TRIGGER_MSI
+
+/* AST2600 SCU */
+#define ASPEED_SCU04			0x04
+#define AST2600A3_SCU04				0x05030303
+#define ASPEED_SCUC20			0xC20
+#define ASPEED_SCUC24			0xC24

These could all use properly descriptive names.

Pinctrl is an exception because of how the documentation is structured.

Quoted 35 lines
drivers/soc/aspeed/aspeed-bmc-dev.c new file +35 -0
+#define MSI_ROUTING_MASK			GENMASK(11, 10)
+#define PCIDEV1_INTX_MSI_HOST2BMC_EN		BIT(18)
+#define MSI_ROUTING_PCIe2LPC_PCIDEV0		(0x1 << 10)
+#define MSI_ROUTING_PCIe2LPC_PCIDEV1		(0x2 << 10)
+
+#define ASPEED_SCU_PCIE_CONF_CTRL	0xC20
+#define  SCU_PCIE_CONF_BMC_DEV_EN			 BIT(8)
+#define  SCU_PCIE_CONF_BMC_DEV_EN_MMIO		 BIT(9)
+#define  SCU_PCIE_CONF_BMC_DEV_EN_MSI		 BIT(11)
+#define  SCU_PCIE_CONF_BMC_DEV_EN_IRQ		 BIT(13)
+#define  SCU_PCIE_CONF_BMC_DEV_EN_DMA		 BIT(14)
+#define  SCU_PCIE_CONF_BMC_DEV_EN_E2L		 BIT(15)
+#define  SCU_PCIE_CONF_BMC_DEV_EN_LPC_DECODE BIT(21)
+
+#define ASPEED_SCU_BMC_DEV_CLASS	0xC68
+
+
+struct aspeed_platform {
+	int (*init)(struct platform_device *pdev);
+};
+
+struct aspeed_bmc_device {
+	struct device *dev;
+	int id;
+	void __iomem *reg_base;
+
+	int pcie2lpc;
+	int irq;
+
+	const struct aspeed_platform *platform;
+
+	struct regmap *scu;
+	int pcie_irq;
+};
+

drivers/soc/aspeed/aspeed-bmc-dev.c line 67

Quoted 10 lines
drivers/soc/aspeed/aspeed-bmc-dev.c new file +10 -0
+
+static int aspeed_ast2600_init(struct platform_device *pdev)
+{
+	struct aspeed_bmc_device *bmc_device = platform_get_drvdata(pdev);
+	struct device *dev = &pdev->dev;
+	u32 pcie_config_ctl = SCU_PCIE_CONF_BMC_DEV_EN_IRQ |
+			      SCU_PCIE_CONF_BMC_DEV_EN_MMIO | SCU_PCIE_CONF_BMC_DEV_EN;
+	u32 scu_id;
+
+	bmc_device->scu = syscon_regmap_lookup_by_phandle(dev->of_node, "aspeed,scu");

We should rather look at auxbus for the SCU.

Quoted 6 lines
drivers/soc/aspeed/aspeed-bmc-dev.c new file +6 -0
+	if (IS_ERR(bmc_device->scu)) {
+		dev_err(&pdev->dev, "failed to find SCU regmap\n");
+		return PTR_ERR(bmc_device->scu);
+	}
+
+	if (bmc_device->pcie2lpc)

drivers/soc/aspeed/aspeed-bmc-dev.c line 83

Quoted 10 lines
drivers/soc/aspeed/aspeed-bmc-dev.c new file +10 -0
+		pcie_config_ctl |= SCU_PCIE_CONF_BMC_DEV_EN_E2L |
+				   SCU_PCIE_CONF_BMC_DEV_EN_LPC_DECODE;
+
+	regmap_update_bits(bmc_device->scu, ASPEED_SCU_PCIE_CONF_CTRL,
+			   pcie_config_ctl, pcie_config_ctl);
+
+	/* update class code to others as it is a MFD device */
+	regmap_write(bmc_device->scu, ASPEED_SCU_BMC_DEV_CLASS, 0xff000000);
+
+#ifdef SCU_TRIGGER_MSI

I don't see that this needs to be a CPP test. This could be a C test. The construct would be optimised because of the constant and we'd get compile time coverage of both sides without additional configuration.

Have you tested both sides?

drivers/soc/aspeed/aspeed-bmc-dev.c line 85

Quoted 2 lines
drivers/soc/aspeed/aspeed-bmc-dev.c new file +2 -0
+	//SCUC24[17]: Enable PCI device 1 INTx/MSI from SCU560[15]. Will be added in next version
+	regmap_update_bits(bmc_device->scu, ASPEED_SCUC20, BIT(11) | BIT(14), BIT(11) | BIT(14));

These bits need descriptive macros.

drivers/soc/aspeed/aspeed-bmc-dev.c line 94

Quoted 9 lines
drivers/soc/aspeed/aspeed-bmc-dev.c new file +9 -0
+
+	regmap_read(bmc_device->scu, ASPEED_SCU04, &scu_id);
+	if (scu_id == AST2600A3_SCU04)
+		regmap_update_bits(bmc_device->scu, ASPEED_SCUC24,
+				   PCIDEV1_INTX_MSI_HOST2BMC_EN | MSI_ROUTING_MASK,
+				   PCIDEV1_INTX_MSI_HOST2BMC_EN | MSI_ROUTING_PCIe2LPC_PCIDEV1);
+	else
+		regmap_update_bits(bmc_device->scu, ASPEED_SCUC24,
+				   BIT(17) | BIT(14) | BIT(11), BIT(17) | BIT(14) | BIT(11));

As do these

drivers/soc/aspeed/aspeed-bmc-dev.c line 97

Quoted 3 lines
drivers/soc/aspeed/aspeed-bmc-dev.c new file +3 -0
+#else
+	//SCUC24[18]: Enable PCI device 1 INTx/MSI from Host-to-BMC controller.
+	regmap_update_bits(bmc_device->scu, 0xc24, BIT(18) | BIT(14), BIT(18) | BIT(14));

And these.

Quoted 4 lines
drivers/soc/aspeed/aspeed-bmc-dev.c new file +4 -0
+#endif
+
+
+	return 0;

drivers/soc/aspeed/aspeed-bmc-dev.c line 111

Quoted 10 lines
drivers/soc/aspeed/aspeed-bmc-dev.c new file +10 -0
+}
+
+
+static struct aspeed_platform ast2600_plaform = {
+	.init = aspeed_ast2600_init
+};
+
+
+static const struct of_device_id aspeed_bmc_device_of_matches[] = {
+	{ .compatible = "aspeed,ast2600-bmc-device", .data = &ast2600_plaform },

This compatible isn't documented in this series and isn't present in linux-next at a87737435cfa ("Add linux-next specific files for 20260608"). You'll need to address that if it's reasonable to continue down this path. I expect you'll want to avoid it, and define any necessary properties on the SCU node rather than add further children.

drivers/soc/aspeed/aspeed-bmc-dev.c line 119

Quoted 8 lines
drivers/soc/aspeed/aspeed-bmc-dev.c new file +8 -0
+	{},
+};
+MODULE_DEVICE_TABLE(of, aspeed_bmc_device_of_matches);
+
+static int aspeed_bmc_device_probe(struct platform_device *pdev)
+{
+	struct aspeed_bmc_device *bmc_device;
+	struct device *dev = &pdev->dev;

This shortcut is defined but inconsistently used.

drivers/soc/aspeed/aspeed-bmc-dev.c line 120

Quoted 1 line
drivers/soc/aspeed/aspeed-bmc-dev.c new file +1 -0
+	const void *md = of_device_get_match_data(dev);

I think we can do without this, see below.

Quoted 12 lines
drivers/soc/aspeed/aspeed-bmc-dev.c new file +12 -0
+	int ret = 0;
+
+	if (!md)
+		return -ENODEV;
+
+	bmc_device = devm_kzalloc(&pdev->dev, sizeof(struct aspeed_bmc_device), GFP_KERNEL);
+	if (!bmc_device)
+		return -ENOMEM;
+	dev_set_drvdata(dev, bmc_device);
+
+	bmc_device->platform = md;
+

drivers/soc/aspeed/aspeed-bmc-dev.c line 142

Quoted 10 lines
drivers/soc/aspeed/aspeed-bmc-dev.c new file +10 -0
+	bmc_device->id = of_alias_get_id(dev->of_node, "bmcdev");
+	if (bmc_device->id < 0)
+		bmc_device->id = 0;
+
+	bmc_device->dev = dev;
+	bmc_device->reg_base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(bmc_device->reg_base))
+		return PTR_ERR(bmc_device->reg_base);
+
+	bmc_device->irq = platform_get_irq(pdev, 0);

This seems unnecessary.

drivers/soc/aspeed/aspeed-bmc-dev.c line 148

Quoted 6 lines
drivers/soc/aspeed/aspeed-bmc-dev.c new file +6 -0
+	if (bmc_device->irq < 0) {
+		dev_err(&pdev->dev, "platform get of irq[=%d] failed!\n", bmc_device->irq);
+		return bmc_device->irq;
+	}
+
+	if (of_property_read_bool(dev->of_node, "pcie2lpc"))

This property isn't documented.

drivers/soc/aspeed/aspeed-bmc-dev.c line 151

Quoted 3 lines
drivers/soc/aspeed/aspeed-bmc-dev.c new file +3 -0
+		bmc_device->pcie2lpc = 1;
+
+	ret = bmc_device->platform->init(pdev);

The driver only supports one SoC, this indirection seems unnecessary right now. We can add that later when there's a need to differentiate. I'd rather you call the setup function directly for now.

Quoted 10 lines
drivers/soc/aspeed/aspeed-bmc-dev.c new file +10 -0
+	if (ret) {
+		dev_err(dev, "Initialize bmc device failed\n");
+		goto out;
+	}
+
+	dev_info(dev, "aspeed bmc device: driver successfully loaded.\n");
+
+	return 0;
+
+out:

drivers/soc/aspeed/aspeed-bmc-dev.c line 171

Quoted 10 lines
drivers/soc/aspeed/aspeed-bmc-dev.c new file +10 -0
+	dev_warn(dev, "aspeed bmc device: driver init failed (ret=%d)!\n", ret);
+	return ret;
+}
+
+static void aspeed_bmc_device_remove(struct platform_device *pdev)
+{
+	struct aspeed_bmc_device *bmc_device = platform_get_drvdata(pdev);
+
+	devm_free_irq(&pdev->dev, bmc_device->irq, bmc_device);
+	devm_kfree(&pdev->dev, bmc_device);

These are unnecessary due to cleanup of devres on release.

Andrew

#11 lore raw

Re: [PATCH v2 1/2] soc: aspeed: add BMC-side PCIe BMC device driver

Hello Andrew,

Quoted 2 lines

It's probably best to use ASPEED's SDK as a source of inspiration for fixing obscure bugs, but not send drivers directly extracted from it.

I would like to discuss the different options then.

If we decide to continue on the current path, I'll modify the code according to your remarks.

Quoted 2 lines

We should avoid adding more drivers in drivers/soc/aspeed where we can. Is this really necessary?

This driver (for the BMC side) only enables some configuration on the SCU to make MSI interrupts work. It is a very specific configuration, which is why I thought it was OK as a separate driver.

Fundamentally, the BMC side driver is not necessary. During my testing, I successfully made data flow in both directions without the BMC side driver, but this was using polling mode (IRQ = 0), it's not ideal.

It is also possible to put the SCU initialisation on the 8250_aspeed_vuart driver
directly. This could be activated with a specific flag added to VUART nodes ('pcie2vuart' for example) on the DeviceTree.

Putting this configuration in the VUART driver directly would make the setup on the devicetree easier and more understandable. Because in this series, the bmc side driver needs a bmc_device node to be loaded. But the bmc_dev node doesn't hold any meaningful information.
If we decide to take this approach, I think we should also add the differentiation for the ast2600 compatibility. Currently, the aspeed-g6.dtsi uses the "aspeed,ast2500-vuart" compatibility entry for the four VUARTs.

What do you think about this solution ?

Thanks,
Grégoire

Quoted 286 lines · Andrew Jeffery

Hello Grégoire,

Quoted 1 line · Grégoire Layet

Taken from ASPEED 6.18 Kernel SDK

It's probably best to use ASPEED's SDK as a source of inspiration for fixing obscure bugs, but not send drivers directly extracted from it.

Quoted 4 lines

Add support for VUART over PCIe between BMC and host. This add BMC side driver.

Quoted 8 lines
---
 drivers/soc/aspeed/Kconfig          |   7 ++
 drivers/soc/aspeed/Makefile         |   1 +
 drivers/soc/aspeed/aspeed-bmc-dev.c | 187 ++++++++++++++++++++++++++++

We should avoid adding more drivers in drivers/soc/aspeed where we can.

Is this really necessary?

Quoted 49 lines
 3 files changed, 195 insertions(+)
 create mode 100644 drivers/soc/aspeed/aspeed-bmc-dev.c
drivers/soc/aspeed/Kconfig +7 -0
index f579ee0b5afa..3e1fcf3c3268 100644
@@ -4,6 +4,13 @@ if ARCH_ASPEED || COMPILE_TEST
 
 menu "ASPEED SoC drivers"
 
+config ASPEED_BMC_DEV
+     tristate "ASPEED BMC Device"
+     default n
+     help
+       Enable support for the ASPEED AST2600 BMC Device.
+       This exposes the PCIe-to-LPC bridge of the BMC to the host over PCIe.
+
 config ASPEED_LPC_CTRL
      tristate "ASPEED LPC firmware cycle control"
      select REGMAP
drivers/soc/aspeed/Makefile +1 -0
index b35d74592964..fab0d247df66 100644
@@ -1,4 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_ASPEED_BMC_DEV)         += aspeed-bmc-dev.o
 obj-$(CONFIG_ASPEED_LPC_CTRL)                += aspeed-lpc-ctrl.o
 obj-$(CONFIG_ASPEED_LPC_SNOOP)               += aspeed-lpc-snoop.o
 obj-$(CONFIG_ASPEED_UART_ROUTING)    += aspeed-uart-routing.o
drivers/soc/aspeed/aspeed-bmc-dev.c new file +12 -0
new file mode 100644
index 000000000000..7a204b543c97
@@ -0,0 +1,187 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// Copyright (C) ASPEED Technology Inc.
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+
+#include <linux/regmap.h>

drivers/soc/aspeed/aspeed-bmc-dev.c line 22

Quoted 10 lines
drivers/soc/aspeed/aspeed-bmc-dev.c new file +10 -0
+#include <linux/interrupt.h>
+#include <linux/mfd/syscon.h>
+
+#define SCU_TRIGGER_MSI
+
+/* AST2600 SCU */
+#define ASPEED_SCU04                 0x04
+#define AST2600A3_SCU04                              0x05030303
+#define ASPEED_SCUC20                        0xC20
+#define ASPEED_SCUC24                        0xC24

These could all use properly descriptive names.

Pinctrl is an exception because of how the documentation is structured.

Quoted 35 lines
drivers/soc/aspeed/aspeed-bmc-dev.c new file +35 -0
+#define MSI_ROUTING_MASK                     GENMASK(11, 10)
+#define PCIDEV1_INTX_MSI_HOST2BMC_EN         BIT(18)
+#define MSI_ROUTING_PCIe2LPC_PCIDEV0         (0x1 << 10)
+#define MSI_ROUTING_PCIe2LPC_PCIDEV1         (0x2 << 10)
+
+#define ASPEED_SCU_PCIE_CONF_CTRL    0xC20
+#define  SCU_PCIE_CONF_BMC_DEV_EN                     BIT(8)
+#define  SCU_PCIE_CONF_BMC_DEV_EN_MMIO                BIT(9)
+#define  SCU_PCIE_CONF_BMC_DEV_EN_MSI                 BIT(11)
+#define  SCU_PCIE_CONF_BMC_DEV_EN_IRQ                 BIT(13)
+#define  SCU_PCIE_CONF_BMC_DEV_EN_DMA                 BIT(14)
+#define  SCU_PCIE_CONF_BMC_DEV_EN_E2L                 BIT(15)
+#define  SCU_PCIE_CONF_BMC_DEV_EN_LPC_DECODE BIT(21)
+
+#define ASPEED_SCU_BMC_DEV_CLASS     0xC68
+
+
+struct aspeed_platform {
+     int (*init)(struct platform_device *pdev);
+};
+
+struct aspeed_bmc_device {
+     struct device *dev;
+     int id;
+     void __iomem *reg_base;
+
+     int pcie2lpc;
+     int irq;
+
+     const struct aspeed_platform *platform;
+
+     struct regmap *scu;
+     int pcie_irq;
+};
+

drivers/soc/aspeed/aspeed-bmc-dev.c line 67

Quoted 10 lines
drivers/soc/aspeed/aspeed-bmc-dev.c new file +10 -0
+
+static int aspeed_ast2600_init(struct platform_device *pdev)
+{
+     struct aspeed_bmc_device *bmc_device = platform_get_drvdata(pdev);
+     struct device *dev = &pdev->dev;
+     u32 pcie_config_ctl = SCU_PCIE_CONF_BMC_DEV_EN_IRQ |
+                           SCU_PCIE_CONF_BMC_DEV_EN_MMIO | SCU_PCIE_CONF_BMC_DEV_EN;
+     u32 scu_id;
+
+     bmc_device->scu = syscon_regmap_lookup_by_phandle(dev->of_node, "aspeed,scu");

We should rather look at auxbus for the SCU.

Quoted 6 lines
drivers/soc/aspeed/aspeed-bmc-dev.c new file +6 -0
+     if (IS_ERR(bmc_device->scu)) {
+             dev_err(&pdev->dev, "failed to find SCU regmap\n");
+             return PTR_ERR(bmc_device->scu);
+     }
+
+     if (bmc_device->pcie2lpc)

drivers/soc/aspeed/aspeed-bmc-dev.c line 83

Quoted 10 lines
drivers/soc/aspeed/aspeed-bmc-dev.c new file +10 -0
+             pcie_config_ctl |= SCU_PCIE_CONF_BMC_DEV_EN_E2L |
+                                SCU_PCIE_CONF_BMC_DEV_EN_LPC_DECODE;
+
+     regmap_update_bits(bmc_device->scu, ASPEED_SCU_PCIE_CONF_CTRL,
+                        pcie_config_ctl, pcie_config_ctl);
+
+     /* update class code to others as it is a MFD device */
+     regmap_write(bmc_device->scu, ASPEED_SCU_BMC_DEV_CLASS, 0xff000000);
+
+#ifdef SCU_TRIGGER_MSI

I don't see that this needs to be a CPP test. This could be a C test. The construct would be optimised because of the constant and we'd get compile time coverage of both sides without additional configuration.

Have you tested both sides?

drivers/soc/aspeed/aspeed-bmc-dev.c line 85

Quoted 2 lines
drivers/soc/aspeed/aspeed-bmc-dev.c new file +2 -0
+     //SCUC24[17]: Enable PCI device 1 INTx/MSI from SCU560[15]. Will be added in next version
+     regmap_update_bits(bmc_device->scu, ASPEED_SCUC20, BIT(11) | BIT(14), BIT(11) | BIT(14));

These bits need descriptive macros.

drivers/soc/aspeed/aspeed-bmc-dev.c line 94

Quoted 9 lines
drivers/soc/aspeed/aspeed-bmc-dev.c new file +9 -0
+
+     regmap_read(bmc_device->scu, ASPEED_SCU04, &scu_id);
+     if (scu_id == AST2600A3_SCU04)
+             regmap_update_bits(bmc_device->scu, ASPEED_SCUC24,
+                                PCIDEV1_INTX_MSI_HOST2BMC_EN | MSI_ROUTING_MASK,
+                                PCIDEV1_INTX_MSI_HOST2BMC_EN | MSI_ROUTING_PCIe2LPC_PCIDEV1);
+     else
+             regmap_update_bits(bmc_device->scu, ASPEED_SCUC24,
+                                BIT(17) | BIT(14) | BIT(11), BIT(17) | BIT(14) | BIT(11));

As do these

drivers/soc/aspeed/aspeed-bmc-dev.c line 97

Quoted 3 lines
drivers/soc/aspeed/aspeed-bmc-dev.c new file +3 -0
+#else
+     //SCUC24[18]: Enable PCI device 1 INTx/MSI from Host-to-BMC controller.
+     regmap_update_bits(bmc_device->scu, 0xc24, BIT(18) | BIT(14), BIT(18) | BIT(14));

And these.

Quoted 4 lines
drivers/soc/aspeed/aspeed-bmc-dev.c new file +4 -0
+#endif
+
+
+     return 0;

drivers/soc/aspeed/aspeed-bmc-dev.c line 111

Quoted 10 lines
drivers/soc/aspeed/aspeed-bmc-dev.c new file +10 -0
+}
+
+
+static struct aspeed_platform ast2600_plaform = {
+     .init = aspeed_ast2600_init
+};
+
+
+static const struct of_device_id aspeed_bmc_device_of_matches[] = {
+     { .compatible = "aspeed,ast2600-bmc-device", .data = &ast2600_plaform },

This compatible isn't documented in this series and isn't present in linux-next at a87737435cfa ("Add linux-next specific files for 20260608"). You'll need to address that if it's reasonable to continue down this path. I expect you'll want to avoid it, and define any necessary properties on the SCU node rather than add further children.

drivers/soc/aspeed/aspeed-bmc-dev.c line 119

Quoted 8 lines
drivers/soc/aspeed/aspeed-bmc-dev.c new file +8 -0
+     {},
+};
+MODULE_DEVICE_TABLE(of, aspeed_bmc_device_of_matches);
+
+static int aspeed_bmc_device_probe(struct platform_device *pdev)
+{
+     struct aspeed_bmc_device *bmc_device;
+     struct device *dev = &pdev->dev;

This shortcut is defined but inconsistently used.

drivers/soc/aspeed/aspeed-bmc-dev.c line 120

Quoted 1 line
drivers/soc/aspeed/aspeed-bmc-dev.c new file +1 -0
+     const void *md = of_device_get_match_data(dev);

I think we can do without this, see below.

Quoted 12 lines
drivers/soc/aspeed/aspeed-bmc-dev.c new file +12 -0
+     int ret = 0;
+
+     if (!md)
+             return -ENODEV;
+
+     bmc_device = devm_kzalloc(&pdev->dev, sizeof(struct aspeed_bmc_device), GFP_KERNEL);
+     if (!bmc_device)
+             return -ENOMEM;
+     dev_set_drvdata(dev, bmc_device);
+
+     bmc_device->platform = md;
+

drivers/soc/aspeed/aspeed-bmc-dev.c line 142

Quoted 10 lines
drivers/soc/aspeed/aspeed-bmc-dev.c new file +10 -0
+     bmc_device->id = of_alias_get_id(dev->of_node, "bmcdev");
+     if (bmc_device->id < 0)
+             bmc_device->id = 0;
+
+     bmc_device->dev = dev;
+     bmc_device->reg_base = devm_platform_ioremap_resource(pdev, 0);
+     if (IS_ERR(bmc_device->reg_base))
+             return PTR_ERR(bmc_device->reg_base);
+
+     bmc_device->irq = platform_get_irq(pdev, 0);

This seems unnecessary.

drivers/soc/aspeed/aspeed-bmc-dev.c line 148

Quoted 6 lines
drivers/soc/aspeed/aspeed-bmc-dev.c new file +6 -0
+     if (bmc_device->irq < 0) {
+             dev_err(&pdev->dev, "platform get of irq[=%d] failed!\n", bmc_device->irq);
+             return bmc_device->irq;
+     }
+
+     if (of_property_read_bool(dev->of_node, "pcie2lpc"))

This property isn't documented.

drivers/soc/aspeed/aspeed-bmc-dev.c line 151

Quoted 3 lines
drivers/soc/aspeed/aspeed-bmc-dev.c new file +3 -0
+             bmc_device->pcie2lpc = 1;
+
+     ret = bmc_device->platform->init(pdev);

The driver only supports one SoC, this indirection seems unnecessary right now. We can add that later when there's a need to differentiate. I'd rather you call the setup function directly for now.

Quoted 10 lines
drivers/soc/aspeed/aspeed-bmc-dev.c new file +10 -0
+     if (ret) {
+             dev_err(dev, "Initialize bmc device failed\n");
+             goto out;
+     }
+
+     dev_info(dev, "aspeed bmc device: driver successfully loaded.\n");
+
+     return 0;
+
+out:

drivers/soc/aspeed/aspeed-bmc-dev.c line 171

Quoted 10 lines
drivers/soc/aspeed/aspeed-bmc-dev.c new file +10 -0
+     dev_warn(dev, "aspeed bmc device: driver init failed (ret=%d)!\n", ret);
+     return ret;
+}
+
+static void aspeed_bmc_device_remove(struct platform_device *pdev)
+{
+     struct aspeed_bmc_device *bmc_device = platform_get_drvdata(pdev);
+
+     devm_free_irq(&pdev->dev, bmc_device->irq, bmc_device);
+     devm_kfree(&pdev->dev, bmc_device);

These are unnecessary due to cleanup of devres on release.

Andrew

#12 lore raw

Re: [PATCH v2 1/2] soc: aspeed: add BMC-side PCIe BMC device driver

Hello Andrew,

Anirudh Srinivasan and I have found that IPMI over KCS using the PCI worked with the stock ASPEED bmc driver (the bmc driver in the V1) but not with the trimmed-down version in the V2. I have apparently removed a bit too much from the V2 , but that's not what I want to focus on.

This brings back the question of where we should put the registers configuration,
considering that two different functionalities depend on it.

Quoted 4 lines

It is also possible to put the SCU initialisation on the 8250_aspeed_vuart driver
directly. This could be activated with a specific flag added to VUART nodes ('pcie2vuart' for example) on the DeviceTree.

Similarly to this idea, we could include have the necessary configuration in the 'kcs_bmc_aspeed' driver. This could be activated using a similar flag ,such as 'pci2lpc'
or 'pci2kcs' directly. However, this would result in a lot of code duplication for most
of the configuration.

The issue for me is that, two drivers configuring the same registers is not a good idea.
I don't know how to do this the proper way.

I wanted to add this information because it could influence the move to a bmc_device driver that configures both VUART and KCS, over PCI. This would be similar to the V2 bmc driver, and I fix the KCS bug.

Thanks,
Grégoire

maintainer
#13 lore raw

Re: [PATCH v2 1/2] soc: aspeed: add BMC-side PCIe BMC device driver

Quoted 6 lines · Grégoire Layet

Hello Andrew,

Anirudh Srinivasan and I have found that IPMI over KCS using the PCI worked with the stock ASPEED bmc driver (the bmc driver in the V1) but not with the trimmed-down version in the V2. I have apparently removed a bit too much from the V2 , but that's not what I want to focus on.

Sure.

Quoted 9 lines

This brings back the question of where we should put the registers configuration,
considering that two different functionalities depend on it.

Quoted 4 lines

It is also possible to put the SCU initialisation on the 8250_aspeed_vuart driver
directly. This could be activated with a specific flag added to VUART nodes ('pcie2vuart' for example) on the DeviceTree.

The concept sounds reasonable to me. There's probably some bikeshedding to do on the devicetree property though.

Quoted 7 lines

Similarly to this idea, we could include have the necessary configuration in the 'kcs_bmc_aspeed' driver. This could be activated using a similar flag ,such as 'pci2lpc'
or 'pci2kcs' directly. However, this would result in a lot of code duplication for most
of the configuration.

Can you outline the duplication you're concerned about? I think it's a matter of resolving the SCU syscon to its regmap, then performing the necessary accesses?

Quoted 3 lines

The issue for me is that, two drivers configuring the same registers is not a good idea.

I think it's not as bad as you make it out to be. The SCU's regmap protects updates to individual registers under a lock, so concurrent modification isn't a concern. The hardware design choices make all of this slightly awkward for any related software design. As an alternative you could implement a mini subsystem that relevant drivers could call through to set the bits, but I currently think that's unnecessary work.

Andrew

#14 lore raw

Re: [PATCH v2 1/2] soc: aspeed: add BMC-side PCIe BMC device driver

Hello Andrew,

Quoted 2 lines

The concept sounds reasonable to me. There's probably some bikeshedding to do on the devicetree property though.

Yes, having looked at how it's done, I would say :
'aspeed,vuart-over-pci' and 'aspeed,kcs-over-pci' flags would be better.

Quoted 3 lines

Can you outline the duplication you're concerned about? I think it's a matter of resolving the SCU syscon to its regmap, then performing the necessary accesses?

Both drivers will need to set :
- Enable PCI BMC Device MMIO
- Enable PCI BMC Device IRQ
- Enable PCI BMC Device MSI rooting over PCI Device 1 (BAR1)
- Enable Host 2 BMC MSI interrupts
- PCI device class to 0xff000000 to be identified as a MFD device. The reset default is 0x0C070100 which is an IPMI KCS device, but that causes issues as it is detected by ipmi_si but can't be loaded because of non default KCS address.

Sorry for my errors, there is not that much. But both drivers will do almost the same initialisation. That was my code duplication concern.

Quoted 7 lines

I think it's not as bad as you make it out to be. The SCU's regmap protects updates to individual registers under a lock, so concurrent modification isn't a concern. The hardware design choices make all of this slightly awkward for any related software design. As an alternative you could implement a mini subsystem that relevant drivers could call through to set the bits, but I currently think that's unnecessary work.

You are right it's not as bad as I thought.
For now, I will focus on the VUART until the solution has been validated. Then I will easily do the same for the KCS over PCI.

So I'll do for the V3 of the BMC side driver:
- modify the device tree binding to have 'aspeed,ast2600-vuart' and add the 'aspeed,vuart-over-pci' boolean flag, only for the ast2600.
- modify the '8250_aspeed_vuart' driver to add 'aspeed,ast2600-vuart' support.
- add vuart over pci enable and disable code to the '8250_aspeed_vuart' driver.

Regards,
Grégoire

maintainer
#15 lore raw

Re: [PATCH v2 1/2] soc: aspeed: add BMC-side PCIe BMC device driver

Hi Grégoire,

Quoted 23 lines · Grégoire Layet

Hello Andrew,

Quoted 2 lines

The concept sounds reasonable to me. There's probably some bikeshedding to do on the devicetree property though.

Yes, having looked at how it's done, I would say :
'aspeed,vuart-over-pci' and 'aspeed,kcs-over-pci' flags would be better.

Quoted 3 lines

Can you outline the duplication you're concerned about? I think it's a matter of resolving the SCU syscon to its regmap, then performing the necessary accesses?

Both drivers will need to set :
- Enable PCI BMC Device MMIO
- Enable PCI BMC Device IRQ
- Enable PCI BMC Device MSI rooting over PCI Device 1 (BAR1)
- Enable Host 2 BMC MSI interrupts
- PCI device class to 0xff000000 to be identified as a MFD device. The reset default is 0x0C070100 which is an IPMI KCS device, but that causes issues as it is detected by ipmi_si but can't be loaded because of non default KCS address.

Quoted 2 lines

Sorry for my errors, there is not that much. But both drivers will do almost the same initialisation. That was my code duplication concern.

I think it's valid to be concerned, but perhaps not for the reason of code duplication. If there are multiple consumers then we need to ensure consistency of configuration and correctness wrt to enabling / disabling the capability based on the number of consumers.

Quoted 9 lines
Quoted 8 lines

I think it's not as bad as you make it out to be. The SCU's regmap protects updates to individual registers under a lock, so concurrent modification isn't a concern. The hardware design choices make all of this slightly awkward for any related software design. As an alternative you could implement a mini subsystem that relevant drivers could call through to set the bits, but I currently think that's unnecessary work.

Quoted 3 lines

You are right it's not as bad as I thought.
For now, I will focus on the VUART until the solution has been validated. Then I will easily do the same for the KCS over PCI.

I think it's a good step to at least solve one thing at a time, so long as we're not precluding making those future steps.

Quoted 4 lines

So I'll do for the V3 of the BMC side driver:
- modify the device tree binding to have 'aspeed,ast2600-vuart' and add the 'aspeed,vuart-over-pci' boolean flag, only for the ast2600.

Just to confirm, you're proposing modifying the 8250 binding?

Quoted 3 lines

- modify the '8250_aspeed_vuart' driver to add 'aspeed,ast2600-vuart' support.
- add vuart over pci enable and disable code to the '8250_aspeed_vuart' driver.

Sounds like a reasonable start to me.

Andrew

#16 lore raw

PATCH v2 2/2 soc: aspeed: add host-side PCIe BMC device driver

In reply to Grégoire Layet

Taken from ASPEED 6.18 Kernel SDK

Add support for VUART over PCIe between BMC and host. This add host side driver.

---
 drivers/soc/aspeed/Kconfig               |   8 +
 drivers/soc/aspeed/Makefile              |   1 +
 drivers/soc/aspeed/aspeed-host-bmc-dev.c | 249 +++++++++++++++++++++++
 3 files changed, 258 insertions(+)
 create mode 100644 drivers/soc/aspeed/aspeed-host-bmc-dev.c
drivers/soc/aspeed/Kconfig +8 -0
index 3e1fcf3c3268..5deefb64e8c7 100644
@@ -11,6 +11,14 @@ config ASPEED_BMC_DEV
 	  Enable support for the ASPEED AST2600 BMC Device.
 	  This exposes the PCIe-to-LPC bridge of the BMC to the host over PCIe.
 
+config ASPEED_HOST_BMC_DEV
+	tristate "ASPEED Host BMC Device"
+	depends on PCI
+	depends on SERIAL_8250
+	help
+	  Enable support for the ASPEED AST2600 BMC Device on the Host.
+	  This configure the PCIe and setup two 8250 compatible VUART ports.
+
 config ASPEED_LPC_CTRL
 	tristate "ASPEED LPC firmware cycle control"
 	select REGMAP
drivers/soc/aspeed/Makefile +1 -0
index fab0d247df66..3fd3f6d8d36e 100644
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-$(CONFIG_ASPEED_BMC_DEV)		+= aspeed-bmc-dev.o
+obj-$(CONFIG_ASPEED_HOST_BMC_DEV)	+= aspeed-host-bmc-dev.o
 obj-$(CONFIG_ASPEED_LPC_CTRL)		+= aspeed-lpc-ctrl.o
 obj-$(CONFIG_ASPEED_LPC_SNOOP)		+= aspeed-lpc-snoop.o
 obj-$(CONFIG_ASPEED_UART_ROUTING)	+= aspeed-uart-routing.o
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +249 -0

249 lines not on this page · raw message

Signature · 1 line
2.51.2
maintainer
#17 lore raw

Re: [PATCH v2 2/2] soc: aspeed: add host-side PCIe BMC device driver

Quoted 5 lines · Grégoire Layet

Taken from ASPEED 6.18 Kernel SDK

Add support for VUART over PCIe between BMC and host. This add host side driver.

Quoted 8 lines

---
 drivers/soc/aspeed/Kconfig               |   8 + drivers/soc/aspeed/Makefile              |   1 + drivers/soc/aspeed/aspeed-host-bmc-dev.c | 249 +++++++++++++++++++++++

Again, I'd rather we avoid drivers/soc/aspeed.

Quoted 44 lines
 3 files changed, 258 insertions(+)

 create mode 100644 drivers/soc/aspeed/aspeed-host-bmc-dev.c

drivers/soc/aspeed/Kconfig +0 -0
index 3e1fcf3c3268..5deefb64e8c7 100644
@@ -11,6 +11,14 @@ config ASPEED_BMC_DEV

    Enable support for the ASPEED AST2600 BMC Device.
    This exposes the PCIe-to-LPC bridge of the BMC to the host over PCIe.

drivers/soc/aspeed/Kconfig +8 -0
+config ASPEED_HOST_BMC_DEV
+	tristate "ASPEED Host BMC Device"
+	depends on PCI
+	depends on SERIAL_8250
+	help
+	  Enable support for the ASPEED AST2600 BMC Device on the Host.
+	  This configure the PCIe and setup two 8250 compatible VUART ports.
+

 config ASPEED_LPC_CTRL
  tristate "ASPEED LPC firmware cycle control" select REGMAP

drivers/soc/aspeed/Makefile +0 -0
index fab0d247df66..3fd3f6d8d36e 100644
@@ -1,5 +1,6 @@
  # SPDX-License-Identifier: GPL-2.0-only

 obj-$(CONFIG_ASPEED_BMC_DEV) += aspeed-bmc-dev.o
+obj-$(CONFIG_ASPEED_HOST_BMC_DEV) += aspeed-host-bmc-dev.o
 obj-$(CONFIG_ASPEED_LPC_CTRL) += aspeed-lpc-ctrl.o
 obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o
 obj-$(CONFIG_ASPEED_UART_ROUTING) += aspeed-uart-routing.o

drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +5 -0
new file mode 100644
index 000000000000..7cb52a770fb6
@@ -0,0 +1,249 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// Copyright (C) ASPEED Technology Inc.
+
+#include <linux/init.h>
+#include <linux/version.h>

drivers/soc/aspeed/aspeed-host-bmc-dev.c line 15

Quoted 10 lines
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +10 -0
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
+
+static DEFINE_IDA(bmc_device_ida);
+
+#define VUART_MAX_PARMS	2

Given the one supported piece of hardware we could avoid the associated loops and rather extract loop bodies to functions and call the function twice.

Quoted 101 lines
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +101 -0
+#define MAX_MSI_NUM		8
+#define BMC_MULTI_MSI	32
+
+#define DRIVER_NAME "aspeed-host-bmc-dev"
+
+enum aspeed_platform_id {
+	ASPEED,
+};
+
+enum msi_index {
+	VUART0_MSI,
+	VUART1_MSI,
+};
+
+/* Match msi_index */
+static int ast2600_msi_idx_table[MAX_MSI_NUM] = { 16, 15 };
+
+struct aspeed_platform {
+	int (*setup)(struct pci_dev *pdev);
+};
+
+struct aspeed_pci_bmc_dev {
+	struct device *dev;
+	struct aspeed_platform *platform;
+	kernel_ulong_t driver_data;
+	int id;
+
+	unsigned long message_bar_base;
+	unsigned long message_bar_size;
+	void __iomem *msg_bar_reg;
+
+	struct uart_8250_port uart[VUART_MAX_PARMS];
+	int uart_line[VUART_MAX_PARMS];
+
+	/* Interrupt
+	 * The index of array is using to enum msi_index
+	 */
+	int *msi_idx_table;
+};
+
+static void aspeed_pci_setup_irq_resource(struct pci_dev *pdev)
+{
+	struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev);
+
+	/* Assign static msi index table by platform */
+	pci_bmc_dev->msi_idx_table = ast2600_msi_idx_table;
+
+	if (pci_alloc_irq_vectors(pdev, 1, BMC_MULTI_MSI, PCI_IRQ_INTX | PCI_IRQ_MSI) <= 1)
+		/* Set all msi index to the first vector */
+		memset(pci_bmc_dev->msi_idx_table, 0, sizeof(int) * MAX_MSI_NUM);
+}
+
+static int aspeed_pci_bmc_device_setup_vuart(struct pci_dev *pdev)
+{
+	struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev);
+	struct device *dev = &pdev->dev;
+	u16 vuart_ioport;
+	int ret, i;
+
+	for (i = 0; i < VUART_MAX_PARMS; i++) {
+		/* Assign the line to non-exist device */
+		pci_bmc_dev->uart_line[i] = -ENOENT;
+		vuart_ioport = 0x3F8 - (i * 0x100);
+		pci_bmc_dev->uart[i].port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
+		pci_bmc_dev->uart[i].port.uartclk = 115200 * 16;
+		pci_bmc_dev->uart[i].port.irq =
+			pci_irq_vector(pdev, pci_bmc_dev->msi_idx_table[VUART0_MSI + i]);
+		pci_bmc_dev->uart[i].port.dev = dev;
+		pci_bmc_dev->uart[i].port.iotype = UPIO_MEM32;
+		pci_bmc_dev->uart[i].port.iobase = 0;
+		pci_bmc_dev->uart[i].port.mapbase =
+			pci_bmc_dev->message_bar_base + (vuart_ioport << 2);
+		pci_bmc_dev->uart[i].port.membase = 0;
+		pci_bmc_dev->uart[i].port.type = PORT_16550A;
+		pci_bmc_dev->uart[i].port.flags |= (UPF_IOREMAP | UPF_FIXED_PORT | UPF_FIXED_TYPE);
+		pci_bmc_dev->uart[i].port.regshift = 2;
+		ret = serial8250_register_8250_port(&pci_bmc_dev->uart[i]);
+		if (ret < 0) {
+			dev_err_probe(dev, ret, "Can't setup PCIe VUART\n");
+			return ret;
+		}
+		pci_bmc_dev->uart_line[i] = ret;
+	}
+	return 0;
+}
+
+static void aspeed_pci_host_bmc_device_release_vuart(struct pci_dev *pdev)
+{
+	struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev);
+	int i;
+
+	for (i = 0; i < VUART_MAX_PARMS; i++) {
+		if (pci_bmc_dev->uart_line[i] >= 0)
+			serial8250_unregister_port(pci_bmc_dev->uart_line[i]);
+	}
+}
+
+static int aspeed_pci_host_setup(struct pci_dev *pdev)
+{
+	struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev);
+	int rc = 0;

drivers/soc/aspeed/aspeed-host-bmc-dev.c line 126

Quoted 10 lines
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +10 -0
+
+	/* Get Message BAR */
+	pci_bmc_dev->message_bar_base = pci_resource_start(pdev, 1);
+	pci_bmc_dev->message_bar_size = pci_resource_len(pdev, 1);
+	pci_bmc_dev->msg_bar_reg = pci_ioremap_bar(pdev, 1);
+	if (!pci_bmc_dev->msg_bar_reg)
+		return -ENOMEM;
+
+	if (pdev->revision < 0x27) {
+		/* AST2600 ERRTA40: dummy read */

Can you please rather document what problem this is actually solving.

drivers/soc/aspeed/aspeed-host-bmc-dev.c line 130

Quoted 4 lines
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +4 -0
+		(void)__raw_readl((void __iomem *)pci_bmc_dev->msg_bar_reg);
+	} else {
+		/* AST2700 not supported */
+		pr_err("AST2700 detected but not supported");

This logs an error but rc = 0 on return. Perhaps drop the log message and return an appropriate error code?

Quoted 18 lines
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +18 -0
+		goto out_free0;
+	}
+
+	rc = aspeed_pci_bmc_device_setup_vuart(pdev);
+	if (rc) {
+		pr_err("Cannot setup Virtual UART");
+		goto out_free0;
+	}
+
+	return 0;
+
+out_free0:
+	pci_iounmap(pdev, pci_bmc_dev->msg_bar_reg);
+
+	return rc;
+}
+
+static struct aspeed_platform aspeed_pcie_host[] = {

drivers/soc/aspeed/aspeed-host-bmc-dev.c line 158

Quoted 10 lines
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +10 -0
+	{ .setup = aspeed_pci_host_setup },
+	{ 0 }
+};
+
+static int aspeed_pci_host_bmc_device_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	struct aspeed_pci_bmc_dev *pci_bmc_dev;
+	int rc = 0;
+
+	pr_info("ASPEED BMC PCI ID %04x:%04x, IRQ=%u\n", pdev->vendor, pdev->device, pdev->irq);

I think we could do without this.

drivers/soc/aspeed/aspeed-host-bmc-dev.c line 168

Quoted 10 lines
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +10 -0
+
+	pci_bmc_dev = devm_kzalloc(&pdev->dev, sizeof(*pci_bmc_dev), GFP_KERNEL);
+	if (!pci_bmc_dev)
+		return -ENOMEM;
+
+	/* Get platform id */
+	pci_bmc_dev->driver_data = ent->driver_data;
+	pci_bmc_dev->platform = &aspeed_pcie_host[ent->driver_data];
+
+	pci_bmc_dev->id = ida_alloc(&bmc_device_ida, GFP_KERNEL);

This seems unnecessary.

Quoted 7 lines
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +7 -0
+	if (pci_bmc_dev->id < 0)
+		return pci_bmc_dev->id;
+
+	rc = pci_enable_device(pdev);
+	if (rc) {
+		dev_err(&pdev->dev, "pci_enable_device() returned error %d\n", rc);
+		return rc;

drivers/soc/aspeed/aspeed-host-bmc-dev.c line 185

Quoted 10 lines
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +10 -0
+	}
+
+	pci_set_master(pdev);
+	pci_set_drvdata(pdev, pci_bmc_dev);
+
+	/* Prepare IRQ resource */
+	aspeed_pci_setup_irq_resource(pdev);
+
+	/* Setup BMC PCI device */
+	rc = pci_bmc_dev->platform->setup(pdev);

As with patch 1 this indirection seems unnecessary.

Quoted 5 lines
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +5 -0
+	if (rc) {
+		dev_err(&pdev->dev, "ASPEED PCIe Host device returned error %d\n", rc);
+		pci_free_irq_vectors(pdev);
+		pci_disable_device(pdev);
+		return rc;

drivers/soc/aspeed/aspeed-host-bmc-dev.c line 200

Quoted 10 lines
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +10 -0
+	}
+
+	return 0;
+}
+
+static void aspeed_pci_host_bmc_device_remove(struct pci_dev *pdev)
+{
+	struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev);
+
+	if (pci_bmc_dev->driver_data == ASPEED)

This condition seems unnecessary as the value shouldn't be anything else.

Quoted 4 lines
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +4 -0
+		aspeed_pci_host_bmc_device_release_vuart(pdev);
+
+	ida_free(&bmc_device_ida, pci_bmc_dev->id);
+

drivers/soc/aspeed/aspeed-host-bmc-dev.c line 214

Quoted 10 lines
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +10 -0
+	pci_iounmap(pdev, pci_bmc_dev->msg_bar_reg);
+
+	pci_free_irq_vectors(pdev);
+	pci_disable_device(pdev);
+}
+
+/**
+ * This table holds the list of (VendorID,DeviceID) supported by this driver
+ *
+ */

I think that's self-evident and prefer the comment be removed.

Quoted 21 lines
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +21 -0
+static struct pci_device_id aspeed_host_bmc_dev_pci_ids[] = {
+	/* ASPEED BMC Device */
+	{ PCI_DEVICE(0x1A03, 0x2402), .class = 0xFF0000, .class_mask = 0xFFFF00,
+	  .driver_data = ASPEED },
+	{
+		0,
+	}
+};
+
+MODULE_DEVICE_TABLE(pci, aspeed_host_bmc_dev_pci_ids);
+
+static struct pci_driver aspeed_host_bmc_dev_driver = {
+	.name		= DRIVER_NAME,
+	.id_table	= aspeed_host_bmc_dev_pci_ids,
+	.probe		= aspeed_pci_host_bmc_device_probe,
+	.remove		= aspeed_pci_host_bmc_device_remove,
+};
+
+static int __init aspeed_host_bmc_device_init(void)
+{
+	return pci_register_driver(&aspeed_host_bmc_dev_driver);

drivers/soc/aspeed/aspeed-host-bmc-dev.c line 245

Quoted 10 lines
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +10 -0
+}
+
+static void aspeed_host_bmc_device_exit(void)
+{
+	/* unregister pci driver */
+	pci_unregister_driver(&aspeed_host_bmc_dev_driver);
+}
+
+late_initcall(aspeed_host_bmc_device_init);
+module_exit(aspeed_host_bmc_device_exit);

module_driver() could be used here.

Quoted 4 lines
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +4 -0
+
+MODULE_AUTHOR("Ryan Chen <[email protected]>");
+MODULE_DESCRIPTION("ASPEED Host BMC DEVICE Driver");
+MODULE_LICENSE("GPL");
#18 lore raw

Re: [PATCH v2 2/2] soc: aspeed: add host-side PCIe BMC device driver

Hello Andrew,

Quoted 1 line

Again, I'd rather we avoid drivers/soc/aspeed.

If creating a new specific driver is the right move, where should it go if not in drivers/soc/aspeed ?
But again, considering all you remarks, maybe this driver is unnecessary.

As initially the driver was doing all the PCI BMC device functionality provided by ASPEED (shared memory, VUART, message queue and doorbell), it made sense to have everything in a driver for this specific case.

However for a TTY-only driver, that might be excessive.
When I trimmed down the driver, I didn't consider whether the driver itself was still necessary.
I think adding a new driver is not the right solution for this.

From my research, the ASPEED PCIe device could be added to the 8250_pci driver. The ASPEED PCIe device has a specific device ID and Vendor ID.

What do you think about this?

Thanks,
Grégoire

Quoted 337 lines · Andrew Jeffery
Quoted 5 lines · Grégoire Layet

Taken from ASPEED 6.18 Kernel SDK

Add support for VUART over PCIe between BMC and host. This add host side driver.

Quoted 8 lines
---
 drivers/soc/aspeed/Kconfig               |   8 +
 drivers/soc/aspeed/Makefile              |   1 +
 drivers/soc/aspeed/aspeed-host-bmc-dev.c | 249 +++++++++++++++++++++++

Again, I'd rather we avoid drivers/soc/aspeed.

Quoted 44 lines
 3 files changed, 258 insertions(+)
 create mode 100644 drivers/soc/aspeed/aspeed-host-bmc-dev.c
drivers/soc/aspeed/Kconfig +8 -0
index 3e1fcf3c3268..5deefb64e8c7 100644
@@ -11,6 +11,14 @@ config ASPEED_BMC_DEV
        Enable support for the ASPEED AST2600 BMC Device.
        This exposes the PCIe-to-LPC bridge of the BMC to the host over PCIe.
 
+config ASPEED_HOST_BMC_DEV
+     tristate "ASPEED Host BMC Device"
+     depends on PCI
+     depends on SERIAL_8250
+     help
+       Enable support for the ASPEED AST2600 BMC Device on the Host.
+       This configure the PCIe and setup two 8250 compatible VUART ports.
+
 config ASPEED_LPC_CTRL
      tristate "ASPEED LPC firmware cycle control"
      select REGMAP
drivers/soc/aspeed/Makefile +1 -0
index fab0d247df66..3fd3f6d8d36e 100644
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-$(CONFIG_ASPEED_BMC_DEV)         += aspeed-bmc-dev.o
+obj-$(CONFIG_ASPEED_HOST_BMC_DEV)    += aspeed-host-bmc-dev.o
 obj-$(CONFIG_ASPEED_LPC_CTRL)                += aspeed-lpc-ctrl.o
 obj-$(CONFIG_ASPEED_LPC_SNOOP)               += aspeed-lpc-snoop.o
 obj-$(CONFIG_ASPEED_UART_ROUTING)    += aspeed-uart-routing.o
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +5 -0
new file mode 100644
index 000000000000..7cb52a770fb6
@@ -0,0 +1,249 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// Copyright (C) ASPEED Technology Inc.
+
+#include <linux/init.h>
+#include <linux/version.h>

drivers/soc/aspeed/aspeed-host-bmc-dev.c line 15

Quoted 10 lines
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +10 -0
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
+
+static DEFINE_IDA(bmc_device_ida);
+
+#define VUART_MAX_PARMS      2

Given the one supported piece of hardware we could avoid the associated loops and rather extract loop bodies to functions and call the function twice.

Quoted 101 lines
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +101 -0
+#define MAX_MSI_NUM          8
+#define BMC_MULTI_MSI        32
+
+#define DRIVER_NAME "aspeed-host-bmc-dev"
+
+enum aspeed_platform_id {
+     ASPEED,
+};
+
+enum msi_index {
+     VUART0_MSI,
+     VUART1_MSI,
+};
+
+/* Match msi_index */
+static int ast2600_msi_idx_table[MAX_MSI_NUM] = { 16, 15 };
+
+struct aspeed_platform {
+     int (*setup)(struct pci_dev *pdev);
+};
+
+struct aspeed_pci_bmc_dev {
+     struct device *dev;
+     struct aspeed_platform *platform;
+     kernel_ulong_t driver_data;
+     int id;
+
+     unsigned long message_bar_base;
+     unsigned long message_bar_size;
+     void __iomem *msg_bar_reg;
+
+     struct uart_8250_port uart[VUART_MAX_PARMS];
+     int uart_line[VUART_MAX_PARMS];
+
+     /* Interrupt
+      * The index of array is using to enum msi_index
+      */
+     int *msi_idx_table;
+};
+
+static void aspeed_pci_setup_irq_resource(struct pci_dev *pdev)
+{
+     struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev);
+
+     /* Assign static msi index table by platform */
+     pci_bmc_dev->msi_idx_table = ast2600_msi_idx_table;
+
+     if (pci_alloc_irq_vectors(pdev, 1, BMC_MULTI_MSI, PCI_IRQ_INTX | PCI_IRQ_MSI) <= 1)
+             /* Set all msi index to the first vector */
+             memset(pci_bmc_dev->msi_idx_table, 0, sizeof(int) * MAX_MSI_NUM);
+}
+
+static int aspeed_pci_bmc_device_setup_vuart(struct pci_dev *pdev)
+{
+     struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev);
+     struct device *dev = &pdev->dev;
+     u16 vuart_ioport;
+     int ret, i;
+
+     for (i = 0; i < VUART_MAX_PARMS; i++) {
+             /* Assign the line to non-exist device */
+             pci_bmc_dev->uart_line[i] = -ENOENT;
+             vuart_ioport = 0x3F8 - (i * 0x100);
+             pci_bmc_dev->uart[i].port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
+             pci_bmc_dev->uart[i].port.uartclk = 115200 * 16;
+             pci_bmc_dev->uart[i].port.irq =
+                     pci_irq_vector(pdev, pci_bmc_dev->msi_idx_table[VUART0_MSI + i]);
+             pci_bmc_dev->uart[i].port.dev = dev;
+             pci_bmc_dev->uart[i].port.iotype = UPIO_MEM32;
+             pci_bmc_dev->uart[i].port.iobase = 0;
+             pci_bmc_dev->uart[i].port.mapbase =
+                     pci_bmc_dev->message_bar_base + (vuart_ioport << 2);
+             pci_bmc_dev->uart[i].port.membase = 0;
+             pci_bmc_dev->uart[i].port.type = PORT_16550A;
+             pci_bmc_dev->uart[i].port.flags |= (UPF_IOREMAP | UPF_FIXED_PORT | UPF_FIXED_TYPE);
+             pci_bmc_dev->uart[i].port.regshift = 2;
+             ret = serial8250_register_8250_port(&pci_bmc_dev->uart[i]);
+             if (ret < 0) {
+                     dev_err_probe(dev, ret, "Can't setup PCIe VUART\n");
+                     return ret;
+             }
+             pci_bmc_dev->uart_line[i] = ret;
+     }
+     return 0;
+}
+
+static void aspeed_pci_host_bmc_device_release_vuart(struct pci_dev *pdev)
+{
+     struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev);
+     int i;
+
+     for (i = 0; i < VUART_MAX_PARMS; i++) {
+             if (pci_bmc_dev->uart_line[i] >= 0)
+                     serial8250_unregister_port(pci_bmc_dev->uart_line[i]);
+     }
+}
+
+static int aspeed_pci_host_setup(struct pci_dev *pdev)
+{
+     struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev);
+     int rc = 0;

drivers/soc/aspeed/aspeed-host-bmc-dev.c line 126

Quoted 10 lines
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +10 -0
+
+     /* Get Message BAR */
+     pci_bmc_dev->message_bar_base = pci_resource_start(pdev, 1);
+     pci_bmc_dev->message_bar_size = pci_resource_len(pdev, 1);
+     pci_bmc_dev->msg_bar_reg = pci_ioremap_bar(pdev, 1);
+     if (!pci_bmc_dev->msg_bar_reg)
+             return -ENOMEM;
+
+     if (pdev->revision < 0x27) {
+             /* AST2600 ERRTA40: dummy read */

Can you please rather document what problem this is actually solving.

drivers/soc/aspeed/aspeed-host-bmc-dev.c line 130

Quoted 4 lines
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +4 -0
+             (void)__raw_readl((void __iomem *)pci_bmc_dev->msg_bar_reg);
+     } else {
+             /* AST2700 not supported */
+             pr_err("AST2700 detected but not supported");

This logs an error but rc = 0 on return. Perhaps drop the log message and return an appropriate error code?

Quoted 18 lines
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +18 -0
+             goto out_free0;
+     }
+
+     rc = aspeed_pci_bmc_device_setup_vuart(pdev);
+     if (rc) {
+             pr_err("Cannot setup Virtual UART");
+             goto out_free0;
+     }
+
+     return 0;
+
+out_free0:
+     pci_iounmap(pdev, pci_bmc_dev->msg_bar_reg);
+
+     return rc;
+}
+
+static struct aspeed_platform aspeed_pcie_host[] = {

drivers/soc/aspeed/aspeed-host-bmc-dev.c line 158

Quoted 10 lines
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +10 -0
+     { .setup = aspeed_pci_host_setup },
+     { 0 }
+};
+
+static int aspeed_pci_host_bmc_device_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+     struct aspeed_pci_bmc_dev *pci_bmc_dev;
+     int rc = 0;
+
+     pr_info("ASPEED BMC PCI ID %04x:%04x, IRQ=%u\n", pdev->vendor, pdev->device, pdev->irq);

I think we could do without this.

drivers/soc/aspeed/aspeed-host-bmc-dev.c line 168

Quoted 10 lines
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +10 -0
+
+     pci_bmc_dev = devm_kzalloc(&pdev->dev, sizeof(*pci_bmc_dev), GFP_KERNEL);
+     if (!pci_bmc_dev)
+             return -ENOMEM;
+
+     /* Get platform id */
+     pci_bmc_dev->driver_data = ent->driver_data;
+     pci_bmc_dev->platform = &aspeed_pcie_host[ent->driver_data];
+
+     pci_bmc_dev->id = ida_alloc(&bmc_device_ida, GFP_KERNEL);

This seems unnecessary.

Quoted 7 lines
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +7 -0
+     if (pci_bmc_dev->id < 0)
+             return pci_bmc_dev->id;
+
+     rc = pci_enable_device(pdev);
+     if (rc) {
+             dev_err(&pdev->dev, "pci_enable_device() returned error %d\n", rc);
+             return rc;

drivers/soc/aspeed/aspeed-host-bmc-dev.c line 185

Quoted 10 lines
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +10 -0
+     }
+
+     pci_set_master(pdev);
+     pci_set_drvdata(pdev, pci_bmc_dev);
+
+     /* Prepare IRQ resource */
+     aspeed_pci_setup_irq_resource(pdev);
+
+     /* Setup BMC PCI device */
+     rc = pci_bmc_dev->platform->setup(pdev);

As with patch 1 this indirection seems unnecessary.

Quoted 5 lines
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +5 -0
+     if (rc) {
+             dev_err(&pdev->dev, "ASPEED PCIe Host device returned error %d\n", rc);
+             pci_free_irq_vectors(pdev);
+             pci_disable_device(pdev);
+             return rc;

drivers/soc/aspeed/aspeed-host-bmc-dev.c line 200

Quoted 10 lines
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +10 -0
+     }
+
+     return 0;
+}
+
+static void aspeed_pci_host_bmc_device_remove(struct pci_dev *pdev)
+{
+     struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev);
+
+     if (pci_bmc_dev->driver_data == ASPEED)

This condition seems unnecessary as the value shouldn't be anything else.

Quoted 4 lines
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +4 -0
+             aspeed_pci_host_bmc_device_release_vuart(pdev);
+
+     ida_free(&bmc_device_ida, pci_bmc_dev->id);
+

drivers/soc/aspeed/aspeed-host-bmc-dev.c line 214

Quoted 10 lines
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +10 -0
+     pci_iounmap(pdev, pci_bmc_dev->msg_bar_reg);
+
+     pci_free_irq_vectors(pdev);
+     pci_disable_device(pdev);
+}
+
+/**
+ * This table holds the list of (VendorID,DeviceID) supported by this driver
+ *
+ */

I think that's self-evident and prefer the comment be removed.

Quoted 21 lines
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +21 -0
+static struct pci_device_id aspeed_host_bmc_dev_pci_ids[] = {
+     /* ASPEED BMC Device */
+     { PCI_DEVICE(0x1A03, 0x2402), .class = 0xFF0000, .class_mask = 0xFFFF00,
+       .driver_data = ASPEED },
+     {
+             0,
+     }
+};
+
+MODULE_DEVICE_TABLE(pci, aspeed_host_bmc_dev_pci_ids);
+
+static struct pci_driver aspeed_host_bmc_dev_driver = {
+     .name           = DRIVER_NAME,
+     .id_table       = aspeed_host_bmc_dev_pci_ids,
+     .probe          = aspeed_pci_host_bmc_device_probe,
+     .remove         = aspeed_pci_host_bmc_device_remove,
+};
+
+static int __init aspeed_host_bmc_device_init(void)
+{
+     return pci_register_driver(&aspeed_host_bmc_dev_driver);

drivers/soc/aspeed/aspeed-host-bmc-dev.c line 245

Quoted 10 lines
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +10 -0
+}
+
+static void aspeed_host_bmc_device_exit(void)
+{
+     /* unregister pci driver */
+     pci_unregister_driver(&aspeed_host_bmc_dev_driver);
+}
+
+late_initcall(aspeed_host_bmc_device_init);
+module_exit(aspeed_host_bmc_device_exit);

module_driver() could be used here.

Quoted 4 lines
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +4 -0
+
+MODULE_AUTHOR("Ryan Chen <[email protected]>");
+MODULE_DESCRIPTION("ASPEED Host BMC DEVICE Driver");
+MODULE_LICENSE("GPL");
#19 lore raw
In reply to Grégoire Layet
Quoted 3 lines · Grégoire Layet

This is a v2 for upstreaming the VUART over PCIe BMC device driver from the ASPEED kernel SDK (branch master-v6.18) [1]. There are two drivers: a BMC-side driver and a host-side driver.
Together they enable host<->BMC VUART communication via PCIe.

I would like to see somewhere a comment about security. From the replies i got the host can access anything on the LPC bus of the aspeed. What are the implications of that? What are typically on such a bus? TPMs are often there, but does a BMC have a TPM?

Andrew

#20 lore raw
Quoted 2 lines

From the replies i got the host can access anything on the LPC bus of the aspeed.

The PCI-to-LPC bridge only decodes some addresses. In fact, only the following are accessible over PCIe :
- LPC Channel 4, which only supports the KCS protocol
- The 2 VUARTs
- SuperIO-style Mailbox

Regarding the KCS interface over the LPC channel 4,
the BMC driver in this series does not set this up.
It just needs to be activated in the DTS.
Then the host can just start the ipmi_si driver with the correct address. This is the intended usage for IPMI management and is part of the normal trust model of a BMC-managed system.

Here is a summary dump of the PCI BAR1 from the host.
The BAR0 is only used to expose a BMC DRAM region for shared memory access. This v2 removed the memory mapping so BAR0 is not exposed to userspace. The BAR1 is used for the PCI-to-LPC bridge.

Offset          Size        Contents
--------        --------    ------------------------------------
0x0000-0x00B7   184 B       Blank (0xFF)
0x00B8-0x00BF   8 B         SuperIO Index/Data port, mailbox config only
0x00C0-0x0E87   3528 B      Blank (some no decode 0xFF and some reading 0x00)
0x0E88-0x0E8F   8 B         LPC KCS4
0x0E90-0x0FDF   336 B       Blank (0xFF)
0x0FE0-0x0FFF   32 B        VUART1
0x1000-0x2FFFF  188 KiB     Blank (some no decode 0xFF and some reading 0x00)
0x30000-0x3FFFF 64 KiB      Inert region: 256 times repeating reset-default

values, not affected by mailbox activation, not accessed by this driver
The datasheet doesn't explain what this is.

So, the host does not have arbitrary LPC bus access,
it can only access a small subset of it.
The relevant peripherals must be explicitly enabled the PCI bridge to be activated on the BMC to be accessed over PCIe.

Only the specific interfaces listed above are exposed, and each one must be enabled by the BMC.

The security implications are limited.
The host side attack surface is bounded by what the BMC chooses to expose.

Quoted 1 line

TPMs are often there, but does a BMC have a TPM?

The AST2600 chip doesn't have a TPM.
The Asus IPMI card doesn't have a TPM module either. If a similar PCIe add-in IPMI card has a TPM module, it will be accessible to the BMC via the LPC bus.

But this will not be bridged to BAR1 by default
as only the above-listed interfaces are exposed.

However, the host could access the TPM with some specific BMC side configuration of the PCIe BMC Device (PBMC).
That would be a deliberate BMC side firmware decision or bug. This driver doesn't expose a BMC TPM.

#21 lore raw

v3 cover soc: aspeed: Add BMC and host driver for PCIe BMC device

In reply to Grégoire Layet

This is a v3 for upstreaming the VUART over PCIe BMC device driver. The initial driver is from the ASPEED kernel SDK (master-v6.18) [1].

There are two drivers: a BMC-side driver and a host-side driver. Together they enable host<->BMC VUART communication via PCIe.

The host cannot access the BMC's memory. Only the enabled features are accessible. These are the KCS4 channel and 2 VUARTs. There is also some mailbox register functionality also exist for a communication between the host and the BMC. More information can be found here [2].

This v3 mainly modifies the BMC driver and focuses on VUART. The BMC driver is now incorporated into the '8250_aspeed_vuart' driver. A specific flag can be set to indicate that the VUART should be used over PCI. Several changes have been made to the 8250 device tree binding and the 'aspeed-g6.dtsi'.

Changes since v2 [3]:
- Add the aspeed,ast2600-vuart compatible entry to the '8250' DT binding
- Add the aspeed,ast2600-vuart compatible property in 'aspeed-g6.dtsi'
- Add the aspeed,vuart-over-pci boolean property to the '8250' DT binding, only for the aspeed,ast2600-vuart
- Add the aspeed,vuart-over-pci flag to the vuart3 and vuart4
- Add the aspeed,ast2600-vuart compatible property to the '8250_aspeed_vuart' driver
- Add the VUART over PCI code to the '8250_aspeed_vuart' driver
- The v2 review of the host-side BMC driver has been applied.

The host-side driver is still in /soc/aspeed/, as it is very specific to this SoC for me. I didn't receive any feedback on where to put this driver. I can, of course, change this to the relevant location.

It's important to consider that the host driver will do multiple functions. The AST2600 also supports LPC over PCI, with a specific KCS channel (KCS4). This driver should also be used to enable the IPMI automatically via this KCS channel. The UART and the IPMI will depend on the same PCI resource (BAR1), so this must be configured in one driver.

As with v2, VUART data flow and MSI interrupts have been verified working on the test hardware.

Tested on:
BMC:
- Asus IPMI Kommando Card R1.01, AST2600 A3.
- OpenBMC
Host:
- Linux kernel v7.0.0

This v3 only supports AST2600; the AST2700 is not supported by this series.

I would like to know whether I should add the 'lpc-io-reg' and 'lpc-interrupt' values to the vuart3 and vuart4 nodes directly in the 'aspeed-g6.dtsi'. The host driver is not capable of finding the vuart address on his own, so they are hardcoded to 0x3f8 and 0x2f8. It will not work with other adresses, so perhaps they should be in the .dtsi to ensure the correct configuration for the 2 vuart over PCI.

For the interrupt number, my test is working with interrupt = 0 for vuart3 and interrupt = 1 for vuart4. I don't fully understand how the silicon routes MSI numbers to the VUART but the following combination is working :

       | host MSI idx | BMC lpc-interrupts |
VUART3 |      16      |       0            |
VUART4 |      17      |       1            |

The original ASPEED driver used MSI index 15 for the VUART4. I tested every lpc-interrupts on the BMC from 0 to 15, but none of them worked with the host MSI index set to 15.

For me, the silicon only routes the MSI index 16 to VUART3 and 17 to VUART4, and the lpc-interrupt needs to match the 4 least significant bits. I might be wrong on this explanation but the data path is working with those numbers. There is no explanation for any of this in the datasheet.

[1]: https://github.com/AspeedTech-BMC/linux/tree/aspeed-master-v6.18/drivers/soc/aspeed
[2]: https://lore.kernel.org/linux-aspeed/CAFi2wKYOAotiezepDqaR5PZDqDaPKKDfAEnpx5EHC0mL39hy6w@mail.gmail.com/
[3]: https://lore.kernel.org/linux-aspeed/[email protected]/

Grégoire Layet (7):
dt-bindings: serial: 8250: aspeed: add compatible string for ast2600
dt-bindings: serial: 8250: aspeed: add aspeed,vuart-over-pci bool prop
serial: 8250_aspeed_vuart: add aspeed,ast2600-vuart compatible string
serial: 8250_aspeed_vuart: add VUART over PCI
soc: aspeed: add host-side PCIe BMC device driver
ARM: dts: aspeed: g6: Change vuart compatible string for ast2600
ARM: dts: aspeed: g6: add aspeed,vuart-over-pci prop to vuart3 and 4

 .../devicetree/bindings/serial/8250.yaml      |  35 +++-
 arch/arm/boot/dts/aspeed/aspeed-g6.dtsi       |  10 +-
 drivers/soc/aspeed/Kconfig                    |   8 +
 drivers/soc/aspeed/Makefile                   |   1 +
 drivers/soc/aspeed/aspeed-host-bmc-dev.c      | 183 ++++++++++++++++++
 drivers/tty/serial/8250/8250_aspeed_vuart.c   |  87 +++++++++
 6 files changed, 312 insertions(+), 12 deletions(-)
 create mode 100644 drivers/soc/aspeed/aspeed-host-bmc-dev.c
Signature · 1 line
2.54.0
#22 lore raw

PATCH v3 1/7 dt-bindings: serial: 8250: aspeed: add compatible string for ast2600

The ast2600 was using the ast2500 vuart compatible string. This change makes it possible to have ast2600-specific properties.

---
 .../devicetree/bindings/serial/8250.yaml      | 20 +++++++++++--------
 1 file changed, 12 insertions(+), 8 deletions(-)
Documentation/devicetree/bindings/serial/8250.yaml +12 -8
index bb7b9c87a807..3cbd0f532e15 100644
@@ -23,7 +23,9 @@ allOf:
     then:
       properties:
         compatible:
-          const: aspeed,ast2500-vuart
+          anyOf:
+            - const: aspeed,ast2500-vuart
+            - const: aspeed,ast2600-vuart
   - if:
       properties:
         compatible:
@@ -287,17 +289,19 @@ properties:
   aspeed,sirq-polarity-sense:
     $ref: /schemas/types.yaml#/definitions/phandle-array
     description: |
-      Phandle to aspeed,ast2500-scu compatible syscon alongside register
-      offset and bit number to identify how the SIRQ polarity should be
-      configured. One possible data source is the LPC/eSPI mode bit. Only
-      applicable to aspeed,ast2500-vuart.
+      Phandle to aspeed,ast2500-scu or aspeed,ast2600-scu compatible syscon
+      alongside register offset and bit number to identify how the SIRQ
+      polarity should be configured. One possible data source is the LPC/eSPI
+      mode bit. Only applicable to aspeed,ast2500-vuart and
+      aspeed,ast2600-vuart.
     deprecated: true
 
   aspeed,lpc-io-reg:
     $ref: /schemas/types.yaml#/definitions/uint32-array
     maxItems: 1
     description: |
-      The VUART LPC address.  Only applicable to aspeed,ast2500-vuart.
+      The VUART LPC address. Only applicable to aspeed,ast2500-vuart and
+      aspeed,ast2600-vuart.
 
   aspeed,lpc-interrupts:
     $ref: /schemas/types.yaml#/definitions/uint32-array
@@ -305,8 +309,8 @@ properties:
     maxItems: 2
     description: |
       A 2-cell property describing the VUART SIRQ number and SIRQ
-      polarity (IRQ_TYPE_LEVEL_LOW or IRQ_TYPE_LEVEL_HIGH).  Only
-      applicable to aspeed,ast2500-vuart.
+      polarity (IRQ_TYPE_LEVEL_LOW or IRQ_TYPE_LEVEL_HIGH). Only
+      applicable to aspeed,ast2500-vuart and aspeed,ast2600-vuart.
 
 required:
   - reg
Signature · 1 line
2.54.0
#23 lore raw

Re: [PATCH v3 1/7] dt-bindings: serial: 8250: aspeed: add compatible string for ast2600

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Low] The newly introduced compatible string `aspeed,ast2600-vuart` is missing from the top-level…

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] The newly introduced compatible string aspeed,ast2600-vuart is missing from the top-level properties: compatible: oneOf: allowed list. While it was correctly added to the allOf conditional blocks, its absence from the main enumeration will cause device tree schema validation (dt_binding_check and dtbs_check) to fail for any device tree node utilizing this compatible string. --

commit 6f7f111bc5bb5cca5a6591d60c1457c4bf00cb3e
Author: Grégoire Layet <[email protected]>

dt-bindings: serial: 8250: aspeed: add compatible string for ast2600

The ast2600 was using the ast2500 vuart compatible string. This change makes it possible to have ast2600-specific properties.

Documentation/devicetree/bindings/serial/8250.yaml allOf: · line 28

Quoted 12 lines
Documentation/devicetree/bindings/serial/8250.yaml +3 -1
index bb7b9c87a8072..3cbd0f532e151 100644
@@ -23,7 +23,9 @@ allOf:
     then:
       properties:
         compatible:
-          const: aspeed,ast2500-vuart
+          anyOf:
+            - const: aspeed,ast2500-vuart
+            - const: aspeed,ast2600-vuart

[Severity: Low]
Does this compatible string also need to be added to the top-level properties enumeration?

While it is added here in the allOf conditional block, it appears to be missing from the main allowed list, which currently looks like this:

properties:
compatible:
oneOf:
- const: ns8250
- const: ns16450
- const: ns16550
- const: ns16550a
- const: ns16850
- const: aspeed,ast2400-vuart
- const: aspeed,ast2500-vuart

Will this omission cause a regression during device tree schema validation for device trees using the new aspeed,ast2600-vuart compatible string?

[ ... ]

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
#24 lore raw

Re: [PATCH v3 1/7] dt-bindings: serial: 8250: aspeed: add compatible string for ast2600

In reply to Grégoire Layet
Quoted 4 lines · Grégoire Layet

The ast2600 was using the ast2500 vuart compatible string. This change makes it possible to have ast2600-specific properties.

Do not attach (thread) your patchsets to some other threads (unrelated or older versions). This buries them deep in the mailbox and might interfere with applying entire sets. See also:
https://elixir.bootlin.com/linux/v6.16-rc2/source/Documentation/process/submitting-patches.rst#L830

Quoted 9 lines
---
 .../devicetree/bindings/serial/8250.yaml      | 20 +++++++++++--------
 1 file changed, 12 insertions(+), 8 deletions(-)
Documentation/devicetree/bindings/serial/8250.yaml +0 -0
index bb7b9c87a807..3cbd0f532e15 100644

Documentation/devicetree/bindings/serial/8250.yaml allOf: · line 26

Quoted 5 lines
Documentation/devicetree/bindings/serial/8250.yaml +1 -1
@@ -23,7 +23,9 @@ allOf:
     then:
       properties:
         compatible:
-          const: aspeed,ast2500-vuart
+          anyOf:

This should be oneOf (by convention and actually more accurate meaning).

Quoted 31 lines
Documentation/devicetree/bindings/serial/8250.yaml +9 -5
+            - const: aspeed,ast2500-vuart
+            - const: aspeed,ast2600-vuart
   - if:
       properties:
         compatible:
@@ -287,17 +289,19 @@ properties:
   aspeed,sirq-polarity-sense:
     $ref: /schemas/types.yaml#/definitions/phandle-array
     description: |
-      Phandle to aspeed,ast2500-scu compatible syscon alongside register
-      offset and bit number to identify how the SIRQ polarity should be
-      configured. One possible data source is the LPC/eSPI mode bit. Only
-      applicable to aspeed,ast2500-vuart.
+      Phandle to aspeed,ast2500-scu or aspeed,ast2600-scu compatible syscon
+      alongside register offset and bit number to identify how the SIRQ
+      polarity should be configured. One possible data source is the LPC/eSPI
+      mode bit. Only applicable to aspeed,ast2500-vuart and
+      aspeed,ast2600-vuart.
     deprecated: true
 
   aspeed,lpc-io-reg:
     $ref: /schemas/types.yaml#/definitions/uint32-array
     maxItems: 1
     description: |
-      The VUART LPC address.  Only applicable to aspeed,ast2500-vuart.
+      The VUART LPC address. Only applicable to aspeed,ast2500-vuart and
+      aspeed,ast2600-vuart.
 
   aspeed,lpc-interrupts:
     $ref: /schemas/types.yaml#/definitions/uint32-array

Documentation/devicetree/bindings/serial/8250.yaml properties: · line 314

Quoted 8 lines
Documentation/devicetree/bindings/serial/8250.yaml +2 -2
@@ -305,8 +309,8 @@ properties:
     maxItems: 2
     description: |
       A 2-cell property describing the VUART SIRQ number and SIRQ
-      polarity (IRQ_TYPE_LEVEL_LOW or IRQ_TYPE_LEVEL_HIGH).  Only
-      applicable to aspeed,ast2500-vuart.
+      polarity (IRQ_TYPE_LEVEL_LOW or IRQ_TYPE_LEVEL_HIGH). Only
+      applicable to aspeed,ast2500-vuart and aspeed,ast2600-vuart.
 

More important, where is documenting of the actual compatible?

Best regards,
Krzysztof

#25 lore raw

Re: [PATCH v3 1/7] dt-bindings: serial: 8250: aspeed: add compatible string for ast2600

Hi Krzysztof,

Quoted 4 lines

Do not attach (thread) your patchsets to some other threads (unrelated or older versions). This buries them deep in the mailbox and might interfere with applying entire sets. See also:
https://elixir.bootlin.com/linux/v6.16-rc2/source/Documentation/process/submitting-patches.rst#L830

Oh okay sorry I missed this information. Thank's for letting me know !

Quoted 1 line

This should be oneOf (by convention and actually more accurate meaning).

Acknowledged

Quoted 1 line

More important, where is documenting of the actual compatible?

Yes, you are right, I missed it. Will be added in v4.

Best regards,
Grégoire

#26 lore raw

PATCH v3 2/7 dt-bindings: serial: 8250: aspeed: add aspeed,vuart-over-pci bool prop

In reply to Grégoire Layet

The ASPEED AST2600 has 2 VUART accessible over PCI. This boolean can be set to specify if the VUART is used over PCI.

---
 .../devicetree/bindings/serial/8250.yaml          | 15 +++++++++++++++
 1 file changed, 15 insertions(+)
Documentation/devicetree/bindings/serial/8250.yaml +15 -0
index 3cbd0f532e15..b03797f4674d 100644
@@ -26,6 +26,14 @@ allOf:
           anyOf:
             - const: aspeed,ast2500-vuart
             - const: aspeed,ast2600-vuart
+  - if:
+      anyOf:
+        - required:
+            - aspeed,vuart-over-pci
+    then:
+      properties:
+        compatible:
+          const: aspeed,ast2600-vuart
   - if:
       properties:
         compatible:
@@ -312,6 +320,13 @@ properties:
       polarity (IRQ_TYPE_LEVEL_LOW or IRQ_TYPE_LEVEL_HIGH). Only
       applicable to aspeed,ast2500-vuart and aspeed,ast2600-vuart.
 
+  aspeed,vuart-over-pci:
+    type: boolean
+    default: false
+    description: |
+      Enable the VUART over the BMC PCI device. Only applicable to
+      aspeed,ast2600-vuart.
+
 required:
   - reg
   - interrupts
Signature · 1 line
2.54.0
#27 lore raw

Re: [PATCH v3 2/7] dt-bindings: serial: 8250: aspeed: add aspeed,vuart-over-pci bool prop

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Low] Missing `aspeed,ast2600-vuart` in the top-level `compatible` property schema definition, causing…

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] Missing aspeed,ast2600-vuart in the top-level compatible property schema definition, causing dt_binding_check failures. --

commit 33747bb385812ccb653177817f0ed8cba28dbdec
Author: Grégoire Layet <[email protected]>

dt-bindings: serial: 8250: aspeed: add aspeed,vuart-over-pci bool prop

The ASPEED AST2600 has 2 VUART accessible over PCI. This boolean can be set to specify if the VUART is used over PCI.

Quoted 6 lines
Documentation/devicetree/bindings/serial/8250.yaml +0 -0
index 3cbd0f532e151..b03797f4674d4 100644
@@ -26,6 +26,14 @@ allOf:
           anyOf:

Documentation/devicetree/bindings/serial/8250.yaml allOf: · line 36

Quoted 10 lines
Documentation/devicetree/bindings/serial/8250.yaml +8 -0
             - const: aspeed,ast2500-vuart
             - const: aspeed,ast2600-vuart
+  - if:
+      anyOf:
+        - required:
+            - aspeed,vuart-over-pci
+    then:
+      properties:
+        compatible:
+          const: aspeed,ast2600-vuart

[Severity: Low]
Should aspeed,ast2600-vuart also be explicitly added to the top-level
properties: compatible: oneOf: block?

Documentation/devicetree/bindings/serial/8250.yaml:properties.compatible.oneOf:
properties:
compatible:
oneOf:
- const: ns8250
- const: ns16450
- const: ns16550
- const: ns16550a
- const: ns16850
- const: aspeed,ast2400-vuart
- const: aspeed,ast2500-vuart

Device tree nodes using compatible = "aspeed,ast2600-vuart" will be rejected by make dt_binding_check because the string is missing from this top-level definition.

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2
#28 lore raw

Re: [PATCH v3 2/7] dt-bindings: serial: 8250: aspeed: add aspeed,vuart-over-pci bool prop

In reply to Grégoire Layet
Quoted 1 line · Grégoire Layet

The ASPEED AST2600 has 2 VUART accessible over PCI.

What does that mean? How UART can be accessible over PCI bus?

Quoted 27 lines

This boolean can be set to specify if the VUART is used over PCI.

---
 .../devicetree/bindings/serial/8250.yaml          | 15 +++++++++++++++
 1 file changed, 15 insertions(+)
Documentation/devicetree/bindings/serial/8250.yaml +8 -0
index 3cbd0f532e15..b03797f4674d 100644
@@ -26,6 +26,14 @@ allOf:
           anyOf:
             - const: aspeed,ast2500-vuart
             - const: aspeed,ast2600-vuart
+  - if:
+      anyOf:
+        - required:
+            - aspeed,vuart-over-pci
+    then:
+      properties:
+        compatible:
+          const: aspeed,ast2600-vuart
   - if:
       properties:
         compatible:

Documentation/devicetree/bindings/serial/8250.yaml properties: · line 325

Quoted 6 lines
Documentation/devicetree/bindings/serial/8250.yaml +3 -0
@@ -312,6 +320,13 @@ properties:
       polarity (IRQ_TYPE_LEVEL_LOW or IRQ_TYPE_LEVEL_HIGH). Only
       applicable to aspeed,ast2500-vuart and aspeed,ast2600-vuart.
 
+  aspeed,vuart-over-pci:
+    type: boolean
+    default: false

There is no such syntax. Please do not introduce own style. Instead, look at other files how this is done.

Documentation/devicetree/bindings/serial/8250.yaml properties: · line 326

Quoted 1 line
Documentation/devicetree/bindings/serial/8250.yaml +1 -0
+    description: |

Do not need '|' unless you need to preserve formatting.

Documentation/devicetree/bindings/serial/8250.yaml properties: · line 328

Quoted 2 lines
Documentation/devicetree/bindings/serial/8250.yaml +2 -0
+      Enable the VUART over the BMC PCI device. Only applicable to
+      aspeed,ast2600-vuart.

Best regards,
Krzysztof

#29 lore raw

Re: [PATCH v3 2/7] dt-bindings: serial: 8250: aspeed: add aspeed,vuart-over-pci bool prop

Hi Krzysztof,

Quoted 1 line

What does that mean? How UART can be accessible over PCI bus?

It's a Virtual UART. Internally, it's two FIFOs accessible via 8250-compatible register sets on both ends.
There is 4 Virtuals UARTs on the LPC bus of the AST2600 and 2 of them are bridged over the PCI bus.
So, from the host, you can access the 8250 register set on the PCI bus.

Quoted 6 lines

Documentation/devicetree/bindings/serial/8250.yaml properties: · line 325

Quoted 3 lines
Documentation/devicetree/bindings/serial/8250.yaml +3 -0
+  aspeed,vuart-over-pci:
+    type: boolean
+    default: false

There is no such syntax. Please do not introduce own style. Instead, look at other files how this is done.

Ack. I will remove 'default: false' for the v4.

Quoted 3 lines
Quoted 1 line

+ description: |

Do not need '|' unless you need to preserve formatting.

Acknowledged

Best regards,
Grégoire

#30 lore raw

Re: [PATCH v3 2/7] dt-bindings: serial: 8250: aspeed: add aspeed,vuart-over-pci bool prop

Quoted 6 lines · Grégoire Layet

Hi Krzysztof,

Quoted 1 line

What does that mean? How UART can be accessible over PCI bus?

It's a Virtual UART. Internally, it's two FIFOs accessible via 8250-compatible register sets on both ends.

I do not know what is Virtual UART...

Quoted 3 lines

There is 4 Virtuals UARTs on the LPC bus of the AST2600 and 2 of them are bridged over the PCI bus.
So, from the host, you can access the 8250 register set on the PCI bus.

You mean these appear (or are) as PCI devices?

Quoted 1 line

Best regards,
Krzysztof

#31 lore raw

Re: [PATCH v3 2/7] dt-bindings: serial: 8250: aspeed: add aspeed,vuart-over-pci bool prop

Hi Krzysztof,

Quoted 4 lines
Quoted 2 lines

It's a Virtual UART. Internally, it's two FIFOs accessible via 8250-compatible register sets on both ends.

I do not know what is Virtual UART...

Yes the name of ASPEED is a bit weird, it means that it is not a real UART. It is two 8250-compatible register sets, and the data path is handled by two hardware FIFOs (one per direction).

Quoted 5 lines
Quoted 3 lines

There is 4 Virtuals UARTs on the LPC bus of the AST2600 and 2 of them are bridged over the PCI bus.
So, from the host, you can access the 8250 register set on the PCI bus.

You mean these appear (or are) as PCI devices?

Yes but not as a UART devices.
The two VUART are accessible under the same PCIe BMC device, at the VUART addresses configured on the BMC. They are accessible on the BAR1 of the PCIe BMC device.
There is a 2 bit left shift between the addresses of the registers on the BMC LPC bus and the addresses accessible over the PCI device. 0x3F8 on the BMC is accessible at BAR1 0xFE0 over the PCI device.

The PCIe BMC Device is one PCI device where you can access several peripherals. It's not one PCI device per VUART.

For example, you can also enable the KCS channel 4 and it will be also accessible via the BAR1 of the PCI BMC device. KCS is a protocol used for IPMI.

Only these two peripherals can be accessed over the PCI BMC device and they need to be enabled.
The host cannot access everything on the LPC bus of the BMC.

Best regards,
Grégoire

#32 lore raw

PATCH v3 3/7 serial: 8250_aspeed_vuart: add aspeed,ast2600-vuart compatible string

In reply to Grégoire Layet

Makes the driver compatible with the ast2600-vuart. This enables specific configuration for the AST2600.

---
 drivers/tty/serial/8250/8250_aspeed_vuart.c | 1 +
 1 file changed, 1 insertion(+)
drivers/tty/serial/8250/8250_aspeed_vuart.c +1 -0
index 26fc0464f1cc..6afa2f4057e1 100644
@@ -560,6 +560,7 @@ static void aspeed_vuart_remove(struct platform_device *pdev)
 static const struct of_device_id aspeed_vuart_table[] = {
 	{ .compatible = "aspeed,ast2400-vuart" },
 	{ .compatible = "aspeed,ast2500-vuart" },
+	{ .compatible = "aspeed,ast2600-vuart" },
 	{ },
 };
 MODULE_DEVICE_TABLE(of, aspeed_vuart_table);
Signature · 1 line
2.54.0
#33 lore raw

Re: [PATCH v3 3/7] serial: 8250_aspeed_vuart: add aspeed,ast2600-vuart compatible string

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:

New issues:
- [High] Direct return in the newly added AST2600 PCI initialization logic bypasses all resource cleanup.

Pre-existing issues:
- [High] Missing serial port unregistration and timer cleanup on probe error paths causes resource leaks and a Use-After-Free.
- [High] Sysfs attributes are created prematurely in probe() and removed late in remove(), allowing NULL pointer dereference and unmapped memory access.
- [High] Incorrect teardown order in remove() deletes the timer before unregistering the port, allowing the timer to be re-armed. --

commit 0b81ae92f1a0f52b8cec821070559651477025dd
Author: Grégoire Layet <[email protected]>

serial: 8250_aspeed_vuart: add aspeed,ast2600-vuart compatible string

Makes the driver compatible with the ast2600-vuart. This enables specific configuration for the AST2600.

drivers/tty/serial/8250/8250_aspeed_vuart.c static void aspeed_vuart_remove(struct platform_device *pdev) · line 563

Quoted 9 lines
drivers/tty/serial/8250/8250_aspeed_vuart.c +1 -0
index 26fc0464f1cc2..6afa2f4057e1b 100644
@@ -560,6 +560,7 @@ static void aspeed_vuart_remove(struct platform_device *pdev)
 static const struct of_device_id aspeed_vuart_table[] = {
 	{ .compatible = "aspeed,ast2400-vuart" },
 	{ .compatible = "aspeed,ast2500-vuart" },
+	{ .compatible = "aspeed,ast2600-vuart" },

[Severity: High]
Does the AST2600 PCI initialization logic bypass the error handling labels in aspeed_vuart_probe()?

If aspeed_ast2600_vuart_over_pci_set_enabled() fails, the code returns directly:

drivers/tty/serial/8250/8250_aspeed_vuart.c:aspeed_vuart_probe() {
    ...
    if (of_device_is_compatible(dev->of_node, "aspeed,ast2600-vuart") &&
        of_property_read_bool(dev->of_node, "aspeed,vuart-over-pci")) {
        rc = aspeed_ast2600_vuart_over_pci_set_enabled(pdev);
        if (rc) {
            dev_err(dev, "could not enable VUART over PCI\n");
            return rc;
        }
    }
    return 0;

err_sysfs_remove:

    sysfs_remove_group(&vuart->dev->kobj, &aspeed_vuart_attr_group);
    return rc;
}

This direct return bypasses the err_sysfs_remove cleanup label, which would leave the sysfs group leaked and the UART port and timer active with pointers to the devm-freed vuart structure.

[Severity: High]
This isn't a bug introduced by this patch, but does aspeed_vuart_probe() leak resources and cause a use-after-free on other error paths?

If the probe fails and jumps to err_sysfs_remove, it removes the sysfs group but fails to call serial8250_unregister_port() or timer_delete_sync():

drivers/tty/serial/8250/8250_aspeed_vuart.c:aspeed_vuart_probe() {
    ...
    rc = serial8250_register_8250_port(&port);
    ...
err_sysfs_remove:
    sysfs_remove_group(&vuart->dev->kobj, &aspeed_vuart_attr_group);
    return rc;
}

Because vuart is devm-allocated, it will be freed upon probe failure, leaving the UART port registered with private_data pointing to freed memory.

[Severity: High]
This is a pre-existing issue, but are the sysfs attributes exposed too early in probe() and removed too late in remove()?

In aspeed_vuart_probe(), sysfs_create_group() is called before the driver data is set via platform_set_drvdata():

drivers/tty/serial/8250/8250_aspeed_vuart.c:aspeed_vuart_probe() {
    ...
    rc = sysfs_create_group(&vuart->dev->kobj, &aspeed_vuart_attr_group);
    ...
    platform_set_drvdata(pdev, vuart);
    ...
}

If userspace reads attributes like lpc_address during this window, dev_get_drvdata() returns NULL which is then dereferenced in the callback.

Additionally, in aspeed_vuart_remove(), sysfs_remove_group() is called after serial8250_unregister_port():

drivers/tty/serial/8250/8250_aspeed_vuart.c:aspeed_vuart_remove() {
    ...
    serial8250_unregister_port(vuart->line);
    sysfs_remove_group(&vuart->dev->kobj, &aspeed_vuart_attr_group);
}

Because unregistering the port calls iounmap(), any concurrent sysfs access in this window could access unmapped I/O memory.

[Severity: High]
This is also a pre-existing issue, but does aspeed_vuart_remove() delete the unthrottle timer before disabling the interrupt source that re-arms it?

drivers/tty/serial/8250/8250_aspeed_vuart.c:aspeed_vuart_remove() {
    ...
    timer_delete_sync(&vuart->unthrottle_timer);
    aspeed_vuart_set_enabled(vuart, false);
    serial8250_unregister_port(vuart->line);
    ...
}

At the point timer_delete_sync() is called, the UART port is still active. If an RX interrupt triggers concurrently, aspeed_vuart_handle_irq() can call mod_timer() and re-arm it. The re-armed timer could then fire after the devm-allocated vuart structure is freed.

Quoted 3 lines
drivers/tty/serial/8250/8250_aspeed_vuart.c +0 -0
 	{ },
 };
 MODULE_DEVICE_TABLE(of, aspeed_vuart_table);
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=3
#34 lore raw

PATCH v3 4/7 serial: 8250_aspeed_vuart: add VUART over PCI

In reply to Grégoire Layet

This patch enables the VUART over PCI possible for the AST2600. This is only activated if the 'aspeed,vuart-over-pci' property flag is set on an 'ast2600-vuart' compatible node.

The AST2600 has 2 VUART that are usable over PCI. These are the VUART3 and VUART4 in the 'apseed-g6.dtsi'.

This code sets the BMC PCI device enables
bits, sets the PCI class code to MFD device and configures MSI interrupts.

There is no disable function. Removing this driver should not disable
the BMC PCI device, as other drivers could use it.
However, if all the drivers using it are removed, the
BMC PCI device will still be activated, which is not ideal. Realistically though, this is not a use case for a BMC, the drivers will never be removed.

This is useful on PCIe BMC expansion cards that use the AST2600, such as the ASUS Kommando IPMI Expansion Card.

Registers initialisation taken from ASPEED 6.18 Kernel SDK. Return code checks were added to each register write. The code has been simplified and macros have been added.

The ASPEED_SCUC24 regmap update is missing a macro for 'BIT(14)'. I was unable to determine the purpose of this bit. In the AST2600 A3 datasheet it is marked as 'reserved'. It is only used on the other revision. As I only have the AST2600A3, I was unable to try this code path.

---
 drivers/tty/serial/8250/8250_aspeed_vuart.c | 86 +++++++++++++++++++++
 1 file changed, 86 insertions(+)
drivers/tty/serial/8250/8250_aspeed_vuart.c +86 -0
index 6afa2f4057e1..e204e26fa173 100644
@@ -32,6 +32,27 @@
 #define ASPEED_VUART_DEFAULT_SIRQ	4
 #define ASPEED_VUART_DEFAULT_SIRQ_POLARITY	IRQ_TYPE_LEVEL_LOW
 
+#define ASPEED_SCU_SILICON_REVISION_ID			0x04
+#define AST2600A3_REVISION_ID				0x05030303
+
+#define ASPEED_SCUC24			0xC24
+#define  ASPEED_SCUC24_MSI_ROUTING_MASK			GENMASK(11, 10)
+#define  ASPEED_SCUC24_MSI_ROUTING_PCIe2LPC_PCIDEV1		(0x2 << 10)
+#define  ASPEED_SCUC24_PCIDEV1_INTX_MSI_HOST2BMC_EN		BIT(18)
+#define  ASPEED_SCUC24_PCIDEV1_INTX_MSI_SCU560_EN			BIT(17)
+
+
+#define ASPEED_SCU_PCIE_CONF_CTRL	0xC20
+#define  SCU_PCIE_CONF_BMC_DEV_EN					BIT(8)
+#define  SCU_PCIE_CONF_BMC_DEV_EN_MMIO				BIT(9)
+#define  SCU_PCIE_CONF_BMC_DEV_EN_MSI				BIT(11)
+#define  SCU_PCIE_CONF_BMC_DEV_EN_IRQ				BIT(13)
+#define  SCU_PCIE_CONF_BMC_DEV_EN_PCIE_BUS_MASTER	BIT(14)
+#define  SCU_PCIE_CONF_BMC_DEV_EN_E2L				BIT(15)
+#define  SCU_PCIE_CONF_BMC_DEV_EN_LPC_DECODE		BIT(21)
+
+#define ASPEED_SCU_BMC_DEV_CLASS	0xC68
+
 struct aspeed_vuart {
 	struct device		*dev;
 	int			line;
@@ -412,6 +433,62 @@ static int aspeed_vuart_map_irq_polarity(u32 dt)
 	}
 }
 
+static int aspeed_ast2600_vuart_over_pci_set_enabled(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	u32 silicon_revision_id;
+	struct regmap *scu;
+	int rc;
+
+	u32 pcie_config_ctl = SCU_PCIE_CONF_BMC_DEV_EN_IRQ |
+						SCU_PCIE_CONF_BMC_DEV_EN_MMIO |
+						SCU_PCIE_CONF_BMC_DEV_EN_MSI |
+						SCU_PCIE_CONF_BMC_DEV_EN_PCIE_BUS_MASTER |
+						SCU_PCIE_CONF_BMC_DEV_EN_E2L |
+						SCU_PCIE_CONF_BMC_DEV_EN_LPC_DECODE |
+						SCU_PCIE_CONF_BMC_DEV_EN;
+
+	scu = syscon_regmap_lookup_by_phandle(dev->of_node, "clocks");
+	if (IS_ERR(scu)) {
+		dev_err(&pdev->dev, "failed to find SCU regmap\n");
+		return PTR_ERR(scu);
+	}
+
+	/* update class code to be an MFD device */
+	if (regmap_write(scu, ASPEED_SCU_BMC_DEV_CLASS, 0xff000000)) {
+		dev_err(dev, "could not set PCI class code\n");
+		return -EIO;
+	}
+
+	if (regmap_update_bits(scu, ASPEED_SCU_PCIE_CONF_CTRL,
+			   pcie_config_ctl, pcie_config_ctl)) {
+		dev_err(dev, "could not set PCIe configuration\n");
+		return -EIO;
+	}
+
+	if (regmap_read(scu, ASPEED_SCU_SILICON_REVISION_ID, &silicon_revision_id)) {
+		dev_err(dev, "could not read silicon revision\n");
+		return -EIO;
+	}
+
+	if (silicon_revision_id == AST2600A3_REVISION_ID)
+		rc = regmap_update_bits(scu, ASPEED_SCUC24,
+				   ASPEED_SCUC24_PCIDEV1_INTX_MSI_HOST2BMC_EN | ASPEED_SCUC24_MSI_ROUTING_MASK,
+				   ASPEED_SCUC24_PCIDEV1_INTX_MSI_HOST2BMC_EN | ASPEED_SCUC24_MSI_ROUTING_PCIe2LPC_PCIDEV1);
+	else
+		rc = regmap_update_bits(scu, ASPEED_SCUC24,
+					/* The bit 14 is reserved in the Datasheet, so we can't say what it does. This revision has not been tested */
+				   ASPEED_SCUC24_PCIDEV1_INTX_MSI_SCU560_EN | BIT(14) | ASPEED_SCUC24_MSI_ROUTING_MASK,
+				   ASPEED_SCUC24_PCIDEV1_INTX_MSI_SCU560_EN | BIT(14) | ASPEED_SCUC24_MSI_ROUTING_PCIe2LPC_PCIDEV1);
+	if (rc) {
+		dev_err(dev, "could not set PCI device 1 MSI interrupt routing\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+
 static int aspeed_vuart_probe(struct platform_device *pdev)
 {
 	struct of_phandle_args sirq_polarity_sense_args;
@@ -540,6 +617,15 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
 	aspeed_vuart_set_host_tx_discard(vuart, true);
 	platform_set_drvdata(pdev, vuart);
 
+	if (of_device_is_compatible(dev->of_node, "aspeed,ast2600-vuart") &&
+		of_property_read_bool(dev->of_node, "aspeed,vuart-over-pci")) {
+		rc = aspeed_ast2600_vuart_over_pci_set_enabled(pdev);
+		if (rc) {
+			dev_err(dev, "could not enable VUART over PCI\n");
+			return rc;
+		}
+	}
+
 	return 0;
 
 err_sysfs_remove:
Signature · 1 line
2.54.0
#35 lore raw

Re: [PATCH v3 4/7] serial: 8250_aspeed_vuart: add VUART over PCI

Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:

Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:

New issues:
- [High] The newly added error path directly returns on failure, bypassing sysfs cleanup and leaving the hardware enabled and port registered.
- [Medium] Brittle lookup of the SCU syscon regmap by parsing the "clocks" property.
- [Medium] Setting untested and reserved bits in SCU registers.

Pre-existing issues:
- [High] Preexisting error paths fail to unregister the 8250 serial port and delete the timer on probe failure, leading to a Use-After-Free.
- [High] Unprotected Read-Modify-Write operations on shared hardware registers.
- [High] Sysfs files and TTY port are exposed to userspace before driver data is initialized.
--

commit 277ed031956064f236c5536027c1f37b4a76d71d
Author: Grégoire Layet <[email protected]>

serial: 8250_aspeed_vuart: add VUART over PCI

This commit adds support for VUART over PCI on the AST2600 platform. It configures the BMC PCI device enables, sets the PCI class code to MFD, and configures MSI interrupts based on the silicon revision.

Quoted 4 lines
drivers/tty/serial/8250/8250_aspeed_vuart.c +0 -0
index 6afa2f4057e1b..e204e26fa173b 100644

[ ... ]

Quoted 8 lines
drivers/tty/serial/8250/8250_aspeed_vuart.c +7 -0
@@ -412,6 +433,62 @@ static int aspeed_vuart_map_irq_polarity(u32 dt)
+static int aspeed_ast2600_vuart_over_pci_set_enabled(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	u32 silicon_revision_id;
+	struct regmap *scu;
+	int rc;
+

drivers/tty/serial/8250/8250_aspeed_vuart.c static int aspeed_vuart_map_irq_polarity(u32 dt) · line 449

Quoted 10 lines
drivers/tty/serial/8250/8250_aspeed_vuart.c +10 -0
+	u32 pcie_config_ctl = SCU_PCIE_CONF_BMC_DEV_EN_IRQ |
+						SCU_PCIE_CONF_BMC_DEV_EN_MMIO |
+						SCU_PCIE_CONF_BMC_DEV_EN_MSI |
+						SCU_PCIE_CONF_BMC_DEV_EN_PCIE_BUS_MASTER |
+						SCU_PCIE_CONF_BMC_DEV_EN_E2L |
+						SCU_PCIE_CONF_BMC_DEV_EN_LPC_DECODE |
+						SCU_PCIE_CONF_BMC_DEV_EN;
+
+	scu = syscon_regmap_lookup_by_phandle(dev->of_node, "clocks");
+	if (IS_ERR(scu)) {

[Severity: Medium]
Will this break if any clock multiplexer or intermediate clock controller is inserted between the SCU and the VUART?

This code uses syscon_regmap_lookup_by_phandle() to fetch the SCU regmap by parsing the "clocks" property. While this may happen to work if the SCU is the direct clock provider, does this conflate the clock provider bindings with syscon mappings?

Quoted 3 lines
drivers/tty/serial/8250/8250_aspeed_vuart.c +3 -0
+		dev_err(&pdev->dev, "failed to find SCU regmap\n");
+		return PTR_ERR(scu);
+	}

[ ... ]

drivers/tty/serial/8250/8250_aspeed_vuart.c static int aspeed_vuart_map_irq_polarity(u32 dt) · line 481

Quoted 8 lines
drivers/tty/serial/8250/8250_aspeed_vuart.c +8 -0
+	if (silicon_revision_id == AST2600A3_REVISION_ID)
+		rc = regmap_update_bits(scu, ASPEED_SCUC24,
+				   ASPEED_SCUC24_PCIDEV1_INTX_MSI_HOST2BMC_EN | ASPEED_SCUC24_MSI_ROUTING_MASK,
+				   ASPEED_SCUC24_PCIDEV1_INTX_MSI_HOST2BMC_EN | ASPEED_SCUC24_MSI_ROUTING_PCIe2LPC_PCIDEV1);
+	else
+		rc = regmap_update_bits(scu, ASPEED_SCUC24,
+					/* The bit 14 is reserved in the Datasheet, so we can't say what it does. This revision has not been tested */
+				   ASPEED_SCUC24_PCIDEV1_INTX_MSI_SCU560_EN | BIT(14) | ASPEED_SCUC24_MSI_ROUTING_MASK,

[Severity: Medium]
Is it safe to write BIT(14) into ASPEED_SCUC24 when it is undocumented and reserved?

The comment indicates the bit's purpose is unknown and this revision is untested. Can setting this undocumented, reserved bit trigger unpredictable hardware behavior on other silicon revisions?

Quoted 8 lines
drivers/tty/serial/8250/8250_aspeed_vuart.c +8 -0
+				   ASPEED_SCUC24_PCIDEV1_INTX_MSI_SCU560_EN | BIT(14) | ASPEED_SCUC24_MSI_ROUTING_PCIe2LPC_PCIDEV1);
+	if (rc) {
+		dev_err(dev, "could not set PCI device 1 MSI interrupt routing\n");
+		return -EIO;
+	}
+
+	return 0;
+}

[ ... ]

drivers/tty/serial/8250/8250_aspeed_vuart.c static int aspeed_vuart_probe(struct platform_device *pdev) · line 617

Quoted 2 lines
drivers/tty/serial/8250/8250_aspeed_vuart.c +0 -0
@@ -540,6 +617,15 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
 	aspeed_vuart_set_host_tx_discard(vuart, true);

[Severity: High]
This isn't a bug introduced by this patch, but can concurrent access clobber register modifications?

Functions like aspeed_vuart_set_host_tx_discard() and aspeed_vuart_set_sirq_polarity() perform read-modify-write operations on ASPEED_VUART_GCRA. Does a concurrent sysfs write and TTY port open/close cause a race condition here, since these are invoked from contexts with different locks (or no locks)?

drivers/tty/serial/8250/8250_aspeed_vuart.c static int aspeed_vuart_probe(struct platform_device *pdev) · line 618

Quoted 1 line
drivers/tty/serial/8250/8250_aspeed_vuart.c +0 -0
 	platform_set_drvdata(pdev, vuart);

[Severity: High]
This isn't a bug introduced by this patch, but does the delay in calling platform_set_drvdata() expose userspace to a null pointer dereference?

In aspeed_vuart_probe(), sysfs_create_group() is called very early. If a concurrent userspace process reads the sysfs files, invoking lpc_address_show() before platform_set_drvdata() is called here, it will retrieve a null pointer and immediately dereference it.

drivers/tty/serial/8250/8250_aspeed_vuart.c static int aspeed_vuart_probe(struct platform_device *pdev) · line 625

Quoted 7 lines
drivers/tty/serial/8250/8250_aspeed_vuart.c +6 -0
+	if (of_device_is_compatible(dev->of_node, "aspeed,ast2600-vuart") &&
+		of_property_read_bool(dev->of_node, "aspeed,vuart-over-pci")) {
+		rc = aspeed_ast2600_vuart_over_pci_set_enabled(pdev);
+		if (rc) {
+			dev_err(dev, "could not enable VUART over PCI\n");
+			return rc;

[Severity: High]
Does this direct return bypass necessary cleanup logic and leave the hardware enabled?

By returning rc directly instead of jumping to a cleanup label, the sysfs group aspeed_vuart_attr_group is leaked. Furthermore, does this bypass unregistering the 8250 port and leave the VUART active despite probe failure, since aspeed_vuart_set_enabled(vuart, true) was called earlier?

Quoted 9 lines
drivers/tty/serial/8250/8250_aspeed_vuart.c +3 -0
+		}
+	}
+
 	return 0;
 
 err_sysfs_remove:
 	sysfs_remove_group(&vuart->dev->kobj, &aspeed_vuart_attr_group);

return rc;
}

[Severity: High]
This isn't a bug introduced by this patch, but does this error path lead to a use-after-free?

The err_sysfs_remove block cleans up sysfs attributes but entirely omits calling serial8250_unregister_port() and timer_delete_sync(). Because the driver uses devres, the vuart structure will be freed upon probe failure. Since the port remains actively registered, any subsequent access to the port via TTY operations will dereference this freed memory.

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=4
#36 lore raw

PATCH v3 5/7 soc: aspeed: add host-side PCIe BMC device driver

In reply to Grégoire Layet

Add support for VUART over PCIe between BMC and host. This add host side driver.
This only support the AST2600.

Taken from ASPEED 6.18 Kernel SDK and trimmed down.

The host can't detect the VUART adresses, they are forced at 0x3f8 and 0x2f8, similar from the initial ASPEED driver.

The MSI vector index has been changed for the VUART2 from 15 to 17. The index 15 used in the initial driver was not working.

Data path in both direction is tested on both VUART.

---
 drivers/soc/aspeed/Kconfig               |   8 +
 drivers/soc/aspeed/Makefile              |   1 +
 drivers/soc/aspeed/aspeed-host-bmc-dev.c | 183 +++++++++++++++++++++++
 3 files changed, 192 insertions(+)
 create mode 100644 drivers/soc/aspeed/aspeed-host-bmc-dev.c
drivers/soc/aspeed/Kconfig +8 -0
index 63a656449a1a..ebd023b10701 100644
@@ -4,6 +4,14 @@ if ARCH_ASPEED || COMPILE_TEST
 
 menu "ASPEED SoC drivers"
 
+config ASPEED_HOST_BMC_DEV
+	tristate "ASPEED Host BMC Device"
+	depends on PCI
+	depends on SERIAL_8250
+	help
+	  Enable support for the ASPEED AST2600 BMC Device on the Host.
+	  This configure the PCIe and setup two 8250 compatible VUART ports.
+
 config ASPEED_LPC_CTRL
 	tristate "ASPEED LPC firmware cycle control"
 	select REGMAP
drivers/soc/aspeed/Makefile +1 -0
index b35d74592964..c515e163eab7 100644
@@ -1,4 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_ASPEED_HOST_BMC_DEV)	+= aspeed-host-bmc-dev.o
 obj-$(CONFIG_ASPEED_LPC_CTRL)		+= aspeed-lpc-ctrl.o
 obj-$(CONFIG_ASPEED_LPC_SNOOP)		+= aspeed-lpc-snoop.o
 obj-$(CONFIG_ASPEED_UART_ROUTING)	+= aspeed-uart-routing.o
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +183 -0

183 lines not on this page · raw message

Signature · 1 line
2.54.0
#37 lore raw

Re: [PATCH v3 5/7] soc: aspeed: add host-side PCIe BMC device driver

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider: - [High] Modifying a shared static global array on IRQ allocation fallback permanently corrupts the driver…

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Modifying a shared static global array on IRQ allocation fallback permanently corrupts the driver state for all subsequent devices and creates a data race.
- [High] The driver mishandles pci_alloc_irq_vectors() return values, leading to silent probe successes with invalid IRQs or out-of-bounds vector accesses that trigger kernel warnings.
- [Medium] Truncation of a 64-bit PCI physical address due to storing it in an unsigned long on 32-bit architectures.
--

commit 64de7243e0e8e8cd9ac72d04be5ef937e8143347
Author: Grégoire Layet <[email protected]>

soc: aspeed: add host-side PCIe BMC device driver

Add support for VUART over PCIe between BMC and host.
This configures the PCIe and sets up two 8250 compatible VUART ports.

Quoted 5 lines
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +0 -0
new file mode 100644
index 0000000000000..3160b6aedb5b6

[ ... ]

drivers/soc/aspeed/aspeed-host-bmc-dev.c line 30

Quoted 9 lines
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +9 -0
+static int vuart_msi_index[2] = { 16, 17 };
+static int vuart_port_addr[2] = {0x3f8, 0x2f8};
+
+struct aspeed_pci_bmc_dev {
+	struct device *dev;
+	kernel_ulong_t driver_data;
+	int id;
+
+	unsigned long message_bar_base;

[Severity: Medium]
Does storing the BAR address in an unsigned long truncate 64-bit physical addresses on 32-bit architectures with PAE/LPAE?

pci_resource_start() returns a resource_size_t, which could be 64-bit, potentially leading to incorrect I/O memory mapping here.

Quoted 4 lines
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +4 -0
+
+	struct uart_8250_port uart[2];
+	int uart_line[2];
+

drivers/soc/aspeed/aspeed-host-bmc-dev.c line 44

Quoted 10 lines
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +10 -0
+	int *msi_idx_table;
+};
+
+static void aspeed_pci_setup_irq_resource(struct pci_dev *pdev)
+{
+	struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev);
+
+	pci_bmc_dev->msi_idx_table = vuart_msi_index;
+
+	if (pci_alloc_irq_vectors(pdev, 1, BMC_MULTI_MSI, PCI_IRQ_INTX | PCI_IRQ_MSI) <= 1)

[Severity: High]
Can this condition mishandle partial allocations and negative error codes?

If pci_alloc_irq_vectors() partially succeeds and returns a value between 2 and 16, the <= 1 check evaluates to false. This leaves the indices at 16 and 17, but pci_irq_vector() will later trigger a WARN_ON_ONCE out-of-bounds check in the PCI core when it tries to access index 16.

Additionally, if it fails entirely and returns a negative error, the check passes, but the probe doesn't abort. Does this result in silently registering the 8250 UART with an invalid IRQ?

drivers/soc/aspeed/aspeed-host-bmc-dev.c line 46

Quoted 2 lines
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +2 -0
+		/* If pci_alloc fail, set all msi index to the first vector */
+		memset(pci_bmc_dev->msi_idx_table, 0, sizeof(vuart_msi_index));

[Severity: High]
Does this memset corrupt the driver state for all subsequent instances?

Because pci_bmc_dev->msi_idx_table points directly to the static global array vuart_msi_index, writing zeroes here permanently overwrites the shared array.

If multiple ASPEED PCI devices are probed, or if the device is probed again later, will the indices be permanently stuck at 0?

Quoted 1 line

+}

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=5
#38 lore raw

PATCH v3 6/7 ARM: dts: aspeed: g6: Change vuart compatible string for ast2600

In reply to Grégoire Layet

Use the ast2600 compatible string.
This makes it more precise and enables specific ast2600 properties. Still use the ast2500 compatible string as a fallback.

---
 arch/arm/boot/dts/aspeed/aspeed-g6.dtsi | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
arch/arm/boot/dts/aspeed/aspeed-g6.dtsi +4 -4
index 56bb3b0444f7..7c02633f2bd6 100644
@@ -707,7 +707,7 @@ emmc: sdhci@1e750100 {
 			};
 
 			vuart1: serial@1e787000 {
-				compatible = "aspeed,ast2500-vuart";
+				compatible = "aspeed,ast2600-vuart", "aspeed,ast2500-vuart";
 				reg = <0x1e787000 0x40>;
 				reg-shift = <2>;
 				interrupts = <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
@@ -717,7 +717,7 @@ vuart1: serial@1e787000 {
 			};
 
 			vuart3: serial@1e787800 {
-				compatible = "aspeed,ast2500-vuart";
+				compatible = "aspeed,ast2600-vuart", "aspeed,ast2500-vuart";
 				reg = <0x1e787800 0x40>;
 				reg-shift = <2>;
 				interrupts = <GIC_SPI 180 IRQ_TYPE_LEVEL_HIGH>;
@@ -727,7 +727,7 @@ vuart3: serial@1e787800 {
 			};
 
 			vuart2: serial@1e788000 {
-				compatible = "aspeed,ast2500-vuart";
+				compatible = "aspeed,ast2600-vuart", "aspeed,ast2500-vuart";
 				reg = <0x1e788000 0x40>;
 				reg-shift = <2>;
 				interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
@@ -737,7 +737,7 @@ vuart2: serial@1e788000 {
 			};
 
 			vuart4: serial@1e788800 {
-				compatible = "aspeed,ast2500-vuart";
+				compatible = "aspeed,ast2600-vuart", "aspeed,ast2500-vuart";
 				reg = <0x1e788800 0x40>;
 				reg-shift = <2>;
 				interrupts = <GIC_SPI 181 IRQ_TYPE_LEVEL_HIGH>;
Signature · 1 line
2.54.0
#39 lore raw

Re: [PATCH v3 6/7] ARM: dts: aspeed: g6: Change vuart compatible string for ast2600

Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:

Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:

New issues:
- [High] Newly introduced error path completely bypasses all probe cleanup.
- [High] Modifying a static global array when MSI allocation fails causes state corruption.
- [High] Assuming index 16 and 17 are unconditionally valid for partially allocated MSI vectors.
- [Medium] Device Tree Binding Schema Validation Failure
- [Medium] Using the 'clocks' property as a syscon phandle violates DT semantics.

Pre-existing issues:
- [High] Probe error paths fail to unregister the 8250 serial port, leading to Use-After-Free. --

commit cd4f0040d97e2d9918c8ecf27108ed2de48871b7
Author: Grégoire Layet <[email protected]>

ARM: dts: aspeed: g6: Change vuart compatible string for ast2600

Use the ast2600 compatible string.
This makes it more precise and enables specific ast2600 properties. Still use the ast2500 compatible string as a fallback.

Quoted 12 lines
Documentation/devicetree/bindings/serial/8250.yaml +3 -1
index bb7b9c87a8072..b03797f4674d4 100644
@@ -23,7 +23,17 @@ allOf:
     then:
       properties:
         compatible:
-          const: aspeed,ast2500-vuart
+          anyOf:
+            - const: aspeed,ast2500-vuart
+            - const: aspeed,ast2600-vuart

[ ... ]

arch/arm/boot/dts/aspeed/aspeed-g6.dtsi emmc: sdhci@1e750100 { · line 701

Quoted 10 lines
arch/arm/boot/dts/aspeed/aspeed-g6.dtsi +1 -1
index 189bc3bbb47c9..5ff52697e8bb4 100644
@@ -698,7 +698,7 @@ emmc: sdhci@1e750100 {
 			};
 
 			vuart1: serial@1e787000 {
-				compatible = "aspeed,ast2500-vuart";
+				compatible = "aspeed,ast2600-vuart", "aspeed,ast2500-vuart";

[Severity: Medium]
Will this pass device tree schema validation (dtbs_check)? The binding in 8250.yaml defines the compatible property as anyOf with single const strings, meaning it expects exactly one of those strings. The device tree uses an array of two strings. Should the schema be updated with an items array definition to accept this combination?

[ ... ]

Quoted 5 lines
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +0 -0
new file mode 100644
index 0000000000000..3160b6aedb5b6

[ ... ]

Quoted 1 line

+static int vuart_msi_index[2] = { 16, 17 };

[ ... ]

drivers/soc/aspeed/aspeed-host-bmc-dev.c

Quoted 9 lines
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +9 -0
+static void aspeed_pci_setup_irq_resource(struct pci_dev *pdev)
+{
+	struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev);
+
+	pci_bmc_dev->msi_idx_table = vuart_msi_index;
+
+	if (pci_alloc_irq_vectors(pdev, 1, BMC_MULTI_MSI, PCI_IRQ_INTX | PCI_IRQ_MSI) <= 1)
+		/* If pci_alloc fail, set all msi index to the first vector */
+		memset(pci_bmc_dev->msi_idx_table, 0, sizeof(vuart_msi_index));

[Severity: High]
Does this code inadvertently corrupt global state for all driver instances? Since pci_bmc_dev->msi_idx_table points to vuart_msi_index (a static global array), calling memset on it will permanently zero out the MSI indices system-wide if any device fails to allocate multiple MSI vectors.

Also, does the threshold check protect against partial allocations falling short of index 17?

If pci_alloc_irq_vectors() successfully allocates an intermediate number of vectors (e.g., 4 or 8), the '<= 1' check evaluates to false. The driver retains indices 16 and 17 and attempts to fetch them via pci_irq_vector() below, which triggers an out-of-bounds warning and returns -EINVAL.

[ ... ]

Quoted 3 lines
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +3 -0
+static int aspeed_pci_bmc_device_setup_vuart(struct pci_dev *pdev, int idx)
+{
+	struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev);

[ ... ]

drivers/soc/aspeed/aspeed-host-bmc-dev.c

Quoted 1 line
drivers/soc/aspeed/aspeed-host-bmc-dev.c new file +1 -0
+	uart->port.irq = pci_irq_vector(pdev, pci_bmc_dev->msi_idx_table[idx]);

[Severity: High]
If a partial allocation leaves us with fewer vectors than the index stored in msi_idx_table[idx], pci_irq_vector() returns a negative error code like -EINVAL. Could this error code be incorrectly passed as the IRQ number here, causing interrupt registration to fail later?

[ ... ]

Quoted 4 lines
drivers/tty/serial/8250/8250_aspeed_vuart.c +0 -0
index 26fc0464f1cc2..e204e26fa173b 100644

[ ... ]

Quoted 3 lines
drivers/tty/serial/8250/8250_aspeed_vuart.c +3 -0
+static int aspeed_ast2600_vuart_over_pci_set_enabled(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;

[ ... ]

drivers/tty/serial/8250/8250_aspeed_vuart.c

Quoted 1 line
drivers/tty/serial/8250/8250_aspeed_vuart.c +1 -0
+	scu = syscon_regmap_lookup_by_phandle(dev->of_node, "clocks");

[Severity: Medium]
Is it semantically correct to use the "clocks" property as a syscon phandle? The "clocks" property specifies clock providers and specifiers, not raw syscon phandles. Piggybacking on this to extract a syscon regmap leverages an implementation detail of syscon_regmap_lookup_by_phandle() and violates device tree semantics.

[ ... ]

drivers/tty/serial/8250/8250_aspeed_vuart.c static int aspeed_vuart_probe(struct platform_device *pdev) · line 625

Quoted 10 lines
drivers/tty/serial/8250/8250_aspeed_vuart.c +6 -0
@@ -540,6 +617,15 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
 	aspeed_vuart_set_host_tx_discard(vuart, true);
 	platform_set_drvdata(pdev, vuart);
 
+	if (of_device_is_compatible(dev->of_node, "aspeed,ast2600-vuart") &&
+		of_property_read_bool(dev->of_node, "aspeed,vuart-over-pci")) {
+		rc = aspeed_ast2600_vuart_over_pci_set_enabled(pdev);
+		if (rc) {
+			dev_err(dev, "could not enable VUART over PCI\n");
+			return rc;

[Severity: High]
Does returning directly here skip probe cleanup? Bypassing the err_sysfs_remove label leaves sysfs groups, timers, and the 8250 serial port registered while devres frees the underlying vuart structure. Does this leak the sysfs groups and timers, and potentially cause a use-after-free if the 8250 core accesses the unregistered port?

drivers/tty/serial/8250/8250_aspeed_vuart.c

Quoted 8 lines
drivers/tty/serial/8250/8250_aspeed_vuart.c +3 -0
+		}
+	}
+
 	return 0;
 
 err_sysfs_remove:
drivers/tty/serial/8250/8250_aspeed_vuart.c +0 -0
 	sysfs_remove_group(&vuart->dev->kobj, &aspeed_vuart_attr_group);
 	return rc;

[Severity: High]
This isn't a bug introduced by this patch, but does the err_sysfs_remove path fail to unregister the 8250 port? If probe fails after port registration, serial8250_unregister_port() is missed. The 8250 core will later dereference the freed vuart pointer via port.private_data, causing a use-after-free.

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=6
#40 lore raw

Re: [PATCH v3 6/7] ARM: dts: aspeed: g6: Change vuart compatible string for ast2600

In reply to Grégoire Layet
Quoted 14 lines · Grégoire Layet

Use the ast2600 compatible string.
This makes it more precise and enables specific ast2600 properties. Still use the ast2500 compatible string as a fallback.

---
 arch/arm/boot/dts/aspeed/aspeed-g6.dtsi | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
arch/arm/boot/dts/aspeed/aspeed-g6.dtsi +0 -0
index 56bb3b0444f7..7c02633f2bd6 100644

arch/arm/boot/dts/aspeed/aspeed-g6.dtsi emmc: sdhci@1e750100 { · line 710

Quoted 5 lines
arch/arm/boot/dts/aspeed/aspeed-g6.dtsi +1 -1
@@ -707,7 +707,7 @@ emmc: sdhci@1e750100 {
 			};
 
 			vuart1: serial@1e787000 {
-				compatible = "aspeed,ast2500-vuart";
+				compatible = "aspeed,ast2600-vuart", "aspeed,ast2500-vuart";

Please start testing your patches. This for sure fails tests.

It does not look like you tested the DTS against bindings. Please run 'make dtbs_check W=1' (see Documentation/devicetree/bindings/writing-schema.rst or
https://www.linaro.org/blog/tips-and-tricks-for-validating-devicetree-sources-with-the-devicetree-schema/
for instructions).
Maybe you need to update your dtschema and yamllint. Don't rely on distro packages for dtschema and be sure you are using the latest released dtschema.

Best regards,
Krzysztof

#41 lore raw

Re: [PATCH v3 6/7] ARM: dts: aspeed: g6: Change vuart compatible string for ast2600

Hi Krzysztof,

Quoted 10 lines

Please start testing your patches. This for sure fails tests.

It does not look like you tested the DTS against bindings. Please run 'make dtbs_check W=1' (see Documentation/devicetree/bindings/writing-schema.rst or
https://www.linaro.org/blog/tips-and-tricks-for-validating-devicetree-sources-with-the-devicetree-schema/
for instructions).
Maybe you need to update your dtschema and yamllint. Don't rely on distro packages for dtschema and be sure you are using the latest released dtschema.

You are right, I had tested my patches but wrongly. It is indeed failling. I'm very sorry for that. Thank's for taking the time to explain.

Best regards,
Grégoire

#42 lore raw

PATCH v3 7/7 ARM: dts: aspeed: g6: add aspeed,vuart-over-pci prop to vuart3 and 4

In reply to Grégoire Layet

The VUART 3 and 4 are VUART over PCI.
This flag indicates this information.

---
 arch/arm/boot/dts/aspeed/aspeed-g6.dtsi | 2 ++
 1 file changed, 2 insertions(+)
arch/arm/boot/dts/aspeed/aspeed-g6.dtsi +2 -0
index 7c02633f2bd6..2a19463b4c21 100644
@@ -723,6 +723,7 @@ vuart3: serial@1e787800 {
 				interrupts = <GIC_SPI 180 IRQ_TYPE_LEVEL_HIGH>;
 				clocks = <&syscon ASPEED_CLK_APB2>;
 				no-loopback-test;
+				aspeed,vuart-over-pci;
 				status = "disabled";
 			};
 
@@ -743,6 +744,7 @@ vuart4: serial@1e788800 {
 				interrupts = <GIC_SPI 181 IRQ_TYPE_LEVEL_HIGH>;
 				clocks = <&syscon ASPEED_CLK_APB2>;
 				no-loopback-test;
+				aspeed,vuart-over-pci;
 				status = "disabled";
 			};
 
Signature · 1 line
2.54.0
#43 lore raw

Re: [PATCH v3 7/7] ARM: dts: aspeed: g6: add aspeed,vuart-over-pci prop to vuart3 and 4

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:

New issues:
- [Low] Adding aspeed,vuart-over-pci to nodes with multiple compatible strings violates the const constraint in the YAML binding, causing a schema validation failure.

Pre-existing issues:
- [High] Probe error paths fail to unregister the 8250 port and remove the sysfs group, resulting in a use-after-free of the devm-allocated driver state and resource leaks. --

commit 3ce60a66a65e6d307209da21c88e6e5c758ddf74

Author: Grégoire Layet <[email protected]>
Date:   Tue Jun 23 14:25:45 2026 +0000

ARM: dts: aspeed: g6: add aspeed,vuart-over-pci prop to vuart3 and 4

The VUART 3 and 4 are VUART over PCI.
This flag indicates this information.

arch/arm/boot/dts/aspeed/aspeed-g6.dtsi vuart3: serial@1e787800 { · line 717

Quoted 9 lines
arch/arm/boot/dts/aspeed/aspeed-g6.dtsi +1 -0
index 5ff52697e8bb4..b33468288d4a5 100644
@@ -714,6 +714,7 @@ vuart3: serial@1e787800 {
 				interrupts = <GIC_SPI 180 IRQ_TYPE_LEVEL_HIGH>;
 				clocks = <&syscon ASPEED_CLK_APB2>;
 				no-loopback-test;
+				aspeed,vuart-over-pci;

[Severity: Low]
Does adding this property cause a device tree schema validation failure?

Looking at Documentation/devicetree/bindings/serial/8250.yaml, the schema restricts the compatible property to a single string when aspeed,vuart-over-pci is present:

        compatible:
          const: aspeed,ast2600-vuart

Since the vuart3 node uses multiple compatible strings ("aspeed,ast2600-vuart", "aspeed,ast2500-vuart"), does this violate the constraint and cause dtbs_check to fail?

[Severity: High]
This isn't a bug introduced by this patch, but adding this property appears to trigger a pre-existing resource leak and use-after-free in the driver's error path.

In drivers/tty/serial/8250/8250_aspeed_vuart.c, if aspeed_ast2600_vuart_over_pci_set_enabled() fails during aspeed_vuart_probe(), the function returns directly:

        rc = aspeed_ast2600_vuart_over_pci_set_enabled(pdev);
        if (rc) {
                dev_err(dev, "could not enable VUART over PCI\n");
                return rc;
        }

Does this bypass calling serial8250_unregister_port() and sysfs_remove_group() after a successful serial8250_register_8250_port()? Since the devm-allocated driver state is freed on probe failure, does the UART core retain a registered port pointing to freed memory?

Quoted 2 lines
arch/arm/boot/dts/aspeed/aspeed-g6.dtsi +0 -0
 				status = "disabled";
 			};

[ ... ]

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=7