From owner-svn-src-all@freebsd.org Tue Oct 15 19:04:40 2019 Return-Path: Delivered-To: svn-src-all@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 4582D151AB0; Tue, 15 Oct 2019 19:04:40 +0000 (UTC) (envelope-from jhb@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 46t4c815S1z3Cl4; Tue, 15 Oct 2019 19:04:40 +0000 (UTC) (envelope-from jhb@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 08B6B23202; Tue, 15 Oct 2019 19:04:40 +0000 (UTC) (envelope-from jhb@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id x9FJ4dIl078975; Tue, 15 Oct 2019 19:04:39 GMT (envelope-from jhb@FreeBSD.org) Received: (from jhb@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id x9FJ4dae078974; Tue, 15 Oct 2019 19:04:39 GMT (envelope-from jhb@FreeBSD.org) Message-Id: <201910151904.x9FJ4dae078974@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: jhb set sender to jhb@FreeBSD.org using -f From: John Baldwin Date: Tue, 15 Oct 2019 19:04:39 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r353586 - head/sys/dev/acpica X-SVN-Group: head X-SVN-Commit-Author: jhb X-SVN-Commit-Paths: head/sys/dev/acpica X-SVN-Commit-Revision: 353586 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 15 Oct 2019 19:04:40 -0000 Author: jhb Date: Tue Oct 15 19:04:39 2019 New Revision: 353586 URL: https://svnweb.freebsd.org/changeset/base/353586 Log: 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. Tested by: cperciva Reviewed by: cperciva, imp, scottl MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D21948 Modified: head/sys/dev/acpica/acpi_pci.c Modified: head/sys/dev/acpica/acpi_pci.c ============================================================================== --- head/sys/dev/acpica/acpi_pci.c Tue Oct 15 18:58:01 2019 (r353585) +++ head/sys/dev/acpica/acpi_pci.c Tue Oct 15 19:04:39 2019 (r353586) @@ -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