#include <linux/iova.h>
 #include <linux/irq.h>
 #include <linux/mm.h>
+#include <linux/mutex.h>
 #include <linux/pci.h>
 #include <linux/scatterlist.h>
 #include <linux/vmalloc.h>
                dma_addr_t              msi_iova;
        };
        struct list_head                msi_page_list;
-       spinlock_t                      msi_lock;
 
        /* Domain for flush queue callback; NULL if flush queue not in use */
        struct iommu_domain             *fq_domain;
 
        cookie = kzalloc(sizeof(*cookie), GFP_KERNEL);
        if (cookie) {
-               spin_lock_init(&cookie->msi_lock);
                INIT_LIST_HEAD(&cookie->msi_page_list);
                cookie->type = type;
        }
                if (msi_page->phys == msi_addr)
                        return msi_page;
 
-       msi_page = kzalloc(sizeof(*msi_page), GFP_ATOMIC);
+       msi_page = kzalloc(sizeof(*msi_page), GFP_KERNEL);
        if (!msi_page)
                return NULL;
 
        struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
        struct iommu_dma_cookie *cookie;
        struct iommu_dma_msi_page *msi_page;
-       unsigned long flags;
+       static DEFINE_MUTEX(msi_prepare_lock); /* see below */
 
        if (!domain || !domain->iova_cookie) {
                desc->iommu_cookie = NULL;
        cookie = domain->iova_cookie;
 
        /*
-        * We disable IRQs to rule out a possible inversion against
-        * irq_desc_lock if, say, someone tries to retarget the affinity
-        * of an MSI from within an IPI handler.
+        * In fact the whole prepare operation should already be serialised by
+        * irq_domain_mutex further up the callchain, but that's pretty subtle
+        * on its own, so consider this locking as failsafe documentation...
         */
-       spin_lock_irqsave(&cookie->msi_lock, flags);
+       mutex_lock(&msi_prepare_lock);
        msi_page = iommu_dma_get_msi_page(dev, msi_addr, domain);
-       spin_unlock_irqrestore(&cookie->msi_lock, flags);
+       mutex_unlock(&msi_prepare_lock);
 
        msi_desc_set_iommu_cookie(desc, msi_page);