From c60fe750b505dbc27c4072dd1c4c9fac9820c2f0 Mon Sep 17 00:00:00 2001 From: patrick Date: Tue, 25 Apr 2023 10:35:48 +0000 Subject: [PATCH] Invalidate ITS caches during suspend/resume cycle to commit the changes to the LPIs. So far we have only flipped the enable bit in the shared memory, but it turns out that the state is actually cached in the ITS. We have to send an invalidation to flush it, both after disabling and enabling the LPI. We probably also should do it after establishing an interrupt, and especially when disestablishing, e.g. for PCIe hotplug. Since we do not currently store the device/event IDs we cannot do a targeted invalidation and have to fall back to sending one that clears the whole cache to each ITS. In the future we should keep some more state per established LPI. Furthermore we currently keep a list of LPIs in each ITS instance, which means in case we have multiple ITS we will re-use LPI numbers. But since there's no relevant HW so far that has those, there's no rish to fix that. This fixes suspend/resume on x13s with NVMe+MSI. ok kettenis@ --- sys/arch/arm64/dev/agintc.c | 38 ++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/sys/arch/arm64/dev/agintc.c b/sys/arch/arm64/dev/agintc.c index 905b5118c70..12f7cac386c 100644 --- a/sys/arch/arm64/dev/agintc.c +++ b/sys/arch/arm64/dev/agintc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: agintc.c,v 1.47 2023/01/27 23:11:59 kettenis Exp $ */ +/* $OpenBSD: agintc.c,v 1.48 2023/04/25 10:35:48 patrick Exp $ */ /* * Copyright (c) 2007, 2009, 2011, 2017 Dale Rahn * Copyright (c) 2018 Mark Kettenis @@ -257,6 +257,8 @@ int agintc_ipi_nop(void *v); int agintc_ipi_combined(void *); void agintc_send_ipi(struct cpu_info *, int); +void agintc_msi_invall(void); + const struct cfattach agintc_ca = { sizeof (struct agintc_softc), agintc_match, agintc_attach }; @@ -841,7 +843,12 @@ agintc_enable_wakeup(void) cpu_dcache_wb_range((vaddr_t)&prop[irq], sizeof(*prop)); __asm volatile("dsb sy"); + + /* XXX: Invalidate cache? */ } + + /* Invalidate cache. */ + agintc_msi_invall(); } void @@ -879,6 +886,9 @@ agintc_disable_wakeup(void) sizeof(*prop)); __asm volatile("dsb sy"); } + + /* Invalidate cache. */ + agintc_msi_invall(); } void @@ -1291,6 +1301,8 @@ agintc_intr_disestablish(void *cookie) cpu_dcache_wb_range((vaddr_t)&prop[irqno - LPI_BASE], sizeof(*prop)); __asm volatile("dsb sy"); + + /* XXX: Invalidate cache? */ } if (ih->ih_name != NULL) @@ -1509,6 +1521,8 @@ struct gits_cmd { #define MAPD 0x08 #define MAPC 0x09 #define MAPTI 0x0a +#define INV 0x0c +#define INVALL 0x0d #define GITS_CMDQ_SIZE (64 * 1024) #define GITS_CMDQ_NENTRIES (GITS_CMDQ_SIZE / sizeof(struct gits_cmd)) @@ -1865,6 +1879,28 @@ agintc_msi_find_device(struct agintc_msi_softc *sc, uint32_t deviceid) return agintc_msi_create_device(sc, deviceid); } +void +agintc_msi_invall(void) +{ + struct cfdriver *cd = &agintcmsi_cd; + struct agintc_msi_softc *sc; + struct gits_cmd cmd; + int i, j; + + for (i = 0; i < cd->cd_ndevs; i++) { + if (cd->cd_devs[i] == NULL) + continue; + sc = cd->cd_devs[i]; + for (j = 0; j < ncpus; j++) { + memset(&cmd, 0, sizeof(cmd)); + cmd.cmd = INVALL; + cmd.dw2 = j; + agintc_msi_send_cmd(sc, &cmd); + agintc_msi_wait_cmd(sc); + } + } +} + void * agintc_intr_establish_msi(void *self, uint64_t *addr, uint64_t *data, int level, struct cpu_info *ci, int (*func)(void *), void *arg, char *name) -- 2.20.1