2121#include <linux/hw_random.h>
2222#include <linux/ccp.h>
2323#include <linux/firmware.h>
24+ #include <linux/panic_notifier.h>
2425#include <linux/gfp.h>
2526#include <linux/cpufeature.h>
2627#include <linux/fs.h>
@@ -143,6 +144,25 @@ static int sev_wait_cmd_ioc(struct sev_device *sev,
143144{
144145 int ret ;
145146
147+ /*
148+ * If invoked during panic handling, local interrupts are disabled,
149+ * so the PSP command completion interrupt can't be used. Poll for
150+ * PSP command completion instead.
151+ */
152+ if (irqs_disabled ()) {
153+ unsigned long timeout_usecs = (timeout * USEC_PER_SEC ) / 10 ;
154+
155+ /* Poll for SEV command completion: */
156+ while (timeout_usecs -- ) {
157+ * reg = ioread32 (sev -> io_regs + sev -> vdata -> cmdresp_reg );
158+ if (* reg & PSP_CMDRESP_RESP )
159+ return 0 ;
160+
161+ udelay (10 );
162+ }
163+ return - ETIMEDOUT ;
164+ }
165+
146166 ret = wait_event_timeout (sev -> int_queue ,
147167 sev -> int_rcvd , timeout * HZ );
148168 if (!ret )
@@ -1338,17 +1358,6 @@ static int __sev_platform_shutdown_locked(int *error)
13381358 return ret ;
13391359}
13401360
1341- static int sev_platform_shutdown (int * error )
1342- {
1343- int rc ;
1344-
1345- mutex_lock (& sev_cmd_mutex );
1346- rc = __sev_platform_shutdown_locked (NULL );
1347- mutex_unlock (& sev_cmd_mutex );
1348-
1349- return rc ;
1350- }
1351-
13521361static int sev_get_platform_state (int * state , int * error )
13531362{
13541363 struct sev_user_data_status data ;
@@ -1624,7 +1633,7 @@ static int sev_update_firmware(struct device *dev)
16241633 return ret ;
16251634}
16261635
1627- static int __sev_snp_shutdown_locked (int * error )
1636+ static int __sev_snp_shutdown_locked (int * error , bool panic )
16281637{
16291638 struct sev_device * sev = psp_master -> sev_data ;
16301639 struct sev_data_snp_shutdown_ex data ;
@@ -1637,7 +1646,16 @@ static int __sev_snp_shutdown_locked(int *error)
16371646 data .len = sizeof (data );
16381647 data .iommu_snp_shutdown = 1 ;
16391648
1640- wbinvd_on_all_cpus ();
1649+ /*
1650+ * If invoked during panic handling, local interrupts are disabled
1651+ * and all CPUs are stopped, so wbinvd_on_all_cpus() can't be called.
1652+ * In that case, a wbinvd() is done on remote CPUs via the NMI
1653+ * callback, so only a local wbinvd() is needed here.
1654+ */
1655+ if (!panic )
1656+ wbinvd_on_all_cpus ();
1657+ else
1658+ wbinvd ();
16411659
16421660 ret = __sev_do_cmd_locked (SEV_CMD_SNP_SHUTDOWN_EX , & data , error );
16431661 /* SHUTDOWN may require DF_FLUSH */
@@ -1681,17 +1699,6 @@ static int __sev_snp_shutdown_locked(int *error)
16811699 return ret ;
16821700}
16831701
1684- static int sev_snp_shutdown (int * error )
1685- {
1686- int rc ;
1687-
1688- mutex_lock (& sev_cmd_mutex );
1689- rc = __sev_snp_shutdown_locked (error );
1690- mutex_unlock (& sev_cmd_mutex );
1691-
1692- return rc ;
1693- }
1694-
16951702static int sev_ioctl_do_pek_import (struct sev_issue_cmd * argp , bool writable )
16961703{
16971704 struct sev_device * sev = psp_master -> sev_data ;
@@ -2139,19 +2146,28 @@ int sev_dev_init(struct psp_device *psp)
21392146 return ret ;
21402147}
21412148
2142- static void sev_firmware_shutdown (struct sev_device * sev )
2149+ static void __sev_firmware_shutdown (struct sev_device * sev , bool panic )
21432150{
21442151 int error ;
21452152
2146- sev_platform_shutdown (NULL );
2153+ __sev_platform_shutdown_locked (NULL );
21472154
21482155 if (sev_es_tmr ) {
2149- /* The TMR area was encrypted, flush it from the cache */
2150- wbinvd_on_all_cpus ();
2156+ /*
2157+ * The TMR area was encrypted, flush it from the cache.
2158+ *
2159+ * If invoked during panic handling, local interrupts are
2160+ * disabled and all CPUs are stopped, so wbinvd_on_all_cpus()
2161+ * can't be used. In that case, wbinvd() is done on remote CPUs
2162+ * via the NMI callback, and done for this CPU later during
2163+ * SNP shutdown, so wbinvd_on_all_cpus() can be skipped.
2164+ */
2165+ if (!panic )
2166+ wbinvd_on_all_cpus ();
21512167
21522168 __snp_free_firmware_pages (virt_to_page (sev_es_tmr ),
21532169 get_order (sev_es_tmr_size ),
2154- false );
2170+ true );
21552171 sev_es_tmr = NULL ;
21562172 }
21572173
@@ -2167,7 +2183,14 @@ static void sev_firmware_shutdown(struct sev_device *sev)
21672183 snp_range_list = NULL ;
21682184 }
21692185
2170- sev_snp_shutdown (& error );
2186+ __sev_snp_shutdown_locked (& error , panic );
2187+ }
2188+
2189+ static void sev_firmware_shutdown (struct sev_device * sev )
2190+ {
2191+ mutex_lock (& sev_cmd_mutex );
2192+ __sev_firmware_shutdown (sev , false);
2193+ mutex_unlock (& sev_cmd_mutex );
21712194}
21722195
21732196void sev_dev_destroy (struct psp_device * psp )
@@ -2185,6 +2208,29 @@ void sev_dev_destroy(struct psp_device *psp)
21852208 psp_clear_sev_irq_handler (psp );
21862209}
21872210
2211+ static int snp_shutdown_on_panic (struct notifier_block * nb ,
2212+ unsigned long reason , void * arg )
2213+ {
2214+ struct sev_device * sev = psp_master -> sev_data ;
2215+
2216+ /*
2217+ * If sev_cmd_mutex is already acquired, then it's likely
2218+ * another PSP command is in flight and issuing a shutdown
2219+ * would fail in unexpected ways. Rather than create even
2220+ * more confusion during a panic, just bail out here.
2221+ */
2222+ if (mutex_is_locked (& sev_cmd_mutex ))
2223+ return NOTIFY_DONE ;
2224+
2225+ __sev_firmware_shutdown (sev , true);
2226+
2227+ return NOTIFY_DONE ;
2228+ }
2229+
2230+ static struct notifier_block snp_panic_notifier = {
2231+ .notifier_call = snp_shutdown_on_panic ,
2232+ };
2233+
21882234int sev_issue_cmd_external_user (struct file * filep , unsigned int cmd ,
21892235 void * data , int * error )
21902236{
@@ -2222,6 +2268,8 @@ void sev_pci_init(void)
22222268 dev_info (sev -> dev , "SEV%s API:%d.%d build:%d\n" , sev -> snp_initialized ?
22232269 "-SNP" : "" , sev -> api_major , sev -> api_minor , sev -> build );
22242270
2271+ atomic_notifier_chain_register (& panic_notifier_list ,
2272+ & snp_panic_notifier );
22252273 return ;
22262274
22272275err :
@@ -2236,4 +2284,7 @@ void sev_pci_exit(void)
22362284 return ;
22372285
22382286 sev_firmware_shutdown (sev );
2287+
2288+ atomic_notifier_chain_unregister (& panic_notifier_list ,
2289+ & snp_panic_notifier );
22392290}
0 commit comments