aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2006-02-10 00:32:07 -0500
committerDavid S. Miller <davem@sunset.davemloft.net>2006-03-20 04:12:10 -0500
commit8f6a93a196ba6c569c3e8daa6e81cca7e3ba81b1 (patch)
tree80d4747608148c56fd8c67baf016ad4fc58610ea
parent4cce4b7cc56abc3d7b269d09224b8297aad15138 (diff)
[SPARC64]: Beginnings of SUN4V PCI controller support.
Abstract out IOMMU operations so that we can have a different set of calls on sun4v, which needs to do things through hypervisor calls. Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--arch/sparc64/kernel/Makefile2
-rw-r--r--arch/sparc64/kernel/pci.c13
-rw-r--r--arch/sparc64/kernel/pci_iommu.c27
-rw-r--r--arch/sparc64/kernel/pci_sun4v.c74
-rw-r--r--include/asm-sparc64/pci.h56
5 files changed, 152 insertions, 20 deletions
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
index a482a9ffe5bc..44043390e34f 100644
--- a/arch/sparc64/kernel/Makefile
+++ b/arch/sparc64/kernel/Makefile
@@ -14,7 +14,7 @@ obj-y := process.o setup.o cpu.o idprom.o \
14 power.o sbus.o iommu_common.o sparc64_ksyms.o chmc.o 14 power.o sbus.o iommu_common.o sparc64_ksyms.o chmc.o
15 15
16obj-$(CONFIG_PCI) += ebus.o isa.o pci_common.o pci_iommu.o \ 16obj-$(CONFIG_PCI) += ebus.o isa.o pci_common.o pci_iommu.o \
17 pci_psycho.o pci_sabre.o pci_schizo.o 17 pci_psycho.o pci_sabre.o pci_schizo.o pci_sun4v.o
18obj-$(CONFIG_SMP) += smp.o trampoline.o 18obj-$(CONFIG_SMP) += smp.o trampoline.o
19obj-$(CONFIG_SPARC32_COMPAT) += sys32.o sys_sparc32.o signal32.o 19obj-$(CONFIG_SPARC32_COMPAT) += sys32.o sys_sparc32.o signal32.o
20obj-$(CONFIG_BINFMT_ELF32) += binfmt_elf32.o 20obj-$(CONFIG_BINFMT_ELF32) += binfmt_elf32.o
diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c
index 2ff7c32ab0ce..95ffa9418620 100644
--- a/arch/sparc64/kernel/pci.c
+++ b/arch/sparc64/kernel/pci.c
@@ -188,6 +188,7 @@ extern void psycho_init(int, char *);
188extern void schizo_init(int, char *); 188extern void schizo_init(int, char *);
189extern void schizo_plus_init(int, char *); 189extern void schizo_plus_init(int, char *);
190extern void tomatillo_init(int, char *); 190extern void tomatillo_init(int, char *);
191extern void sun4v_pci_init(int, char *);
191 192
192static struct { 193static struct {
193 char *model_name; 194 char *model_name;
@@ -204,6 +205,7 @@ static struct {
204 { "pci108e,8002", schizo_plus_init }, 205 { "pci108e,8002", schizo_plus_init },
205 { "SUNW,tomatillo", tomatillo_init }, 206 { "SUNW,tomatillo", tomatillo_init },
206 { "pci108e,a801", tomatillo_init }, 207 { "pci108e,a801", tomatillo_init },
208 { "SUNW,sun4v-pci", sun4v_pci_init },
207}; 209};
208#define PCI_NUM_CONTROLLER_TYPES (sizeof(pci_controller_table) / \ 210#define PCI_NUM_CONTROLLER_TYPES (sizeof(pci_controller_table) / \
209 sizeof(pci_controller_table[0])) 211 sizeof(pci_controller_table[0]))
@@ -283,6 +285,12 @@ int __init pcic_present(void)
283 return pci_controller_scan(pci_is_controller); 285 return pci_controller_scan(pci_is_controller);
284} 286}
285 287
288struct pci_iommu_ops *pci_iommu_ops;
289EXPORT_SYMBOL(pci_iommu_ops);
290
291extern struct pci_iommu_ops pci_sun4u_iommu_ops,
292 pci_sun4v_iommu_ops;
293
286/* Find each controller in the system, attach and initialize 294/* Find each controller in the system, attach and initialize
287 * software state structure for each and link into the 295 * software state structure for each and link into the
288 * pci_controller_root. Setup the controller enough such 296 * pci_controller_root. Setup the controller enough such
@@ -290,6 +298,11 @@ int __init pcic_present(void)
290 */ 298 */
291static void __init pci_controller_probe(void) 299static void __init pci_controller_probe(void)
292{ 300{
301 if (tlb_type == hypervisor)
302 pci_iommu_ops = &pci_sun4v_iommu_ops;
303 else
304 pci_iommu_ops = &pci_sun4u_iommu_ops;
305
293 printk("PCI: Probing for controllers.\n"); 306 printk("PCI: Probing for controllers.\n");
294 307
295 pci_controller_scan(pci_controller_init); 308 pci_controller_scan(pci_controller_init);
diff --git a/arch/sparc64/kernel/pci_iommu.c b/arch/sparc64/kernel/pci_iommu.c
index a11910be1013..8e52232f6f31 100644
--- a/arch/sparc64/kernel/pci_iommu.c
+++ b/arch/sparc64/kernel/pci_iommu.c
@@ -219,7 +219,7 @@ static inline void iommu_free_ctx(struct pci_iommu *iommu, int ctx)
219 * DMA for PCI device PDEV. Return non-NULL cpu-side address if 219 * DMA for PCI device PDEV. Return non-NULL cpu-side address if
220 * successful and set *DMA_ADDRP to the PCI side dma address. 220 * successful and set *DMA_ADDRP to the PCI side dma address.
221 */ 221 */
222void *pci_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp) 222static void *pci_4u_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp)
223{ 223{
224 struct pcidev_cookie *pcp; 224 struct pcidev_cookie *pcp;
225 struct pci_iommu *iommu; 225 struct pci_iommu *iommu;
@@ -267,7 +267,7 @@ void *pci_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_ad
267} 267}
268 268
269/* Free and unmap a consistent DMA translation. */ 269/* Free and unmap a consistent DMA translation. */
270void pci_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_t dvma) 270static void pci_4u_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_t dvma)
271{ 271{
272 struct pcidev_cookie *pcp; 272 struct pcidev_cookie *pcp;
273 struct pci_iommu *iommu; 273 struct pci_iommu *iommu;
@@ -294,7 +294,7 @@ void pci_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_
294/* Map a single buffer at PTR of SZ bytes for PCI DMA 294/* Map a single buffer at PTR of SZ bytes for PCI DMA
295 * in streaming mode. 295 * in streaming mode.
296 */ 296 */
297dma_addr_t pci_map_single(struct pci_dev *pdev, void *ptr, size_t sz, int direction) 297static dma_addr_t pci_4u_map_single(struct pci_dev *pdev, void *ptr, size_t sz, int direction)
298{ 298{
299 struct pcidev_cookie *pcp; 299 struct pcidev_cookie *pcp;
300 struct pci_iommu *iommu; 300 struct pci_iommu *iommu;
@@ -415,7 +415,7 @@ do_flush_sync:
415} 415}
416 416
417/* Unmap a single streaming mode DMA translation. */ 417/* Unmap a single streaming mode DMA translation. */
418void pci_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction) 418static void pci_4u_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction)
419{ 419{
420 struct pcidev_cookie *pcp; 420 struct pcidev_cookie *pcp;
421 struct pci_iommu *iommu; 421 struct pci_iommu *iommu;
@@ -548,7 +548,7 @@ static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg,
548 * When making changes here, inspect the assembly output. I was having 548 * When making changes here, inspect the assembly output. I was having
549 * hard time to kepp this routine out of using stack slots for holding variables. 549 * hard time to kepp this routine out of using stack slots for holding variables.
550 */ 550 */
551int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) 551static int pci_4u_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
552{ 552{
553 struct pcidev_cookie *pcp; 553 struct pcidev_cookie *pcp;
554 struct pci_iommu *iommu; 554 struct pci_iommu *iommu;
@@ -635,7 +635,7 @@ bad_no_ctx:
635} 635}
636 636
637/* Unmap a set of streaming mode DMA translations. */ 637/* Unmap a set of streaming mode DMA translations. */
638void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) 638static void pci_4u_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
639{ 639{
640 struct pcidev_cookie *pcp; 640 struct pcidev_cookie *pcp;
641 struct pci_iommu *iommu; 641 struct pci_iommu *iommu;
@@ -695,7 +695,7 @@ void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems,
695/* Make physical memory consistent for a single 695/* Make physical memory consistent for a single
696 * streaming mode DMA translation after a transfer. 696 * streaming mode DMA translation after a transfer.
697 */ 697 */
698void pci_dma_sync_single_for_cpu(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction) 698static void pci_4u_dma_sync_single_for_cpu(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction)
699{ 699{
700 struct pcidev_cookie *pcp; 700 struct pcidev_cookie *pcp;
701 struct pci_iommu *iommu; 701 struct pci_iommu *iommu;
@@ -735,7 +735,7 @@ void pci_dma_sync_single_for_cpu(struct pci_dev *pdev, dma_addr_t bus_addr, size
735/* Make physical memory consistent for a set of streaming 735/* Make physical memory consistent for a set of streaming
736 * mode DMA translations after a transfer. 736 * mode DMA translations after a transfer.
737 */ 737 */
738void pci_dma_sync_sg_for_cpu(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) 738static void pci_4u_dma_sync_sg_for_cpu(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
739{ 739{
740 struct pcidev_cookie *pcp; 740 struct pcidev_cookie *pcp;
741 struct pci_iommu *iommu; 741 struct pci_iommu *iommu;
@@ -776,6 +776,17 @@ void pci_dma_sync_sg_for_cpu(struct pci_dev *pdev, struct scatterlist *sglist, i
776 spin_unlock_irqrestore(&iommu->lock, flags); 776 spin_unlock_irqrestore(&iommu->lock, flags);
777} 777}
778 778
779struct pci_iommu_ops pci_sun4u_iommu_ops = {
780 .alloc_consistent = pci_4u_alloc_consistent,
781 .free_consistent = pci_4u_free_consistent,
782 .map_single = pci_4u_map_single,
783 .unmap_single = pci_4u_unmap_single,
784 .map_sg = pci_4u_map_sg,
785 .unmap_sg = pci_4u_unmap_sg,
786 .dma_sync_single_for_cpu = pci_4u_dma_sync_single_for_cpu,
787 .dma_sync_sg_for_cpu = pci_4u_dma_sync_sg_for_cpu,
788};
789
779static void ali_sound_dma_hack(struct pci_dev *pdev, int set_bit) 790static void ali_sound_dma_hack(struct pci_dev *pdev, int set_bit)
780{ 791{
781 struct pci_dev *ali_isa_bridge; 792 struct pci_dev *ali_isa_bridge;
diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c
new file mode 100644
index 000000000000..c1a077196c57
--- /dev/null
+++ b/arch/sparc64/kernel/pci_sun4v.c
@@ -0,0 +1,74 @@
1/* pci_sun4v.c: SUN4V specific PCI controller support.
2 *
3 * Copyright (C) 2006 David S. Miller (davem@davemloft.net)
4 */
5
6#include <linux/kernel.h>
7#include <linux/types.h>
8#include <linux/pci.h>
9#include <linux/init.h>
10#include <linux/slab.h>
11#include <linux/interrupt.h>
12
13#include <asm/pbm.h>
14#include <asm/iommu.h>
15#include <asm/irq.h>
16#include <asm/upa.h>
17#include <asm/pstate.h>
18#include <asm/oplib.h>
19#include <asm/hypervisor.h>
20
21#include "pci_impl.h"
22#include "iommu_common.h"
23
24static void *pci_4v_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp)
25{
26 return NULL;
27}
28
29static void pci_4v_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_t dvma)
30{
31}
32
33static dma_addr_t pci_4v_map_single(struct pci_dev *pdev, void *ptr, size_t sz, int direction)
34{
35 return 0;
36}
37
38static void pci_4v_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction)
39{
40}
41
42static int pci_4v_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
43{
44 return nelems;
45}
46
47static void pci_4v_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
48{
49}
50
51static void pci_4v_dma_sync_single_for_cpu(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction)
52{
53}
54
55static void pci_4v_dma_sync_sg_for_cpu(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
56{
57}
58
59struct pci_iommu_ops pci_sun4v_iommu_ops = {
60 .alloc_consistent = pci_4v_alloc_consistent,
61 .free_consistent = pci_4v_free_consistent,
62 .map_single = pci_4v_map_single,
63 .unmap_single = pci_4v_unmap_single,
64 .map_sg = pci_4v_map_sg,
65 .unmap_sg = pci_4v_unmap_sg,
66 .dma_sync_single_for_cpu = pci_4v_dma_sync_single_for_cpu,
67 .dma_sync_sg_for_cpu = pci_4v_dma_sync_sg_for_cpu,
68};
69
70void sun4v_pci_init(int node, char *model_name)
71{
72 prom_printf("sun4v_pci_init: Implement me.\n");
73 prom_halt();
74}
diff --git a/include/asm-sparc64/pci.h b/include/asm-sparc64/pci.h
index 89bd71b1c0d8..7c5a589ea437 100644
--- a/include/asm-sparc64/pci.h
+++ b/include/asm-sparc64/pci.h
@@ -41,10 +41,26 @@ static inline void pcibios_penalize_isa_irq(int irq, int active)
41 41
42struct pci_dev; 42struct pci_dev;
43 43
44struct pci_iommu_ops {
45 void *(*alloc_consistent)(struct pci_dev *, size_t, dma_addr_t *);
46 void (*free_consistent)(struct pci_dev *, size_t, void *, dma_addr_t);
47 dma_addr_t (*map_single)(struct pci_dev *, void *, size_t, int);
48 void (*unmap_single)(struct pci_dev *, dma_addr_t, size_t, int);
49 int (*map_sg)(struct pci_dev *, struct scatterlist *, int, int);
50 void (*unmap_sg)(struct pci_dev *, struct scatterlist *, int, int);
51 void (*dma_sync_single_for_cpu)(struct pci_dev *, dma_addr_t, size_t, int);
52 void (*dma_sync_sg_for_cpu)(struct pci_dev *, struct scatterlist *, int, int);
53};
54
55extern struct pci_iommu_ops *pci_iommu_ops;
56
44/* Allocate and map kernel buffer using consistent mode DMA for a device. 57/* Allocate and map kernel buffer using consistent mode DMA for a device.
45 * hwdev should be valid struct pci_dev pointer for PCI devices. 58 * hwdev should be valid struct pci_dev pointer for PCI devices.
46 */ 59 */
47extern void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle); 60static inline void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle)
61{
62 return pci_iommu_ops->alloc_consistent(hwdev, size, dma_handle);
63}
48 64
49/* Free and unmap a consistent DMA buffer. 65/* Free and unmap a consistent DMA buffer.
50 * cpu_addr is what was returned from pci_alloc_consistent, 66 * cpu_addr is what was returned from pci_alloc_consistent,
@@ -54,7 +70,10 @@ extern void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t
54 * References to the memory and mappings associated with cpu_addr/dma_addr 70 * References to the memory and mappings associated with cpu_addr/dma_addr
55 * past this call are illegal. 71 * past this call are illegal.
56 */ 72 */
57extern void pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle); 73static inline void pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle)
74{
75 return pci_iommu_ops->free_consistent(hwdev, size, vaddr, dma_handle);
76}
58 77
59/* Map a single buffer of the indicated size for DMA in streaming mode. 78/* Map a single buffer of the indicated size for DMA in streaming mode.
60 * The 32-bit bus address to use is returned. 79 * The 32-bit bus address to use is returned.
@@ -62,7 +81,10 @@ extern void pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr,
62 * Once the device is given the dma address, the device owns this memory 81 * Once the device is given the dma address, the device owns this memory
63 * until either pci_unmap_single or pci_dma_sync_single_for_cpu is performed. 82 * until either pci_unmap_single or pci_dma_sync_single_for_cpu is performed.
64 */ 83 */
65extern dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction); 84static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction)
85{
86 return pci_iommu_ops->map_single(hwdev, ptr, size, direction);
87}
66 88
67/* Unmap a single streaming mode DMA translation. The dma_addr and size 89/* Unmap a single streaming mode DMA translation. The dma_addr and size
68 * must match what was provided for in a previous pci_map_single call. All 90 * must match what was provided for in a previous pci_map_single call. All
@@ -71,7 +93,10 @@ extern dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size,
71 * After this call, reads by the cpu to the buffer are guaranteed to see 93 * After this call, reads by the cpu to the buffer are guaranteed to see
72 * whatever the device wrote there. 94 * whatever the device wrote there.
73 */ 95 */
74extern void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction); 96static inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction)
97{
98 pci_iommu_ops->unmap_single(hwdev, dma_addr, size, direction);
99}
75 100
76/* No highmem on sparc64, plus we have an IOMMU, so mapping pages is easy. */ 101/* No highmem on sparc64, plus we have an IOMMU, so mapping pages is easy. */
77#define pci_map_page(dev, page, off, size, dir) \ 102#define pci_map_page(dev, page, off, size, dir) \
@@ -107,15 +132,19 @@ extern void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t
107 * Device ownership issues as mentioned above for pci_map_single are 132 * Device ownership issues as mentioned above for pci_map_single are
108 * the same here. 133 * the same here.
109 */ 134 */
110extern int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, 135static inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction)
111 int nents, int direction); 136{
137 return pci_iommu_ops->map_sg(hwdev, sg, nents, direction);
138}
112 139
113/* Unmap a set of streaming mode DMA translations. 140/* Unmap a set of streaming mode DMA translations.
114 * Again, cpu read rules concerning calls here are the same as for 141 * Again, cpu read rules concerning calls here are the same as for
115 * pci_unmap_single() above. 142 * pci_unmap_single() above.
116 */ 143 */
117extern void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, 144static inline void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nhwents, int direction)
118 int nhwents, int direction); 145{
146 pci_iommu_ops->unmap_sg(hwdev, sg, nhwents, direction);
147}
119 148
120/* Make physical memory consistent for a single 149/* Make physical memory consistent for a single
121 * streaming mode DMA translation after a transfer. 150 * streaming mode DMA translation after a transfer.
@@ -127,8 +156,10 @@ extern void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
127 * must first perform a pci_dma_sync_for_device, and then the 156 * must first perform a pci_dma_sync_for_device, and then the
128 * device again owns the buffer. 157 * device again owns the buffer.
129 */ 158 */
130extern void pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, dma_addr_t dma_handle, 159static inline void pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction)
131 size_t size, int direction); 160{
161 pci_iommu_ops->dma_sync_single_for_cpu(hwdev, dma_handle, size, direction);
162}
132 163
133static inline void 164static inline void
134pci_dma_sync_single_for_device(struct pci_dev *hwdev, dma_addr_t dma_handle, 165pci_dma_sync_single_for_device(struct pci_dev *hwdev, dma_addr_t dma_handle,
@@ -144,7 +175,10 @@ pci_dma_sync_single_for_device(struct pci_dev *hwdev, dma_addr_t dma_handle,
144 * The same as pci_dma_sync_single_* but for a scatter-gather list, 175 * The same as pci_dma_sync_single_* but for a scatter-gather list,
145 * same rules and usage. 176 * same rules and usage.
146 */ 177 */
147extern void pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction); 178static inline void pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction)
179{
180 pci_iommu_ops->dma_sync_sg_for_cpu(hwdev, sg, nelems, direction);
181}
148 182
149static inline void 183static inline void
150pci_dma_sync_sg_for_device(struct pci_dev *hwdev, struct scatterlist *sg, 184pci_dma_sync_sg_for_device(struct pci_dev *hwdev, struct scatterlist *sg,