struct page     **pages;
 };
 
+enum cpa_warn {
+       CPA_PROTECT,
+       CPA_DETECT,
+};
+
+static const int cpa_warn_level = CPA_PROTECT;
+
 /*
  * Serialize cpa() (for !DEBUG_PAGEALLOC which uses large identity mappings)
  * using cpa_lock. So that we don't allow any other cpu, with stale large tlb
 }
 #endif
 
+static inline bool conflicts(pgprot_t prot, pgprotval_t val)
+{
+       return (pgprot_val(prot) & ~val) != pgprot_val(prot);
+}
+
+static inline void check_conflict(int warnlvl, pgprot_t prot, pgprotval_t val,
+                                 unsigned long start, unsigned long end,
+                                 unsigned long pfn, const char *txt)
+{
+       static const char *lvltxt[] = {
+               [CPA_PROTECT]   = "protect",
+               [CPA_DETECT]    = "detect",
+       };
+
+       if (warnlvl > cpa_warn_level || !conflicts(prot, val))
+               return;
+
+       pr_warn("CPA %8s %10s: 0x%016lx - 0x%016lx PFN %lx req %016llx prevent %016llx\n",
+               lvltxt[warnlvl], txt, start, end, pfn, (unsigned long long)pgprot_val(prot),
+               (unsigned long long)val);
+}
+
 /*
  * Certain areas of memory on x86 require very specific protection flags,
  * for example the BIOS area or kernel text. Callers don't always get this
  * checks and fixes these known static required protection bits.
  */
 static inline pgprot_t static_protections(pgprot_t prot, unsigned long start,
-                                         unsigned long pfn, unsigned long npg)
+                                         unsigned long pfn, unsigned long npg,
+                                         int warnlvl)
 {
-       pgprotval_t forbidden;
+       pgprotval_t forbidden, res;
        unsigned long end;
 
        /* Operate on the virtual address */
        end = start + npg * PAGE_SIZE - 1;
-       forbidden  = protect_kernel_text(start, end);
-       forbidden |= protect_kernel_text_ro(start, end);
+
+       res = protect_kernel_text(start, end);
+       check_conflict(warnlvl, prot, res, start, end, pfn, "Text NX");
+       forbidden = res;
+
+       res = protect_kernel_text_ro(start, end);
+       check_conflict(warnlvl, prot, res, start, end, pfn, "Text RO");
+       forbidden |= res;
 
        /* Check the PFN directly */
-       forbidden |= protect_pci_bios(pfn, pfn + npg - 1);
-       forbidden |= protect_rodata(pfn, pfn + npg - 1);
+       res = protect_pci_bios(pfn, pfn + npg - 1);
+       check_conflict(warnlvl, prot, res, start, end, pfn, "PCIBIOS NX");
+       forbidden |= res;
+
+       res = protect_rodata(pfn, pfn + npg - 1);
+       check_conflict(warnlvl, prot, res, start, end, pfn, "Rodata RO");
+       forbidden |= res;
 
        return __pgprot(pgprot_val(prot) & ~forbidden);
 }
         * in it results in a different pgprot than the first one of the
         * requested range. If yes, then the page needs to be split.
         */
-       new_prot = static_protections(req_prot, address, pfn, 1);
+       new_prot = static_protections(req_prot, address, pfn, 1, CPA_DETECT);
        pfn = old_pfn;
        for (i = 0, addr = lpaddr; i < numpages; i++, addr += PAGE_SIZE, pfn++) {
-               pgprot_t chk_prot = static_protections(req_prot, addr, pfn, 1);
+               pgprot_t chk_prot = static_protections(req_prot, addr, pfn, 1,
+                                                      CPA_DETECT);
 
                if (pgprot_val(chk_prot) != pgprot_val(new_prot))
                        return 1;
                pgprot_val(new_prot) &= ~pgprot_val(cpa->mask_clr);
                pgprot_val(new_prot) |= pgprot_val(cpa->mask_set);
 
-               new_prot = static_protections(new_prot, address, pfn, 1);
+               new_prot = static_protections(new_prot, address, pfn, 1,
+                                             CPA_PROTECT);
 
                new_prot = pgprot_clear_protnone_bits(new_prot);