[PATCH] PCI: DMA bursting advice
authorDavid S. Miller <davem@davemloft.net>
Thu, 2 Jun 2005 19:55:50 +0000 (12:55 -0700)
committerGreg Kroah-Hartman <gregkh@suse.de>
Tue, 28 Jun 2005 04:52:45 +0000 (21:52 -0700)
After seeing, at best, "guesses" as to the following kind
of information in several drivers, I decided that we really
need a way for platforms to specifically give advice in this
area for what works best with their PCI controller implementation.

Basically, this new interface gives DMA bursting advice on
PCI.  There are three forms of the advice:

1) Burst as much as possible, it is not necessary to end bursts
   on some particular boundary for best performance.

2) Burst on some byte count multiple.  A DMA burst to some multiple of
   number of bytes may be done, but it is important to end the burst
   on an exact multiple for best performance.

   The best example of this I am aware of are the PPC64 PCI
   controllers, where if you end a burst mid-cacheline then
   chip has to refetch the data and the IOMMU translations
   which hurts performance a lot.

3) Burst on a single byte count multiple.  Bursts shall end
   exactly on the next multiple boundary for best performance.

   Sparc64 and Alpha's PCI controllers operate this way.  They
   disconnect any device which tries to burst across a cacheline
   boundary.

   Actually, newer sparc64 PCI controllers do not have this behavior.
   That is why the "pdev" is passed into the interface, so I can
   add code later to check which PCI controller the system is using
   and give advice accordingly.

Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
16 files changed:
include/asm-alpha/pci.h
include/asm-arm/pci.h
include/asm-frv/pci.h
include/asm-i386/pci.h
include/asm-ia64/pci.h
include/asm-mips/pci.h
include/asm-parisc/pci.h
include/asm-ppc/pci.h
include/asm-ppc64/pci.h
include/asm-sh/pci.h
include/asm-sh64/pci.h
include/asm-sparc/pci.h
include/asm-sparc64/pci.h
include/asm-v850/pci.h
include/asm-x86_64/pci.h
include/linux/pci.h

index 0c7b57bc043a69719386d5ce290210fd8f9ff6be..6c71dc1ad4ca55e3d505ccf5bec155aafadbbcf5 100644 (file)
@@ -223,6 +223,23 @@ pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, dma64_addr_t dma_addr,
        /* Nothing to do. */
 }
 
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+                                       enum pci_dma_burst_strategy *strat,
+                                       unsigned long *strategy_parameter)
+{
+       unsigned long cacheline_size;
+       u8 byte;
+
+       pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &byte);
+       if (byte == 0)
+               cacheline_size = 1024;
+       else
+               cacheline_size = (int) byte * 4;
+
+       *strat = PCI_DMA_BURST_BOUNDARY;
+       *strategy_parameter = cacheline_size;
+}
+
 /* TODO: integrate with include/asm-generic/pci.h ? */
 static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
 {
index 40ffaefbeb1a7eca0f2da3dc4c34c0220f1ea524..bc2ec425aca53b5629dd5bedf144a9584bd6361f 100644 (file)
@@ -42,6 +42,14 @@ static inline void pcibios_penalize_isa_irq(int irq)
 #define pci_unmap_len(PTR, LEN_NAME)           ((PTR)->LEN_NAME)
 #define pci_unmap_len_set(PTR, LEN_NAME, VAL)  (((PTR)->LEN_NAME) = (VAL))
 
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+                                       enum pci_dma_burst_strategy *strat,
+                                       unsigned long *strategy_parameter)
+{
+       *strat = PCI_DMA_BURST_INFINITY;
+       *strategy_parameter = ~0UL;
+}
+
 #define HAVE_PCI_MMAP
 extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
                                enum pci_mmap_state mmap_state, int write_combine);
index a6a469231f6270e67475f99f3fe4298c600cbef2..13427240664f4d510cf0c2e2b1b821674fbae6d6 100644 (file)
@@ -57,6 +57,14 @@ extern void pci_free_consistent(struct pci_dev *hwdev, size_t size,
  */
 #define PCI_DMA_BUS_IS_PHYS    (1)
 
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+                                       enum pci_dma_burst_strategy *strat,
+                                       unsigned long *strategy_parameter)
+{
+       *strat = PCI_DMA_BURST_INFINITY;
+       *strategy_parameter = ~0UL;
+}
+
 /*
  *     These are pretty much arbitary with the CoMEM implementation.
  *     We have the whole address space to ourselves.
index fb749b85a739675b804bc5a3baf07b7a4d574827..bf07b3af85e375dbc8850aadf0569c652a2c4114 100644 (file)
@@ -99,6 +99,14 @@ static inline void pcibios_add_platform_entries(struct pci_dev *dev)
 {
 }
 
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+                                       enum pci_dma_burst_strategy *strat,
+                                       unsigned long *strategy_parameter)
+{
+       *strat = PCI_DMA_BURST_INFINITY;
+       *strategy_parameter = ~0UL;
+}
+
 #endif /* __KERNEL__ */
 
 /* implement the pci_ DMA API in terms of the generic device dma_ one */
index a8314ee4e7d2542d304ccb52f6ba0408ef2c83b9..c9f1ab4e477d97cba6f66c8bc3fabeef07ee225d 100644 (file)
@@ -82,6 +82,23 @@ extern int pcibios_prep_mwi (struct pci_dev *);
 #define sg_dma_len(sg)         ((sg)->dma_length)
 #define sg_dma_address(sg)     ((sg)->dma_address)
 
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+                                       enum pci_dma_burst_strategy *strat,
+                                       unsigned long *strategy_parameter)
+{
+       unsigned long cacheline_size;
+       u8 byte;
+
+       pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &byte);
+       if (byte == 0)
+               cacheline_size = 1024;
+       else
+               cacheline_size = (int) byte * 4;
+
+       *strat = PCI_DMA_BURST_MULTIPLE;
+       *strategy_parameter = cacheline_size;
+}
+
 #define HAVE_PCI_MMAP
 extern int pci_mmap_page_range (struct pci_dev *dev, struct vm_area_struct *vma,
                                enum pci_mmap_state mmap_state, int write_combine);
index c9c576b48556b933829594bae7fb4eb3e0bea296..20b93bfa4565715d66e47b60a3236905c8b33909 100644 (file)
@@ -130,6 +130,14 @@ extern void pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev,
 extern void pci_dac_dma_sync_single_for_device(struct pci_dev *pdev,
        dma64_addr_t dma_addr, size_t len, int direction);
 
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+                                       enum pci_dma_burst_strategy *strat,
+                                       unsigned long *strategy_parameter)
+{
+       *strat = PCI_DMA_BURST_INFINITY;
+       *strategy_parameter = ~0UL;
+}
+
 extern void pcibios_resource_to_bus(struct pci_dev *dev,
        struct pci_bus_region *region, struct resource *res);
 
index 0763c2982fb085b2691893cc400d00f388119df7..f9f5bf90111d1e17037481c68a34cb56ba3146f5 100644 (file)
@@ -230,6 +230,23 @@ extern inline void pcibios_register_hba(struct pci_hba_data *x)
 /* export the pci_ DMA API in terms of the dma_ one */
 #include <asm-generic/pci-dma-compat.h>
 
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+                                       enum pci_dma_burst_strategy *strat,
+                                       unsigned long *strategy_parameter)
+{
+       unsigned long cacheline_size;
+       u8 byte;
+
+       pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &byte);
+       if (byte == 0)
+               cacheline_size = 1024;
+       else
+               cacheline_size = (int) byte * 4;
+
+       *strat = PCI_DMA_BURST_MULTIPLE;
+       *strategy_parameter = cacheline_size;
+}
+
 extern void
 pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
                         struct resource *res);
index 002e7b305777aefc90fca74903458402db0f79fe..669e9de7a5259c179b9cf2bd8f838e2912324df3 100644 (file)
@@ -69,6 +69,14 @@ extern unsigned long pci_bus_to_phys(unsigned int ba, int busnr);
 #define pci_unmap_len(PTR, LEN_NAME)           (0)
 #define pci_unmap_len_set(PTR, LEN_NAME, VAL)  do { } while (0)
 
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+                                       enum pci_dma_burst_strategy *strat,
+                                       unsigned long *strategy_parameter)
+{
+       *strat = PCI_DMA_BURST_INFINITY;
+       *strategy_parameter = ~0UL;
+}
+
 /*
  * At present there are very few 32-bit PPC machines that can have
  * memory above the 4GB point, and we don't support that.
index 411bf5dee3943c691dcf9b58ca974cc0477e9217..20beb10c0902ddb29fc5afdd4e2b7ac314a709df 100644 (file)
@@ -78,6 +78,23 @@ static inline int pci_dac_dma_supported(struct pci_dev *hwdev,u64 mask)
        return 0;
 }
 
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+                                       enum pci_dma_burst_strategy *strat,
+                                       unsigned long *strategy_parameter)
+{
+       unsigned long cacheline_size;
+       u8 byte;
+
+       pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &byte);
+       if (byte == 0)
+               cacheline_size = 1024;
+       else
+               cacheline_size = (int) byte * 4;
+
+       *strat = PCI_DMA_BURST_MULTIPLE;
+       *strategy_parameter = cacheline_size;
+}
+
 extern int pci_domain_nr(struct pci_bus *bus);
 
 /* Decide whether to display the domain number in /proc */
index 9c3b63d0105ef2ef1336822a6311e93773ec7f27..7237bc6a7280fc71fa0fc3e5664a496fad66be1d 100644 (file)
@@ -96,6 +96,14 @@ static inline void pcibios_penalize_isa_irq(int irq)
 #define sg_dma_address(sg)     (virt_to_bus((sg)->dma_address))
 #define sg_dma_len(sg)         ((sg)->length)
 
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+                                       enum pci_dma_burst_strategy *strat,
+                                       unsigned long *strategy_parameter)
+{
+       *strat = PCI_DMA_BURST_INFINITY;
+       *strategy_parameter = ~0UL;
+}
+
 /* Board-specific fixup routines. */
 extern void pcibios_fixup(void);
 extern void pcibios_fixup_irqs(void);
index 8cc14e139750d7833b00b134c4f03b1bfb7ffe62..0ac15ab01cceb101d44068709ce351275276efa0 100644 (file)
@@ -86,6 +86,14 @@ static inline void pcibios_penalize_isa_irq(int irq)
 #define sg_dma_address(sg)     ((sg)->dma_address)
 #define sg_dma_len(sg)         ((sg)->length)
 
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+                                       enum pci_dma_burst_strategy *strat,
+                                       unsigned long *strategy_parameter)
+{
+       *strat = PCI_DMA_BURST_INFINITY;
+       *strategy_parameter = ~0UL;
+}
+
 /* Board-specific fixup routines. */
 extern void pcibios_fixup(void);
 extern void pcibios_fixup_irqs(void);
index d200a25a7373b77c58453a443c802882bf42962d..2fd65db95e92134cf2cce93d2c4f7eb485fbcc9d 100644 (file)
@@ -144,6 +144,14 @@ extern inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask)
 
 #define pci_dac_dma_supported(dev, mask)       (0)
 
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+                                       enum pci_dma_burst_strategy *strat,
+                                       unsigned long *strategy_parameter)
+{
+       *strat = PCI_DMA_BURST_INFINITY;
+       *strategy_parameter = ~0UL;
+}
+
 static inline void pcibios_add_platform_entries(struct pci_dev *dev)
 {
 }
index 2a0c85cd1c11de63ba0bb21ddb4424445e9f8722..402667300d01a060df7dd9956131273379c429e1 100644 (file)
@@ -220,6 +220,23 @@ static inline int pci_dma_mapping_error(dma_addr_t dma_addr)
        return (dma_addr == PCI_DMA_ERROR_CODE);
 }
 
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+                                       enum pci_dma_burst_strategy *strat,
+                                       unsigned long *strategy_parameter)
+{
+       unsigned long cacheline_size;
+       u8 byte;
+
+       pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &byte);
+       if (byte == 0)
+               cacheline_size = 1024;
+       else
+               cacheline_size = (int) byte * 4;
+
+       *strat = PCI_DMA_BURST_BOUNDARY;
+       *strategy_parameter = cacheline_size;
+}
+
 /* Return the index of the PCI controller for device PDEV. */
 
 extern int pci_domain_nr(struct pci_bus *bus);
index e41941447b49210a103361c0d3dfe6ba30e8aef3..d26eb8d67311dfc9d01bebe53e67ecb147fc1fb9 100644 (file)
@@ -81,6 +81,14 @@ extern void
 pci_free_consistent (struct pci_dev *pdev, size_t size, void *cpu_addr,
                     dma_addr_t dma_addr);
 
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+                                       enum pci_dma_burst_strategy *strat,
+                                       unsigned long *strategy_parameter)
+{
+       *strat = PCI_DMA_BURST_INFINITY;
+       *strategy_parameter = ~0UL;
+}
+
 static inline void pcibios_add_platform_entries(struct pci_dev *dev)
 {
 }
index 8712520ca47fc071b1c2eb672c02da70b4f616d3..8461d6af102eba95ba3189b296a677145173628d 100644 (file)
@@ -123,6 +123,14 @@ pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, dma64_addr_t dma_addr,
        flush_write_buffers();
 }
 
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+                                       enum pci_dma_burst_strategy *strat,
+                                       unsigned long *strategy_parameter)
+{
+       *strat = PCI_DMA_BURST_INFINITY;
+       *strategy_parameter = ~0UL;
+}
+
 #define HAVE_PCI_MMAP
 extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
                               enum pci_mmap_state mmap_state, int write_combine);
index cfa1455848f4fd8169bc004229825fc8e2edeb3d..9ce4f1be093fb478f78decbb2e6cbc9df52a9261 100644 (file)
@@ -874,6 +874,15 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass
 #define        pci_pool_alloc(pool, flags, handle) dma_pool_alloc(pool, flags, handle)
 #define        pci_pool_free(pool, vaddr, addr) dma_pool_free(pool, vaddr, addr)
 
+enum pci_dma_burst_strategy {
+       PCI_DMA_BURST_INFINITY, /* make bursts as large as possible,
+                                  strategy_parameter is N/A */
+       PCI_DMA_BURST_BOUNDARY, /* disconnect at every strategy_parameter
+                                  byte boundaries */
+       PCI_DMA_BURST_MULTIPLE, /* disconnect at some multiple of
+                                  strategy_parameter byte boundaries */
+};
+
 #if defined(CONFIG_ISA) || defined(CONFIG_EISA)
 extern struct pci_dev *isa_bridge;
 #endif