From owner-svn-src-all@freebsd.org Wed May 18 10:09:08 2016 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 79BBCB3E8E5; Wed, 18 May 2016 10:09:08 +0000 (UTC) (envelope-from zbb@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 mx1.freebsd.org (Postfix) with ESMTPS id 55D5714D2; Wed, 18 May 2016 10:09:08 +0000 (UTC) (envelope-from zbb@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id u4IA97HP025265; Wed, 18 May 2016 10:09:07 GMT (envelope-from zbb@FreeBSD.org) Received: (from zbb@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id u4IA97mO025263; Wed, 18 May 2016 10:09:07 GMT (envelope-from zbb@FreeBSD.org) Message-Id: <201605181009.u4IA97mO025263@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: zbb set sender to zbb@FreeBSD.org using -f From: Zbigniew Bodek Date: Wed, 18 May 2016 10:09:07 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r300136 - head/sys/arm64/arm64 X-SVN-Group: head 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.22 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: Wed, 18 May 2016 10:09:08 -0000 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 *);