svn commit: r300136 - head/sys/arm64/arm64

Zbigniew Bodek zbb at FreeBSD.org
Wed May 18 10:09:08 UTC 2016


Author: zbb
Date: Wed May 18 10:09:07 2016
New Revision: 300136
URL: https://svnweb.freebsd.org/changeset/base/300136

Log:
  Add support for MSI/MSIX deallocation on GICv3-ITS
  
  Allow to deallocate previously allocated ITS device along with
  its interrupts. Interrupt numbers are being freed when the last
  LPI number is no longer busy.
  
  Reviewed by:	wma
  Obtained from:	Semihalf
  Sponsored by:	Cavium
  Differential Revision:	https://reviews.freebsd.org/D6351

Modified:
  head/sys/arm64/arm64/gic_v3_its.c
  head/sys/arm64/arm64/gic_v3_var.h

Modified: head/sys/arm64/arm64/gic_v3_its.c
==============================================================================
--- head/sys/arm64/arm64/gic_v3_its.c	Wed May 18 09:57:11 2016	(r300135)
+++ head/sys/arm64/arm64/gic_v3_its.c	Wed May 18 10:09:07 2016	(r300136)
@@ -75,8 +75,10 @@ static device_method_t gic_v3_its_method
 	 */
 	/* MSI-X */
 	DEVMETHOD(pic_alloc_msix,	gic_v3_its_alloc_msix),
+	DEVMETHOD(pic_release_msix,	gic_v3_its_release_msix),
 	/* MSI */
 	DEVMETHOD(pic_alloc_msi,	gic_v3_its_alloc_msi),
+	DEVMETHOD(pic_release_msi,	gic_v3_its_release_msi),
 	DEVMETHOD(pic_map_msi,		gic_v3_its_map_msi),
 
 	/* End */
@@ -882,6 +884,7 @@ retry:
 	bit_nset(bitmap, fclr, fclr + nvecs - 1);
 	lpic->lpi_base = fclr + GIC_FIRST_LPI;
 	lpic->lpi_num = nvecs;
+	lpic->lpi_busy = 0;
 	lpic->lpi_free = lpic->lpi_num;
 	lpic->lpi_col_ids = col_ids;
 	for (i = 0; i < lpic->lpi_num; i++) {
@@ -901,10 +904,9 @@ lpi_free_chunk(struct gic_v3_its_softc *
 {
 	int start, end;
 
-	KASSERT((lpic->lpi_free == lpic->lpi_num),
-	    ("Trying to free LPI chunk that is still in use.\n"));
-
 	mtx_lock_spin(&sc->its_dev_lock);
+	KASSERT((lpic->lpi_busy == 0),
+	    ("Trying to free LPI chunk that is still in use.\n"));
 	/* First bit of this chunk in a global bitmap */
 	start = lpic->lpi_base - GIC_FIRST_LPI;
 	/* and last bit of this chunk... */
@@ -1493,6 +1495,7 @@ its_device_alloc(struct gic_v3_its_softc
     u_int nvecs)
 {
 	struct its_dev *newdev;
+	vm_offset_t itt_addr;
 	uint64_t typer;
 	uint32_t devid;
 	size_t esize;
@@ -1528,16 +1531,18 @@ its_device_alloc(struct gic_v3_its_softc
 	 * Allocate ITT for this device.
 	 * PA has to be 256 B aligned. At least two entries for device.
 	 */
-	newdev->itt = (vm_offset_t)contigmalloc(
-	    roundup2(roundup2(nvecs, 2) * esize, 0x100), M_GIC_V3_ITS,
-	    (M_NOWAIT | M_ZERO), 0, ~0UL, 0x100, 0);
-	if (newdev->itt == 0) {
+	newdev->itt_size = roundup2(roundup2(nvecs, 2) * esize, 0x100);
+	itt_addr = (vm_offset_t)contigmalloc(
+	    newdev->itt_size, M_GIC_V3_ITS, (M_NOWAIT | M_ZERO),
+	    0, ~0UL, 0x100, 0);
+	if (itt_addr == 0) {
 		lpi_free_chunk(sc, &newdev->lpis);
 		free(newdev, M_GIC_V3_ITS);
 		return (NULL);
 	}
 
 	mtx_lock_spin(&sc->its_dev_lock);
+	newdev->itt = itt_addr;
 	TAILQ_INSERT_TAIL(&sc->its_dev_list, newdev, entry);
 	mtx_unlock_spin(&sc->its_dev_lock);
 
@@ -1547,6 +1552,50 @@ its_device_alloc(struct gic_v3_its_softc
 	return (newdev);
 }
 
+static void
+its_device_free(struct gic_v3_its_softc *sc, device_t pci_dev,
+    u_int nvecs)
+{
+	struct its_dev *odev;
+
+	mtx_lock_spin(&sc->its_dev_lock);
+	/* Find existing device if any */
+	odev = its_device_find_locked(sc, pci_dev, 0);
+	if (odev == NULL) {
+		mtx_unlock_spin(&sc->its_dev_lock);
+		return;
+	}
+
+	KASSERT((nvecs <= odev->lpis.lpi_num) && (nvecs <= odev->lpis.lpi_busy),
+	    ("Invalid number of LPI vectors to free %d (total %d) (busy %d)",
+	    nvecs, odev->lpis.lpi_num, odev->lpis.lpi_busy));
+	/* Just decrement number of busy LPIs in chunk */
+	odev->lpis.lpi_busy -= nvecs;
+	if (odev->lpis.lpi_busy != 0) {
+		mtx_unlock_spin(&sc->its_dev_lock);
+		return;
+	}
+
+	/*
+	 * At that point we know that there are no busy LPIs for this device.
+	 * Entire ITS device can now be removed.
+	 */
+	mtx_unlock_spin(&sc->its_dev_lock);
+	/* Unmap device in ITS */
+	its_cmd_mapd(sc, odev, 0);
+	/* Free ITT */
+	KASSERT(odev->itt != 0, ("Invalid ITT in valid ITS device"));
+	contigfree((void *)odev->itt, odev->itt_size, M_GIC_V3_ITS);
+	/* Free chunk */
+	lpi_free_chunk(sc, &odev->lpis);
+	/* Free device */
+	mtx_lock_spin(&sc->its_dev_lock);
+	TAILQ_REMOVE(&sc->its_dev_list, odev, entry);
+	mtx_unlock_spin(&sc->its_dev_lock);
+	free((void *)odev, M_GIC_V3_ITS);
+
+}
+
 static __inline void
 its_device_asign_lpi_locked(struct gic_v3_its_softc *sc,
     struct its_dev *its_dev, u_int *irq)
@@ -1561,6 +1610,7 @@ its_device_asign_lpi_locked(struct gic_v
 	*irq = its_dev->lpis.lpi_base + (its_dev->lpis.lpi_num -
 	    its_dev->lpis.lpi_free);
 	its_dev->lpis.lpi_free--;
+	its_dev->lpis.lpi_busy++;
 }
 
 /*
@@ -1678,6 +1728,18 @@ gic_v3_its_alloc_msix(device_t dev, devi
 }
 
 int
+gic_v3_its_release_msix(device_t dev, device_t pci_dev, int irq __unused)
+{
+
+	struct gic_v3_its_softc *sc;
+
+	sc = device_get_softc(dev);
+	its_device_free(sc, pci_dev, 1);
+
+	return (0);
+}
+
+int
 gic_v3_its_alloc_msi(device_t dev, device_t pci_dev, int count, int *irqs)
 {
 	struct gic_v3_its_softc *sc;
@@ -1701,6 +1763,18 @@ gic_v3_its_alloc_msi(device_t dev, devic
 }
 
 int
+gic_v3_its_release_msi(device_t dev, device_t pci_dev, int count,
+    int *irqs __unused)
+{
+	struct gic_v3_its_softc *sc;
+
+	sc = device_get_softc(dev);
+	its_device_free(sc, pci_dev, count);
+
+	return (0);
+}
+
+int
 gic_v3_its_map_msi(device_t dev, device_t pci_dev, int irq, uint64_t *addr,
     uint32_t *data)
 {

Modified: head/sys/arm64/arm64/gic_v3_var.h
==============================================================================
--- head/sys/arm64/arm64/gic_v3_var.h	Wed May 18 09:57:11 2016	(r300135)
+++ head/sys/arm64/arm64/gic_v3_var.h	Wed May 18 10:09:07 2016	(r300136)
@@ -112,9 +112,11 @@ DECLARE_CLASS(gic_v3_its_driver);
 /* LPI chunk owned by ITS device */
 struct lpi_chunk {
 	u_int	lpi_base;
-	u_int	lpi_num;
 	u_int	lpi_free;	/* First free LPI in set */
 	u_int	*lpi_col_ids;
+
+	u_int	lpi_num;	/* Total number of LPIs in chunk */
+	u_int	lpi_busy;	/* Number of busy LPIs in chink */
 };
 
 /* ITS device */
@@ -128,6 +130,7 @@ struct its_dev {
 	struct lpi_chunk	lpis;
 	/* Virtual address of ITT */
 	vm_offset_t		itt;
+	size_t			itt_size;
 };
 TAILQ_HEAD(its_dev_list, its_dev);
 
@@ -277,7 +280,9 @@ extern devclass_t gic_v3_its_devclass;
 int gic_v3_its_detach(device_t);
 
 int gic_v3_its_alloc_msix(device_t, device_t, int *);
+int gic_v3_its_release_msix(device_t, device_t, int);
 int gic_v3_its_alloc_msi(device_t, device_t, int, int *);
+int gic_v3_its_release_msi(device_t, device_t, int, int *);
 int gic_v3_its_map_msi(device_t, device_t, int, uint64_t *, uint32_t *);
 
 int its_init_cpu(struct gic_v3_its_softc *);


More information about the svn-src-head mailing list