Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc/powernv: Override dma_get_required_mask()

The dma_get_required_mask() function is used by some drivers to
query the platform about what DMA mask is needed to cover all of
memory. This is a bit of a strange semantic when we have to choose
between IOMMU translation or bypass, but essentially what it means
is "what DMA mask will give best performances".

Currently, our IOMMU backend always returns a 32-bit mask here, we
don't do anything special to it when we have bypass available. This
causes some drivers to choose a 32-bit mask, thus losing the ability
to use the bypass window, thinking this is more efficient. The problem
was reported from the driver of following device:

0004:03:00.0 0107: 1000:0087 (rev 05)
0004:03:00.0 Serial Attached SCSI controller: LSI Logic / Symbios \
Logic SAS2308 PCI-Express Fusion-MPT SAS-2 (rev 05)

This patch adds an override of that function in order to, instead,
return a 64-bit mask whenever a bypass window is available in order
for drivers to prefer this configuration.

Reported-by: Murali N. Iyer <mniyer@us.ibm.com>
Suggested-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>

authored by

Gavin Shan and committed by
Michael Ellerman
fe7e85c6 372fb80d

+62 -4
+1
arch/powerpc/include/asm/dma-mapping.h
··· 135 135 136 136 extern int dma_set_mask(struct device *dev, u64 dma_mask); 137 137 extern int __dma_set_mask(struct device *dev, u64 dma_mask); 138 + extern u64 __dma_get_required_mask(struct device *dev); 138 139 139 140 #define dma_alloc_coherent(d,s,h,f) dma_alloc_attrs(d,s,h,f,NULL) 140 141
+10 -4
arch/powerpc/kernel/dma.c
··· 202 202 *dev->dma_mask = dma_mask; 203 203 return 0; 204 204 } 205 + 205 206 int dma_set_mask(struct device *dev, u64 dma_mask) 206 207 { 207 208 if (ppc_md.dma_set_mask) ··· 211 210 } 212 211 EXPORT_SYMBOL(dma_set_mask); 213 212 214 - u64 dma_get_required_mask(struct device *dev) 213 + u64 __dma_get_required_mask(struct device *dev) 215 214 { 216 215 struct dma_map_ops *dma_ops = get_dma_ops(dev); 217 - 218 - if (ppc_md.dma_get_required_mask) 219 - return ppc_md.dma_get_required_mask(dev); 220 216 221 217 if (unlikely(dma_ops == NULL)) 222 218 return 0; ··· 222 224 return dma_ops->get_required_mask(dev); 223 225 224 226 return DMA_BIT_MASK(8 * sizeof(dma_addr_t)); 227 + } 228 + 229 + u64 dma_get_required_mask(struct device *dev) 230 + { 231 + if (ppc_md.dma_get_required_mask) 232 + return ppc_md.dma_get_required_mask(dev); 233 + 234 + return __dma_get_required_mask(dev); 225 235 } 226 236 EXPORT_SYMBOL_GPL(dma_get_required_mask); 227 237
+23
arch/powerpc/platforms/powernv/pci-ioda.c
··· 889 889 return 0; 890 890 } 891 891 892 + static u64 pnv_pci_ioda_dma_get_required_mask(struct pnv_phb *phb, 893 + struct pci_dev *pdev) 894 + { 895 + struct pci_dn *pdn = pci_get_pdn(pdev); 896 + struct pnv_ioda_pe *pe; 897 + u64 end, mask; 898 + 899 + if (WARN_ON(!pdn || pdn->pe_number == IODA_INVALID_PE)) 900 + return 0; 901 + 902 + pe = &phb->ioda.pe_array[pdn->pe_number]; 903 + if (!pe->tce_bypass_enabled) 904 + return __dma_get_required_mask(&pdev->dev); 905 + 906 + 907 + end = pe->tce_bypass_base + memblock_end_of_DRAM(); 908 + mask = 1ULL << (fls64(end) - 1); 909 + mask += mask - 1; 910 + 911 + return mask; 912 + } 913 + 892 914 static void pnv_ioda_setup_bus_dma(struct pnv_ioda_pe *pe, 893 915 struct pci_bus *bus, 894 916 bool add_to_iommu_group) ··· 1803 1781 /* Setup TCEs */ 1804 1782 phb->dma_dev_setup = pnv_pci_ioda_dma_dev_setup; 1805 1783 phb->dma_set_mask = pnv_pci_ioda_dma_set_mask; 1784 + phb->dma_get_required_mask = pnv_pci_ioda_dma_get_required_mask; 1806 1785 1807 1786 /* Setup shutdown function for kexec */ 1808 1787 phb->shutdown = pnv_pci_ioda_shutdown;
+11
arch/powerpc/platforms/powernv/pci.c
··· 761 761 return __dma_set_mask(&pdev->dev, dma_mask); 762 762 } 763 763 764 + u64 pnv_pci_dma_get_required_mask(struct pci_dev *pdev) 765 + { 766 + struct pci_controller *hose = pci_bus_to_host(pdev->bus); 767 + struct pnv_phb *phb = hose->private_data; 768 + 769 + if (phb && phb->dma_get_required_mask) 770 + return phb->dma_get_required_mask(phb, pdev); 771 + 772 + return __dma_get_required_mask(&pdev->dev); 773 + } 774 + 764 775 void pnv_pci_shutdown(void) 765 776 { 766 777 struct pci_controller *hose;
+2
arch/powerpc/platforms/powernv/pci.h
··· 124 124 void (*dma_dev_setup)(struct pnv_phb *phb, struct pci_dev *pdev); 125 125 int (*dma_set_mask)(struct pnv_phb *phb, struct pci_dev *pdev, 126 126 u64 dma_mask); 127 + u64 (*dma_get_required_mask)(struct pnv_phb *phb, 128 + struct pci_dev *pdev); 127 129 void (*fixup_phb)(struct pci_controller *hose); 128 130 u32 (*bdfn_to_pe)(struct pnv_phb *phb, struct pci_bus *bus, u32 devfn); 129 131 void (*shutdown)(struct pnv_phb *phb);
+6
arch/powerpc/platforms/powernv/powernv.h
··· 13 13 extern void pnv_pci_init(void); 14 14 extern void pnv_pci_shutdown(void); 15 15 extern int pnv_pci_dma_set_mask(struct pci_dev *pdev, u64 dma_mask); 16 + extern u64 pnv_pci_dma_get_required_mask(struct pci_dev *pdev); 16 17 #else 17 18 static inline void pnv_pci_init(void) { } 18 19 static inline void pnv_pci_shutdown(void) { } ··· 21 20 static inline int pnv_pci_dma_set_mask(struct pci_dev *pdev, u64 dma_mask) 22 21 { 23 22 return -ENODEV; 23 + } 24 + 25 + static inline u64 pnv_pci_dma_get_required_mask(struct pci_dev *pdev) 26 + { 27 + return 0; 24 28 } 25 29 #endif 26 30
+9
arch/powerpc/platforms/powernv/setup.c
··· 173 173 return __dma_set_mask(dev, dma_mask); 174 174 } 175 175 176 + static u64 pnv_dma_get_required_mask(struct device *dev) 177 + { 178 + if (dev_is_pci(dev)) 179 + return pnv_pci_dma_get_required_mask(to_pci_dev(dev)); 180 + 181 + return __dma_get_required_mask(dev); 182 + } 183 + 176 184 static void pnv_shutdown(void) 177 185 { 178 186 /* Let the PCI code clear up IODA tables */ ··· 343 335 .power_save = power7_idle, 344 336 .calibrate_decr = generic_calibrate_decr, 345 337 .dma_set_mask = pnv_dma_set_mask, 338 + .dma_get_required_mask = pnv_dma_get_required_mask, 346 339 #ifdef CONFIG_KEXEC 347 340 .kexec_cpu_down = pnv_kexec_cpu_down, 348 341 #endif