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

[POWERPC] Define pci_unmap_addr() et al. when CONFIG_NOT_COHERENT_CACHE=y

The current PowerPC code makes pci_unmap_addr(), pci_unmap_addr_set(),
and friends trivial for all 32-bit kernels. This is reasonable, since
for those kernels it is true that pci_unmap_single() does not need the
DMA address from the original DMA mapping -- in fact, it is a NOP.

However, I recently tried the tg3 driver on a PowerPC 440SPe machine,
which runs a 32-bit kernel and has non-cache-coherent PCI DMA. I
found that the tg3 driver crashed in pci_dma_sync_single_for_cpu(),
since for non-coherent systems, that function must invalidate the
cache for the DMA address range requested, and therefore it does use
the address passed in. tg3 uses a DMA address it stashes away with
pci_unmap_addr_set() and retrieves with pci_unmap_addr(). Of course,
since pci_unmap_addr() is defined to (0) right now, this doesn't work.

It seems to me that the tg3 driver is using pci_unmap_addr() in a
legitimate way -- I wouldn't want to have to teach all drivers that
they should use pci_unmap_addr() if they only need the address for
unmapping functions, but if they want the pci_dma_sync functions, then
they have to store the DMA address without the helper macros.
The right fix therefore seems to be in the definition of the macros in
<asm/pci.h> -- we should use the trivial versions only for 32-bit
kernels for coherent systems, and the real versions for both 64-bit
kernels and non-coherent systems.

Signed-off-by: Roland Dreier <rolandd@cisco.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>

authored by

Roland Dreier and committed by
Paul Mackerras
1d4454e7 885ed0fb

+45 -11
+22 -11
include/asm-powerpc/pci.h
··· 143 143 /* Tell drivers/pci/proc.c that we have pci_mmap_page_range() */ 144 144 #define HAVE_PCI_MMAP 1 145 145 146 - #ifdef CONFIG_PPC64 147 - /* pci_unmap_{single,page} is not a nop, thus... */ 146 + #if defined(CONFIG_PPC64) || defined(CONFIG_NOT_COHERENT_CACHE) 147 + /* 148 + * For 64-bit kernels, pci_unmap_{single,page} is not a nop. 149 + * For 32-bit non-coherent kernels, pci_dma_sync_single_for_cpu() and 150 + * so on are not nops. 151 + * and thus... 152 + */ 148 153 #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) \ 149 154 dma_addr_t ADDR_NAME; 150 155 #define DECLARE_PCI_UNMAP_LEN(LEN_NAME) \ ··· 162 157 ((PTR)->LEN_NAME) 163 158 #define pci_unmap_len_set(PTR, LEN_NAME, VAL) \ 164 159 (((PTR)->LEN_NAME) = (VAL)) 160 + 161 + #else /* 32-bit && coherent */ 162 + 163 + /* pci_unmap_{page,single} is a nop so... */ 164 + #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) 165 + #define DECLARE_PCI_UNMAP_LEN(LEN_NAME) 166 + #define pci_unmap_addr(PTR, ADDR_NAME) (0) 167 + #define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) do { } while (0) 168 + #define pci_unmap_len(PTR, LEN_NAME) (0) 169 + #define pci_unmap_len_set(PTR, LEN_NAME, VAL) do { } while (0) 170 + 171 + #endif /* CONFIG_PPC64 || CONFIG_NOT_COHERENT_CACHE */ 172 + 173 + #ifdef CONFIG_PPC64 165 174 166 175 /* The PCI address space does not equal the physical memory address 167 176 * space (we have an IOMMU). The IDE and SCSI device layers use ··· 191 172 */ 192 173 #define PCI_DMA_BUS_IS_PHYS (1) 193 174 194 - /* pci_unmap_{page,single} is a nop so... */ 195 - #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) 196 - #define DECLARE_PCI_UNMAP_LEN(LEN_NAME) 197 - #define pci_unmap_addr(PTR, ADDR_NAME) (0) 198 - #define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) do { } while (0) 199 - #define pci_unmap_len(PTR, LEN_NAME) (0) 200 - #define pci_unmap_len_set(PTR, LEN_NAME, VAL) do { } while (0) 201 - 202 175 #endif /* CONFIG_PPC64 */ 203 - 176 + 204 177 extern void pcibios_resource_to_bus(struct pci_dev *dev, 205 178 struct pci_bus_region *region, 206 179 struct resource *res);
+23
include/asm-ppc/pci.h
··· 61 61 */ 62 62 #define PCI_DMA_BUS_IS_PHYS (1) 63 63 64 + #ifdef CONFIG_NOT_COHERENT_CACHE 65 + /* 66 + * pci_unmap_{page,single} are NOPs but pci_dma_sync_single_for_cpu() 67 + * and so on are not, so... 68 + */ 69 + 70 + #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) \ 71 + dma_addr_t ADDR_NAME; 72 + #define DECLARE_PCI_UNMAP_LEN(LEN_NAME) \ 73 + __u32 LEN_NAME; 74 + #define pci_unmap_addr(PTR, ADDR_NAME) \ 75 + ((PTR)->ADDR_NAME) 76 + #define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) \ 77 + (((PTR)->ADDR_NAME) = (VAL)) 78 + #define pci_unmap_len(PTR, LEN_NAME) \ 79 + ((PTR)->LEN_NAME) 80 + #define pci_unmap_len_set(PTR, LEN_NAME, VAL) \ 81 + (((PTR)->LEN_NAME) = (VAL)) 82 + 83 + #else /* coherent */ 84 + 64 85 /* pci_unmap_{page,single} is a nop so... */ 65 86 #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) 66 87 #define DECLARE_PCI_UNMAP_LEN(LEN_NAME) ··· 89 68 #define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) do { } while (0) 90 69 #define pci_unmap_len(PTR, LEN_NAME) (0) 91 70 #define pci_unmap_len_set(PTR, LEN_NAME, VAL) do { } while (0) 71 + 72 + #endif /* CONFIG_NOT_COHERENT_CACHE */ 92 73 93 74 #ifdef CONFIG_PCI 94 75 static inline void pci_dma_burst_advice(struct pci_dev *pdev,