lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <wj2x7viy7o2yoj6r3dfgjurtigifmoingm7yhypvmdn2nltkvo@kf3e4hbzphy7>
Date: Wed, 21 Jan 2026 21:29:39 +0530
From: Manivannan Sadhasivam <mani@...nel.org>
To: Pragnesh Patel <pragneshp@...vell.com>
Cc: gcherian@...vell.com, Suneel Garapati <sgarapati@...vell.com>, 
	Lorenzo Pieralisi <lpieralisi@...nel.org>, Krzysztof Wilczyński <kwilczynski@...nel.org>, 
	Rob Herring <robh@...nel.org>, Bjorn Helgaas <bhelgaas@...gle.com>, 
	linux-kernel@...r.kernel.org, linux-pci@...r.kernel.org
Subject: Re: [PATCH] PCI: octeon: Add link down handler support for PCIe MAC
 controller

On Tue, Jan 20, 2026 at 09:14:29PM -0800, Pragnesh Patel wrote:
> From: Suneel Garapati <sgarapati@...vell.com>
> 
> This driver adds support for link-down interrupt in PCIe MAC (PEM)
> controller in Root complex mode to support hot-plug removal of
> endpoint devices.
> 

What is this device actually? Is this really a Root Complex device? Root complex
(host bridge) is the one that exposes the Root bus and not gets plugged into the
bus. This looks very strange.

> An interrupt handler is registered for RST_INT msix vector
> which is triggered with link going down. This handler
> performs cleanup of root bridge and its children and
> re-initializes root bridge to kernel for next link-up event.
> 

I have a series [1] (needs respin) that allows the controller drivers to reset
the Root Ports in the event of link down. You might want to take a look at that.
I'll try to respin asap.

- Mani

[1] https://lore.kernel.org/linux-pci/20250715-pci-port-reset-v6-0-6f9cce94e7bb@oss.qualcomm.com/

> Signed-off-by: Suneel Garapati <sgarapati@...vell.com>
> Signed-off-by: Pragnesh Patel <pragneshp@...vell.com>
> ---
>  MAINTAINERS                             |   6 +
>  drivers/pci/controller/Kconfig          |   9 +
>  drivers/pci/controller/Makefile         |   1 +
>  drivers/pci/controller/pci-octeon-pem.c | 278 ++++++++++++++++++++++++
>  4 files changed, 294 insertions(+)
>  create mode 100644 drivers/pci/controller/pci-octeon-pem.c
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index f1b020588597..9af8f676c027 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -15363,6 +15363,12 @@ R:	Vamsi Attunuru <vattunuru@...vell.com>
>  S:	Supported
>  F:	drivers/pci/hotplug/octep_hp.c
>  
> +MARVELL OCTEON PEM CONTROLLER DRIVER
> +R:	George Cherian <gcherian@...vell.com>
> +R:	Pragnesh Patel <pragneshp@...vell.com>
> +S:	Supported
> +F:	drivers/pci/controller/pci-octeon-pem.c
> +
>  MATROX FRAMEBUFFER DRIVER
>  L:	linux-fbdev@...r.kernel.org
>  S:	Orphan
> diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
> index c254d2b8bf17..5251dc8b1188 100644
> --- a/drivers/pci/controller/Kconfig
> +++ b/drivers/pci/controller/Kconfig
> @@ -231,6 +231,15 @@ config PCI_HYPERV_INTERFACE
>  	  drivers to have a common interface with the Hyper-V PCI frontend
>  	  driver.
>  
> +config PCI_OCTEON_PEM
> +	bool "Marvell Octeon PEM (PCIe MAC) controller"
> +	depends on ARM64 || COMPILE_TEST
> +	depends on PCI_MSI
> +	depends on HOTPLUG_PCI_PCIE
> +	help
> +	  Say Y here if you want PEM controller support for Marvell ARM64 Octeon SoCs
> +	  in root complex mode.
> +
>  config PCI_TEGRA
>  	bool "NVIDIA Tegra PCIe controller"
>  	depends on ARCH_TEGRA || COMPILE_TEST
> diff --git a/drivers/pci/controller/Makefile b/drivers/pci/controller/Makefile
> index 229929a945c2..dd1dab50dd07 100644
> --- a/drivers/pci/controller/Makefile
> +++ b/drivers/pci/controller/Makefile
> @@ -23,6 +23,7 @@ obj-$(CONFIG_PCI_V3_SEMI) += pci-v3-semi.o
>  obj-$(CONFIG_PCI_XGENE) += pci-xgene.o
>  obj-$(CONFIG_PCI_XGENE_MSI) += pci-xgene-msi.o
>  obj-$(CONFIG_PCI_VERSATILE) += pci-versatile.o
> +obj-$(CONFIG_PCI_OCTEON_PEM) += pci-octeon-pem.o
>  obj-$(CONFIG_PCIE_IPROC) += pcie-iproc.o
>  obj-$(CONFIG_PCIE_IPROC_MSI) += pcie-iproc-msi.o
>  obj-$(CONFIG_PCIE_IPROC_PLATFORM) += pcie-iproc-platform.o
> diff --git a/drivers/pci/controller/pci-octeon-pem.c b/drivers/pci/controller/pci-octeon-pem.c
> new file mode 100644
> index 000000000000..2d67e2b16e9e
> --- /dev/null
> +++ b/drivers/pci/controller/pci-octeon-pem.c
> @@ -0,0 +1,278 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Octeon PEM driver
> + *
> + * Copyright (C) 2021 Marvell.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +#include <linux/delay.h>
> +#include <linux/interrupt.h>
> +#include <linux/irq.h>
> +#include <linux/module.h>
> +#include <linux/pci.h>
> +#include <linux/sysfs.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +
> +#include "../hotplug/pciehp.h"
> +#include "../pci.h"
> +
> +#define DRV_NAME	"octeon-pem"
> +#define DRV_VERSION	"1.0"
> +
> +#define PCI_DEVID_OCTEON_PEM	0xA06C
> +
> +#define ID_SHIFT		36
> +#define DOMAIN_OFFSET		0x3
> +#define ON_OFFSET		0xE0
> +#define RST_SOFT_PERST_OFFSET	0x298
> +#define RST_INT_OFFSET		0x300
> +#define RST_INT_ENA_W1C_OFFSET	0x310
> +#define RST_INT_ENA_W1S_OFFSET	0x318
> +#define RST_INT_LINKDOWN	BIT(1)
> +
> +struct pem_ctlr {
> +	int			index;
> +	char			irq_name[32];
> +	void __iomem		*base;
> +	struct pci_dev		*pdev;
> +	struct work_struct	recover_rc_work;
> +};
> +
> +static struct pcie_device *to_pciehp_dev(struct pci_dev *dev)
> +{
> +	struct device *device;
> +
> +	device = pcie_port_find_device(dev, PCIE_PORT_SERVICE_HP);
> +	if (!device)
> +		return NULL;
> +	return to_pcie_device(device);
> +}
> +
> +static void pem_recover_rc_link(struct work_struct *ws)
> +{
> +	struct pem_ctlr *pem = container_of(ws, struct pem_ctlr,
> +					    recover_rc_work);
> +	struct pci_dev *pem_dev = pem->pdev;
> +	struct pci_dev *root_port;
> +	struct pci_bus *bus;
> +	struct pcie_device *pcie;
> +	struct controller *ctrl;
> +	int rc_domain, timeout = 100;
> +	u64 pem_reg;
> +
> +	rc_domain = pem->index + DOMAIN_OFFSET;
> +
> +	root_port = pci_get_domain_bus_and_slot(rc_domain, 0, 0);
> +	if (!root_port) {
> +		dev_err(&pem_dev->dev, "failed to get root port\n");
> +		return;
> +	}
> +
> +	dev_dbg(&pem_dev->dev, "PEM%d rcvr work\n", pem->index);
> +
> +	/* Check if HP interrupt thread is in progress
> +	 * and wait for it to complete
> +	 */
> +	pcie = to_pciehp_dev(root_port);
> +	if (!pcie)
> +		return;
> +	ctrl = get_service_data(pcie);
> +	wait_event(ctrl->requester,
> +		   !atomic_read(&ctrl->pending_events) &&
> +		   !ctrl->ist_running);
> +	dev_dbg(&pem_dev->dev, "PEM%d HP ist done\n", pem->index);
> +
> +	/* Disable hot-plug interrupt
> +	 * Removal and rescan below would setup again.
> +	 */
> +	pcie_disable_interrupt(ctrl);
> +	dev_dbg(&pem_dev->dev, "PEM%d Disable interrupt\n", pem->index);
> +
> +	pci_lock_rescan_remove();
> +
> +	pci_walk_bus(root_port->subordinate, pci_dev_set_disconnected, NULL);
> +
> +	/* Clean-up device and RC bridge */
> +	pci_stop_and_remove_bus_device(root_port);
> +
> +	pci_unlock_rescan_remove();
> +
> +	usleep_range(100, 200);
> +
> +	writeq(0x0, pem->base + RST_SOFT_PERST_OFFSET);
> +
> +	while (timeout--) {
> +		/* Check for PEM_OOR to be set */
> +		pem_reg = readq(pem->base + ON_OFFSET);
> +		if (pem_reg & BIT(1))
> +			break;
> +		usleep_range(1000, 2000);
> +	}
> +	if (!timeout) {
> +		dev_warn(&pem_dev->dev,
> +			 "PEM failed to get out of reset\n");
> +		return;
> +	}
> +
> +	pci_lock_rescan_remove();
> +
> +	/*
> +	 * Hardware resets and initializes config space of RC bridge
> +	 * on every link down event with auto-mode in use.
> +	 * Re-scan will setup RC bridge cleanly in kernel
> +	 * after removal and to be ready for next link-up event.
> +	 */
> +	bus = NULL;
> +	while ((bus = pci_find_next_bus(bus)) != NULL)
> +		if (bus->domain_nr == rc_domain)
> +			pci_rescan_bus(bus);
> +	pci_unlock_rescan_remove();
> +	pci_dev_put(root_port);
> +
> +	/* Ack interrupt */
> +	writeq(RST_INT_LINKDOWN, pem->base + RST_INT_OFFSET);
> +	/* Enable RST_INT[LINKDOWN] interrupt */
> +	writeq(RST_INT_LINKDOWN, pem->base + RST_INT_ENA_W1S_OFFSET);
> +}
> +
> +static irqreturn_t pem_irq_handler(int irq, void *dev_id)
> +{
> +	struct pem_ctlr *pem = (struct pem_ctlr *)dev_id;
> +
> +	/* Disable RST_INT[LINKDOWN] interrupt */
> +	writeq(RST_INT_LINKDOWN, pem->base + RST_INT_ENA_W1C_OFFSET);
> +	schedule_work(&pem->recover_rc_work);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int pem_register_interrupts(struct pci_dev *pdev)
> +{
> +	struct pem_ctlr *pem = pci_get_drvdata(pdev);
> +	int nvec, err;
> +
> +	nvec = pci_msix_vec_count(pdev);
> +	/* Some earlier silicon versions do not support RST vector
> +	 * so check on table size before registering otherwise
> +	 * return with info message.
> +	 */
> +	if (nvec != 10) {
> +		dev_info(&pdev->dev,
> +			 "No RST MSI-X vector support on silicon\n");
> +		return 0;
> +	}
> +	err = pci_alloc_irq_vectors(pdev, nvec, nvec, PCI_IRQ_MSIX);
> +	if (err < 0) {
> +		dev_err(&pdev->dev, "pci_alloc_irq_vectors() failed %d\n",
> +			nvec);
> +		return -ENOSPC;
> +	}
> +
> +	snprintf(pem->irq_name, 32, "PEM%d RST_INT", pem->index);
> +
> +	/* register interrupt for RST_INT */
> +	return devm_request_irq(&pdev->dev, pci_irq_vector(pdev, 9),
> +				pem_irq_handler, 0,
> +				pem->irq_name, pem);
> +}
> +
> +static int pem_probe(struct pci_dev *pdev, const struct pci_device_id *id)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct pem_ctlr *pem;
> +	struct pci_dev *root_port;
> +	int err, rc_domain;
> +
> +	pem = devm_kzalloc(dev, sizeof(struct pem_ctlr), GFP_KERNEL);
> +	if (!pem)
> +		return -ENOMEM;
> +
> +	pem->pdev = pdev;
> +	pci_set_drvdata(pdev, pem);
> +
> +	err = pcim_enable_device(pdev);
> +	if (err) {
> +		dev_err(dev, "Failed to enable PCI device\n");
> +		goto enable_failed;
> +	}
> +
> +	err = pci_request_regions(pdev, DRV_NAME);
> +	if (err) {
> +		dev_err(dev, "PCI request regions failed 0x%x\n", err);
> +		goto region_failed;
> +	}
> +
> +	pci_set_master(pdev);
> +
> +	/* CSR Space mapping */
> +	pem->base = pcim_iomap(pdev, 0, pci_resource_len(pdev, 0));
> +	if (!pem->base) {
> +		dev_err(&pdev->dev, "Unable to map BAR0\n");
> +		err = -ENODEV;
> +		goto bar0_map_failed;
> +	}
> +	pem->index = ((u64)pci_resource_start(pdev, 0) >> ID_SHIFT) & 0xf;
> +
> +	rc_domain = pem->index + DOMAIN_OFFSET;
> +
> +	root_port = pci_get_domain_bus_and_slot(rc_domain, 0, 0);
> +	if (!root_port) {
> +		dev_err(&pdev->dev, "failed to get root port\n");
> +		goto bar0_map_failed;
> +	}
> +	if (!root_port->is_hotplug_bridge) {
> +		dev_info(&pdev->dev, "Hot-plug disabled skip registration\n");
> +		goto bar0_map_failed;
> +	}
> +
> +	err = pem_register_interrupts(pdev);
> +	if (err < 0) {
> +		dev_err(dev, "Register interrupt failed\n");
> +		goto irq_failed;
> +	}
> +
> +	INIT_WORK(&pem->recover_rc_work, pem_recover_rc_link);
> +
> +	/* Enable RST_INT[LINKDOWN] interrupt */
> +	writeq(RST_INT_LINKDOWN, pem->base + RST_INT_ENA_W1S_OFFSET);
> +
> +	dev_info(&pdev->dev, "PEM%d probed\n", pem->index);
> +	return 0;
> +
> +irq_failed:
> +bar0_map_failed:
> +	pci_release_regions(pdev);
> +region_failed:
> +enable_failed:
> +	pci_set_drvdata(pdev, NULL);
> +	return err;
> +}
> +
> +static void pem_remove(struct pci_dev *pdev)
> +{
> +	pci_release_regions(pdev);
> +}
> +
> +/* Supported devices */
> +static const struct pci_device_id pem_id_table[] = {
> +	{PCI_VDEVICE(CAVIUM, PCI_DEVID_OCTEON_PEM)},
> +	{0} /* end of table */
> +};
> +
> +static struct pci_driver pem_driver = {
> +	.name = DRV_NAME,
> +	.id_table = pem_id_table,
> +	.probe = pem_probe,
> +	.remove = pem_remove,
> +};
> +
> +module_pci_driver(pem_driver);
> +
> +MODULE_AUTHOR("Marvell Inc.");
> +MODULE_DESCRIPTION("Marvell Octeon PEM Driver");
> +MODULE_LICENSE("GPL");
> +MODULE_VERSION(DRV_VERSION);
> +MODULE_DEVICE_TABLE(pci, pem_id_table);
> -- 
> 2.43.0
> 

-- 
மணிவண்ணன் சதாசிவம்

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ