Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 8 Sep 2017 19:39:21 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r323325 - in head/sys/x86: include x86
Message-ID:  <201709081939.v88JdL5d094556@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kib
Date: Fri Sep  8 19:39:20 2017
New Revision: 323325
URL: https://svnweb.freebsd.org/changeset/base/323325

Log:
  Add an ioapic_get_rid() function to obtain PCIe TLP requester-id for
  the interrupt messages from given IOAPIC, if the IOAPIC can be
  enumerated on PCI bus.
  
  If IOAPIC has PCI binding, match the PCI device against MADT
  enumerated IOAPIC.  Match is done first by registers window physical
  address, then by IOAPIC ID as read from the APIC ID register.
  
  PCI bsf address of the matched PCI device is the rid.
  
  Reviewed by:	jhb
  Sponsored by:	The FreeBSD Foundation
  Hardware provided by:	Intel
  MFC after:	2 weeks
  X-Differential revision:	https://reviews.freebsd.org/D12205

Modified:
  head/sys/x86/include/apicvar.h
  head/sys/x86/x86/io_apic.c

Modified: head/sys/x86/include/apicvar.h
==============================================================================
--- head/sys/x86/include/apicvar.h	Fri Sep  8 19:25:11 2017	(r323324)
+++ head/sys/x86/include/apicvar.h	Fri Sep  8 19:39:20 2017	(r323325)
@@ -478,6 +478,8 @@ void	lapic_handle_error(void);
 void	lapic_handle_intr(int vector, struct trapframe *frame);
 void	lapic_handle_timer(struct trapframe *frame);
 
+int	ioapic_get_rid(u_int apic_id, uint16_t *ridp);
+
 extern int x2apic_mode;
 extern int lapic_eoi_suppression;
 

Modified: head/sys/x86/x86/io_apic.c
==============================================================================
--- head/sys/x86/x86/io_apic.c	Fri Sep  8 19:25:11 2017	(r323324)
+++ head/sys/x86/x86/io_apic.c	Fri Sep  8 19:39:20 2017	(r323325)
@@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/malloc.h>
 #include <sys/module.h>
 #include <sys/mutex.h>
+#include <sys/rman.h>
 #include <sys/sysctl.h>
 
 #include <dev/pci/pcireg.h>
@@ -99,6 +100,9 @@ struct ioapic {
 	volatile ioapic_t *io_addr;	/* XXX: should use bus_space */
 	vm_paddr_t io_paddr;
 	STAILQ_ENTRY(ioapic) io_next;
+	device_t pci_dev;		/* matched pci device, if found */
+	struct resource *pci_wnd;	/* BAR 0, should be same or alias to
+					   io_paddr */
 	struct ioapic_intsrc io_pins[0];
 };
 
@@ -622,6 +626,8 @@ ioapic_create(vm_paddr_t addr, int32_t apic_id, int in
 	io = malloc(sizeof(struct ioapic) +
 	    numintr * sizeof(struct ioapic_intsrc), M_IOAPIC, M_WAITOK);
 	io->io_pic = ioapic_template;
+	io->pci_dev = NULL;
+	io->pci_wnd = NULL;
 	mtx_lock_spin(&icu_lock);
 	io->io_id = next_id++;
 	io->io_apic_id = ioapic_read(apic, IOAPIC_ID) >> APIC_ID_SHIFT;
@@ -954,7 +960,72 @@ ioapic_pci_probe(device_t dev)
 static int
 ioapic_pci_attach(device_t dev)
 {
+	struct resource *res;
+	volatile ioapic_t *apic;
+	struct ioapic *io;
+	int rid;
+	u_int apic_id;
 
+	/*
+	 * Try to match the enumerated ioapic.  Match BAR start
+	 * against io_paddr.  Due to a fear that PCI window is not the
+	 * same as the MADT reported io window, but an alias, read the
+	 * APIC ID from the mapped BAR and match against it.
+	 */
+	rid = PCIR_BAR(0);
+	res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+	    RF_ACTIVE | RF_SHAREABLE);
+	if (res == NULL) {
+		if (bootverbose)
+			device_printf(dev, "cannot activate BAR0\n");
+		return (ENXIO);
+	}
+	apic = (volatile ioapic_t *)rman_get_virtual(res);
+	if (rman_get_size(res) < IOAPIC_WND_SIZE) {
+		if (bootverbose)
+			device_printf(dev,
+			    "BAR0 too small (%jd) for IOAPIC window\n",
+			    (uintmax_t)rman_get_size(res));
+		goto fail;
+	}
+	mtx_lock_spin(&icu_lock);
+	apic_id = ioapic_read(apic, IOAPIC_ID) >> APIC_ID_SHIFT;
+	/* First match by io window address */
+	STAILQ_FOREACH(io, &ioapic_list, io_next) {
+		if (io->io_paddr == (vm_paddr_t)rman_get_start(res))
+			goto found;
+	}
+	/* Then by apic id */
+	STAILQ_FOREACH(io, &ioapic_list, io_next) {
+		if (io->io_id == apic_id)
+			goto found;
+	}
+	mtx_unlock_spin(&icu_lock);
+	if (bootverbose)
+		device_printf(dev,
+		    "cannot match pci bar apic id %d against MADT\n",
+		    apic_id);
+fail:
+	bus_release_resource(dev, SYS_RES_MEMORY, rid, res);
+	return (ENXIO);
+found:
+	KASSERT(io->pci_dev == NULL,
+	    ("ioapic %d pci_dev not NULL", io->io_id));
+	KASSERT(io->pci_wnd == NULL,
+	    ("ioapic %d pci_wnd not NULL", io->io_id));
+
+	io->pci_dev = dev;
+	io->pci_wnd = res;
+	if (bootverbose && (io->io_paddr != (vm_paddr_t)rman_get_start(res) ||
+	    io->io_id != apic_id)) {
+		device_printf(dev, "pci%d:%d:%d:%d pci BAR0@%jx id %d "
+		    "MADT id %d paddr@%jx\n",
+		    pci_get_domain(dev), pci_get_bus(dev),
+		    pci_get_slot(dev), pci_get_function(dev),
+		    (uintmax_t)rman_get_start(res), apic_id,
+		    io->io_id, (uintmax_t)io->io_paddr);
+	}
+	mtx_unlock_spin(&icu_lock);
 	return (0);
 }
 
@@ -971,6 +1042,28 @@ DEFINE_CLASS_0(ioapic, ioapic_pci_driver, ioapic_pci_m
 static devclass_t ioapic_devclass;
 DRIVER_MODULE(ioapic, pci, ioapic_pci_driver, ioapic_devclass, 0, 0);
 
+int
+ioapic_get_rid(u_int apic_id, uint16_t *ridp)
+{
+	struct ioapic *io;
+	uintptr_t rid;
+	int error;
+
+	mtx_lock_spin(&icu_lock);
+	STAILQ_FOREACH(io, &ioapic_list, io_next) {
+		if (io->io_id == apic_id)
+			break;
+	}
+	mtx_unlock_spin(&icu_lock);
+	if (io == NULL || io->pci_dev == NULL)
+		return (EINVAL);
+	error = pci_get_id(io->pci_dev, PCI_ID_RID, &rid);
+	if (error != 0)
+		return (error);
+	*ridp = rid;
+	return (0);
+}
+
 /*
  * A new-bus driver to consume the memory resources associated with
  * the APICs in the system.  On some systems ACPI or PnPBIOS system
@@ -1008,7 +1101,7 @@ apic_add_resource(device_t dev, int rid, vm_paddr_t ba
 	if (error)
 		panic("apic_add_resource: resource %d failed set with %d", rid,
 		    error);
-	bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 0);
+	bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_SHAREABLE);
 }
 
 static int



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