Hi,
This patch fixes the following things for pci.h:
- flush cache only on non-coherent archs
- fix usage of bus_to_baddr
- fix DECLARE_PCI_UNMAP_ADDR, ... for non-coherent arch where
pci_unmap_* functions are not a empty.
- change __pa, '+ PAGE_OFFSET' to virt_to_phys() and
phys_to_virt()
- adds sg->offset to page_address(sg->page) when mapping a
scatter-gather buffer
This is a patch against CVS HEAD (2.5.5)/mips64. It should apply
directly to 2.5.5/mips as well. As for 2.5.4 care should be taken with the
old 'sg->address' interface for scatter-gather buffers, but these fixes
should probably be applied as well.
Please comment and/or apply,
Vivien.
--- linux/include/asm-mips64/addrspace.h Thu Aug 1 20:22:00 2002
+++ linux.patch/include/asm-mips64/addrspace.h Thu Aug 1 20:21:54 2002
@@ -58,7 +58,7 @@
#ifndef __ASSEMBLY__
#define PHYSADDR(a) ({ \
- const _ATYPE64_ _a = (a); \
+ const _ATYPE64_ _a = _ACAST64_ (a); \
_a == _ACAST32_ _a ? CPHYSADDR(_a) : XPHYSADDR(_a); })
#endif
--- linux/include/asm-mips64/pci.h Mon Aug 12 00:25:23 2002
+++ linux.patch/include/asm-mips64/pci.h Mon Aug 12 00:19:27 2002
@@ -120,14 +120,20 @@
static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
size_t size, int direction)
{
+#ifdef CONFIG_NONCOHERENT_IO
unsigned long addr = (unsigned long) ptr;
+#endif
if (direction == PCI_DMA_NONE)
BUG();
+#ifdef CONFIG_NONCOHERENT_IO
+ /* even if DMAing from device, make sure there is no dirty entry */
+ /* in the cache that could be evicted during the DMA transfer */
+ /* thus overwritting the device data */
dma_cache_wback_inv(addr, size);
-
- return bus_to_baddr(hwdev->bus->number, __pa(ptr));
+#endif
+ return bus_to_baddr(hwdev, virt_to_phys(ptr));
}
/*
@@ -141,17 +147,37 @@
static inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
size_t size, int direction)
{
+#ifdef CONFIG_NONCOHERENT_IO
+ unsigned long addr;
+#endif
+
if (direction == PCI_DMA_NONE)
BUG();
- if (direction != PCI_DMA_TODEVICE) {
- unsigned long addr;
+ if (direction == PCI_DMA_TODEVICE)
+ return; /* nothing to do */
- addr = baddr_to_bus(hwdev, dma_addr) + PAGE_OFFSET;
- dma_cache_wback_inv(addr, size);
- }
+#ifdef CONFIG_NONCOHERENT_IO
+ addr = (unsigned long) phys_to_virt(baddr_to_bus(hwdev, dma_addr));
+ dma_cache_wback_inv(addr, size);
+#endif
}
+#ifdef CONFIG_NONCOHERENT_IO
+/* pci_unmap_{single,page} is not a nop, thus... */
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) \
+ dma_addr_t ADDR_NAME;
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) \
+ __u32 LEN_NAME;
+#define pci_unmap_addr(PTR, ADDR_NAME) \
+ ((PTR)->ADDR_NAME)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) \
+ (((PTR)->ADDR_NAME) = (VAL))
+#define pci_unmap_len(PTR, LEN_NAME) \
+ ((PTR)->LEN_NAME)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL) \
+ (((PTR)->LEN_NAME) = (VAL))
+#else
/* pci_unmap_{page,single} is a nop so... */
#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
@@ -159,6 +185,7 @@
#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) do { } while (0)
#define pci_unmap_len(PTR, LEN_NAME) (0)
#define pci_unmap_len_set(PTR, LEN_NAME, VAL) do { } while (0)
+#endif
/*
* pci_{map,unmap}_single_page maps a kernel page to a dma_addr_t. identical
@@ -168,13 +195,17 @@
unsigned long offset, size_t size,
int direction)
{
+#ifdef CONFIG_NONCOHERENT_IO
unsigned long addr;
+#endif
if (direction == PCI_DMA_NONE)
BUG();
+#ifdef CONFIG_NONCOHERENT_IO
addr = (unsigned long) page_address(page) + offset;
dma_cache_wback_inv(addr, size);
+#endif
return bus_to_baddr(hwdev, page_to_phys(page) + offset);
}
@@ -182,15 +213,20 @@
static inline void pci_unmap_page(struct pci_dev *hwdev, dma_addr_t
dma_address,
size_t size, int direction)
{
+#ifdef CONFIG_NONCOHERENT_IO
+ unsigned long addr;
+#endif
+
if (direction == PCI_DMA_NONE)
BUG();
- if (direction != PCI_DMA_TODEVICE) {
- unsigned long addr;
+ if (direction == PCI_DMA_TODEVICE)
+ return; /* nothing to do */
- addr = baddr_to_bus(hwdev, dma_address) + PAGE_OFFSET;
- dma_cache_wback_inv(addr, size);
- }
+#ifdef CONFIG_NONCOHERENT_IO
+ addr = (unsigned long) phys_to_virt(baddr_to_bus(hwdev, dma_address));
+ dma_cache_wback_inv(addr, size);
+#endif
}
/*
@@ -212,21 +248,23 @@
static inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
int nents, int direction)
{
+#ifdef CONFIG_NONCOHERENT_IO
int i;
+#endif
if (direction == PCI_DMA_NONE)
BUG();
+#ifdef CONFIG_NONCOHERENT_IO
for (i = 0; i < nents; i++, sg++) {
unsigned long addr;
- addr = (unsigned long) page_address(sg->page);
- if (addr)
- dma_cache_wback_inv(addr, sg->length);
+ addr = (unsigned long) page_address(sg->page) + sg->offset;
+ dma_cache_wback_inv(addr, sg->length);
sg->dma_address = (dma_addr_t) bus_to_baddr(hwdev,
page_to_phys(sg->page) + sg->offset);
}
-
+#endif
return nents;
}
@@ -238,24 +276,27 @@
static inline void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
int nents, int direction)
{
+#ifdef CONFIG_NONCOHERENT_IO
int i;
+#endif
if (direction == PCI_DMA_NONE)
BUG();
if (direction == PCI_DMA_TODEVICE)
- return;
+ return; /* nothing to do */
+#ifdef CONFIG_NONCOHERENT_IO
for (i = 0; i < nents; i++, sg++) {
unsigned long addr;
if (!sg->page)
BUG();
- addr = (unsigned long) page_address(sg->page);
- if (addr)
- dma_cache_wback_inv(addr + sg->offset, sg->length);
+ addr = (unsigned long) page_address(sg->page) + sg->offset;
+ dma_cache_wback_inv(addr, sg->length);
}
+#endif
}
/*
@@ -272,13 +313,17 @@
dma_addr_t dma_handle,
size_t size, int direction)
{
+#ifdef CONFIG_NONCOHERENT_IO
unsigned long addr;
+#endif
if (direction == PCI_DMA_NONE)
BUG();
- addr = baddr_to_bus(hwdev, dma_handle) + PAGE_OFFSET;
+#ifdef CONFIG_NONCOHERENT_IO
+ addr = (unsigned long) phys_to_virt(baddr_to_bus(hwdev, dma_handle));
dma_cache_wback_inv(addr, size);
+#endif
}
/*
@@ -301,9 +346,12 @@
/* Make sure that gcc doesn't leave the empty loop body. */
#ifdef CONFIG_NONCOHERENT_IO
- for (i = 0; i < nelems; i++, sg++)
- dma_cache_wback_inv((unsigned long)page_address(sg->page),
- sg->length);
+ for (i = 0; i < nelems; i++, sg++) {
+ unsigned long addr;
+
+ addr = (unsigned long) page_address(sg->page) + sg->offset;
+ dma_cache_wback_inv(addr, sg->length);
+ }
#endif
}
#endif /* CONFIG_MAPPED_PCI_IO */
@@ -337,7 +385,7 @@
{
dma64_addr_t addr = page_to_phys(page) + offset;
- return (dma64_addr_t) bus_to_baddr(hwdev->bus->number, addr);
+ return (dma64_addr_t) bus_to_baddr(hwdev, addr);
}
static inline struct page *pci_dac_dma_to_page(struct pci_dev *pdev,
@@ -362,8 +410,10 @@
if (direction == PCI_DMA_NONE)
BUG();
- addr = baddr_to_bus(hwdev->bus->number, dma_addr) + PAGE_OFFSET;
+ addr = (unsigned long) phys_to_virt(baddr_to_bus(hwdev, dma_addr));
+#ifdef CONFIG_NONCOHERENT_IO
dma_cache_wback_inv(addr, len);
+#endif
}
/*
|