Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 25 Oct 2019 22:04:06 +0000 (UTC)
From:      John Baldwin <jhb@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org
Subject:   svn commit: r354107 - in stable: 11/sys/dev/acpica 11/sys/dev/pci 12/sys/dev/acpica 12/sys/dev/pci
Message-ID:  <201910252204.x9PM46cs063244@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jhb
Date: Fri Oct 25 22:04:05 2019
New Revision: 354107
URL: https://svnweb.freebsd.org/changeset/base/354107

Log:
  MFC 353585,353586: Support hot insertion and removal of PCI devices on EC2.
  
  353585:
  Export pci_attach() and pci_detach().
  
  353586:
  Support hot insertion and removal of PCI devices on EC2.
  
  Install ACPI notify handlers on PCI devices with an _EJ0 method.  This
  handler is invoked when devices are added or removed.
  
  - When an ACPI_NOTIFY_DEVICE_CHECK event posts, rescan the parent bus
    device.  Note that strictly speaking we only need to rescan the
    specified device, but BUS_RESCAN is what is available, so we rescan
    the entire bus.
  - When an ACPI_NOTIFY_EJECT_REQUEST event posts, detach the device
    associated with the ACPI handle, invoke the _EJ0 method, and then
    delete the device.
  
  Eventually this might be changed to vector notify events to devd in
  userspace where devctl can be used instead to permit more complex
  actions such as graceful unmounting of filesystems.

Modified:
  stable/12/sys/dev/acpica/acpi_pci.c
  stable/12/sys/dev/pci/pci.c
  stable/12/sys/dev/pci/pci_private.h
Directory Properties:
  stable/12/   (props changed)

Changes in other areas also in this revision:
Modified:
  stable/11/sys/dev/acpica/acpi_pci.c
  stable/11/sys/dev/pci/pci.c
  stable/11/sys/dev/pci/pci_private.h
Directory Properties:
  stable/11/   (props changed)

Modified: stable/12/sys/dev/acpica/acpi_pci.c
==============================================================================
--- stable/12/sys/dev/acpica/acpi_pci.c	Fri Oct 25 21:53:05 2019	(r354106)
+++ stable/12/sys/dev/acpica/acpi_pci.c	Fri Oct 25 22:04:05 2019	(r354107)
@@ -71,9 +71,11 @@ CTASSERT(ACPI_STATE_D2 == PCI_POWERSTATE_D2);
 CTASSERT(ACPI_STATE_D3 == PCI_POWERSTATE_D3);
 
 static struct pci_devinfo *acpi_pci_alloc_devinfo(device_t dev);
+static int	acpi_pci_attach(device_t dev);
 static void	acpi_pci_child_deleted(device_t dev, device_t child);
 static int	acpi_pci_child_location_str_method(device_t cbdev,
 		    device_t child, char *buf, size_t buflen);
+static int	acpi_pci_detach(device_t dev);
 static int	acpi_pci_probe(device_t dev);
 static int	acpi_pci_read_ivar(device_t dev, device_t child, int which,
 		    uintptr_t *result);
@@ -89,6 +91,8 @@ static bus_dma_tag_t acpi_pci_get_dma_tag(device_t bus
 static device_method_t acpi_pci_methods[] = {
 	/* Device interface */
 	DEVMETHOD(device_probe,		acpi_pci_probe),
+	DEVMETHOD(device_attach,	acpi_pci_attach),
+	DEVMETHOD(device_detach,	acpi_pci_detach),
 
 	/* Bus interface */
 	DEVMETHOD(bus_read_ivar,	acpi_pci_read_ivar),
@@ -324,6 +328,108 @@ acpi_pci_probe(device_t dev)
 		return (ENXIO);
 	device_set_desc(dev, "ACPI PCI bus");
 	return (BUS_PROBE_DEFAULT);
+}
+
+static void
+acpi_pci_device_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context)
+{
+	device_t child, dev;
+	ACPI_STATUS status;
+	int error;
+
+	dev = context;
+
+	switch (notify) {
+	case ACPI_NOTIFY_DEVICE_CHECK:
+		mtx_lock(&Giant);
+		BUS_RESCAN(dev);
+		mtx_unlock(&Giant);
+		break;
+	case ACPI_NOTIFY_EJECT_REQUEST:
+		child = acpi_get_device(h);
+		if (child == NULL) {
+			device_printf(dev, "no device to eject for %s\n",
+			    acpi_name(h));
+			return;
+		}
+		mtx_lock(&Giant);
+		error = device_detach(child);
+		if (error) {
+			mtx_unlock(&Giant);
+			device_printf(dev, "failed to detach %s: %d\n",
+			    device_get_nameunit(child), error);
+			return;
+		}
+		status = acpi_SetInteger(h, "_EJ0", 1);
+		if (ACPI_FAILURE(status)) {
+			mtx_unlock(&Giant);
+			device_printf(dev, "failed to eject %s: %s\n",
+			    acpi_name(h), AcpiFormatException(status));
+			return;
+		}
+		BUS_RESCAN(dev);
+		mtx_unlock(&Giant);
+		break;
+	default:
+		device_printf(dev, "unknown notify %#x for %s\n", notify,
+		    acpi_name(h));
+		break;
+	}
+}
+
+static ACPI_STATUS
+acpi_pci_install_device_notify_handler(ACPI_HANDLE handle, UINT32 level,
+    void *context, void **status)
+{
+	ACPI_HANDLE h;
+
+	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+	if (ACPI_FAILURE(AcpiGetHandle(handle, "_EJ0", &h)))
+		return_ACPI_STATUS (AE_OK);
+
+	AcpiInstallNotifyHandler(handle, ACPI_SYSTEM_NOTIFY,
+	    acpi_pci_device_notify_handler, context);
+	return_ACPI_STATUS (AE_OK);
+}
+
+static int
+acpi_pci_attach(device_t dev)
+{
+	int error;
+
+	error = pci_attach(dev);
+	if (error)
+		return (error);
+	AcpiWalkNamespace(ACPI_TYPE_DEVICE, acpi_get_handle(dev), 1,
+	    acpi_pci_install_device_notify_handler, NULL, dev, NULL);
+	
+	return (0);
+}
+
+static ACPI_STATUS
+acpi_pci_remove_notify_handler(ACPI_HANDLE handle, UINT32 level, void *context,
+    void **status)
+{
+	ACPI_HANDLE h;
+
+	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+	if (ACPI_FAILURE(AcpiGetHandle(handle, "_EJ0", &h)))
+		return_ACPI_STATUS (AE_OK);
+
+	AcpiRemoveNotifyHandler(handle, ACPI_SYSTEM_NOTIFY,
+	    acpi_pci_device_notify_handler);
+	return_ACPI_STATUS (AE_OK);
+}
+
+static int
+acpi_pci_detach(device_t dev)
+{
+
+	AcpiWalkNamespace(ACPI_TYPE_DEVICE, acpi_get_handle(dev), 1,
+	    acpi_pci_remove_notify_handler, NULL, dev, NULL);
+	return (pci_detach(dev));
 }
 
 #ifdef ACPI_DMAR

Modified: stable/12/sys/dev/pci/pci.c
==============================================================================
--- stable/12/sys/dev/pci/pci.c	Fri Oct 25 21:53:05 2019	(r354106)
+++ stable/12/sys/dev/pci/pci.c	Fri Oct 25 22:04:05 2019	(r354107)
@@ -98,8 +98,6 @@ static void		pci_assign_interrupt(device_t bus, device
 static int		pci_add_map(device_t bus, device_t dev, int reg,
 			    struct resource_list *rl, int force, int prefetch);
 static int		pci_probe(device_t dev);
-static int		pci_attach(device_t dev);
-static int		pci_detach(device_t dev);
 static void		pci_load_vendor_data(void);
 static int		pci_describe_parse_line(char **ptr, int *vendor,
 			    int *device, char **desc);
@@ -4380,7 +4378,7 @@ pci_attach_common(device_t dev)
 	return (0);
 }
 
-static int
+int
 pci_attach(device_t dev)
 {
 	int busno, domain, error;
@@ -4401,7 +4399,7 @@ pci_attach(device_t dev)
 	return (bus_generic_attach(dev));
 }
 
-static int
+int
 pci_detach(device_t dev)
 {
 #ifdef PCI_RES_BUS

Modified: stable/12/sys/dev/pci/pci_private.h
==============================================================================
--- stable/12/sys/dev/pci/pci_private.h	Fri Oct 25 21:53:05 2019	(r354106)
+++ stable/12/sys/dev/pci/pci_private.h	Fri Oct 25 22:04:05 2019	(r354107)
@@ -58,7 +58,9 @@ void		pci_add_resources(device_t bus, device_t dev, in
 		    uint32_t prefetchmask);
 void		pci_add_resources_ea(device_t bus, device_t dev, int alloc_iov);
 struct pci_devinfo *pci_alloc_devinfo_method(device_t dev);
+int		pci_attach(device_t dev);
 int		pci_attach_common(device_t dev);
+int		pci_detach(device_t dev);
 int		pci_rescan_method(device_t dev);
 void		pci_driver_added(device_t dev, driver_t *driver);
 int		pci_ea_is_enabled(device_t dev, int rid);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201910252204.x9PM46cs063244>