If unsure, say N.
 
+config DMA_API_DEBUG_SG
+       bool "Debug DMA scatter-gather usage"
+       default y
+       depends on DMA_API_DEBUG
+       help
+         Perform extra checking that callers of dma_map_sg() have respected the
+         appropriate segment length/boundary limits for the given device when
+         preparing DMA scatterlists.
+
+         This is particularly likely to have been overlooked in cases where the
+         dma_map_sg() API is used for general bulk mapping of pages rather than
+         preparing literal scatter-gather descriptors, where there is a risk of
+         unexpected behaviour from DMA API implementations if the scatterlist
+         is technically out-of-spec.
+
+         If unsure, say N.
+
 menuconfig RUNTIME_TESTING_MENU
        bool "Runtime Testing"
        def_bool y
 
        put_hash_bucket(bucket, &flags);
 }
 
+static void check_sg_segment(struct device *dev, struct scatterlist *sg)
+{
+#ifdef CONFIG_DMA_API_DEBUG_SG
+       unsigned int max_seg = dma_get_max_seg_size(dev);
+       u64 start, end, boundary = dma_get_seg_boundary(dev);
+
+       /*
+        * Either the driver forgot to set dma_parms appropriately, or
+        * whoever generated the list forgot to check them.
+        */
+       if (sg->length > max_seg)
+               err_printk(dev, NULL, "DMA-API: mapping sg segment longer than device claims to support [len=%u] [max=%u]\n",
+                          sg->length, max_seg);
+       /*
+        * In some cases this could potentially be the DMA API
+        * implementation's fault, but it would usually imply that
+        * the scatterlist was built inappropriately to begin with.
+        */
+       start = sg_dma_address(sg);
+       end = start + sg_dma_len(sg) - 1;
+       if ((start ^ end) & ~boundary)
+               err_printk(dev, NULL, "DMA-API: mapping sg segment across boundary [start=0x%016llx] [end=0x%016llx] [boundary=0x%016llx]\n",
+                          start, end, boundary);
+#endif
+}
+
 void debug_dma_map_page(struct device *dev, struct page *page, size_t offset,
                        size_t size, int direction, dma_addr_t dma_addr,
                        bool map_single)
                        check_for_illegal_area(dev, sg_virt(s), sg_dma_len(s));
                }
 
+               check_sg_segment(dev, s);
+
                add_dma_entry(entry);
        }
 }