forked from mirrors/linux
		
	PCI: dwc: Fix MSI msi_msg DMA mapping
As of 07940c369a ("PCI: dwc: Fix MSI page leakage in suspend/resume"),
the PCIe designware host driver has been using the driver data allocation
for the msi_msg DMA mapping which can result in a DMA_MAPPING_ERROR due to
the DMA overflow check in dma_direct_map_page() when the address is greater
than 32 bits (reported in [1]). The commit was trying to address a memory
leak on suspend/resume by moving the MSI mapping to dw_pcie_host_init(),
but subsequently dropped the page allocation thinking it wasn't needed.
To fix the DMA mapping issue as well as make msi_msg DMA'able, switch back
to allocating a 32-bit page for the msi_msg. To avoid the suspend/resume
leak, allocate the page in dw_pcie_host_init() since that shouldn't be
called during suspend/resume.
[1] https://lore.kernel.org/all/Yo0soniFborDl7+C@google.com/
Signed-off-by: Will McVicker <willmcvicker@google.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Rob Herring <robh@kernel.org>
			
			
This commit is contained in:
		
							parent
							
								
									ce06bf5703
								
							
						
					
					
						commit
						35797e672f
					
				
					 2 changed files with 9 additions and 7 deletions
				
			
		|  | @ -267,8 +267,9 @@ static void dw_pcie_free_msi(struct dw_pcie_rp *pp) | |||
| 		struct dw_pcie *pci = to_dw_pcie_from_pp(pp); | ||||
| 		struct device *dev = pci->dev; | ||||
| 
 | ||||
| 		dma_unmap_single_attrs(dev, pp->msi_data, sizeof(pp->msi_msg), | ||||
| 				       DMA_FROM_DEVICE, DMA_ATTR_SKIP_CPU_SYNC); | ||||
| 		dma_unmap_page(dev, pp->msi_data, PAGE_SIZE, DMA_FROM_DEVICE); | ||||
| 		if (pp->msi_page) | ||||
| 			__free_page(pp->msi_page); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | @ -395,13 +396,14 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp) | |||
| 			if (ret) | ||||
| 				dev_warn(dev, "Failed to set DMA mask to 32-bit. Devices with only 32-bit MSI support may not work properly\n"); | ||||
| 
 | ||||
| 			pp->msi_data = dma_map_single_attrs(dev, &pp->msi_msg, | ||||
| 						      sizeof(pp->msi_msg), | ||||
| 						      DMA_FROM_DEVICE, | ||||
| 						      DMA_ATTR_SKIP_CPU_SYNC); | ||||
| 			pp->msi_page = alloc_page(GFP_DMA32); | ||||
| 			pp->msi_data = dma_map_page(dev, pp->msi_page, 0, | ||||
| 						    PAGE_SIZE, DMA_FROM_DEVICE); | ||||
| 			ret = dma_mapping_error(dev, pp->msi_data); | ||||
| 			if (ret) { | ||||
| 				dev_err(pci->dev, "Failed to map MSI data\n"); | ||||
| 				__free_page(pp->msi_page); | ||||
| 				pp->msi_page = NULL; | ||||
| 				pp->msi_data = 0; | ||||
| 				goto err_free_msi; | ||||
| 			} | ||||
|  |  | |||
|  | @ -203,8 +203,8 @@ struct dw_pcie_rp { | |||
| 	int			msi_irq; | ||||
| 	struct irq_domain	*irq_domain; | ||||
| 	struct irq_domain	*msi_domain; | ||||
| 	u16			msi_msg; | ||||
| 	dma_addr_t		msi_data; | ||||
| 	struct page		*msi_page; | ||||
| 	struct irq_chip		*msi_irq_chip; | ||||
| 	u32			num_vectors; | ||||
| 	u32			irq_mask[MAX_MSI_CTRLS]; | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Will McVicker
						Will McVicker