5fc29d935109993270ec376ad527e0cc4dd41005
[linux-flexiantxendom0-3.2.10.git] / arch / ia64 / sn / io / sn2 / pcibr / pcibr_ate.c
1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License.  See the file "COPYING" in the main directory of this archive
4  * for more details.
5  *
6  * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved.
7  */
8
9 #include <linux/types.h>
10 #include <asm/sn/sgi.h>
11 #include <asm/sn/iograph.h>
12 #include <asm/sn/pci/pciio.h>
13 #include <asm/sn/pci/pcibr.h>
14 #include <asm/sn/pci/pcibr_private.h>
15 #include <asm/sn/pci/pci_defs.h>
16
17 /*
18  * functions
19  */
20 int             pcibr_ate_alloc(pcibr_soft_t, int, struct resource *);
21 void            pcibr_ate_free(pcibr_soft_t, int, int, struct resource *);
22 bridge_ate_t    pcibr_flags_to_ate(pcibr_soft_t, unsigned);
23 bridge_ate_p    pcibr_ate_addr(pcibr_soft_t, int);
24 void            ate_write(pcibr_soft_t, int, int, bridge_ate_t);
25
26 int pcibr_invalidate_ate;  /* by default don't invalidate ATE on free */
27
28 /*
29  * Allocate "count" contiguous Bridge Address Translation Entries
30  * on the specified bridge to be used for PCI to XTALK mappings.
31  * Indices in rm map range from 1..num_entries.  Indicies returned
32  * to caller range from 0..num_entries-1.
33  *
34  * Return the start index on success, -1 on failure.
35  */
36 int
37 pcibr_ate_alloc(pcibr_soft_t pcibr_soft, int count, struct resource *res)
38 {
39     int                     status = 0;
40     unsigned long           flag;
41
42     memset(res, 0, sizeof(struct resource));
43     flag = pcibr_lock(pcibr_soft);
44     status = allocate_resource( &pcibr_soft->bs_int_ate_resource, res,
45                                 count, pcibr_soft->bs_int_ate_resource.start, 
46                                 pcibr_soft->bs_int_ate_resource.end, 1,
47                                 NULL, NULL);
48     if (status) {
49         /* Failed to allocate */
50         pcibr_unlock(pcibr_soft, flag);
51         return -1;
52     }
53
54     /* Save the resource for freeing */
55     pcibr_unlock(pcibr_soft, flag);
56
57     return res->start;
58 }
59
60 void
61 pcibr_ate_free(pcibr_soft_t pcibr_soft, int index, int count, struct resource *res)
62 {
63
64     bridge_ate_t ate;
65     int status = 0;
66     unsigned long flags;
67
68     if (pcibr_invalidate_ate) {
69         /* For debugging purposes, clear the valid bit in the ATE */
70         ate = *pcibr_ate_addr(pcibr_soft, index);
71         ate_write(pcibr_soft, index, count, (ate & ~ATE_V));
72     }
73
74     flags = pcibr_lock(pcibr_soft);
75     status = release_resource(res);
76     pcibr_unlock(pcibr_soft, flags);
77     if (status)
78         BUG(); /* Ouch .. */
79
80 }
81
82 /*
83  * Convert PCI-generic software flags and Bridge-specific software flags
84  * into Bridge-specific Address Translation Entry attribute bits.
85  */
86 bridge_ate_t
87 pcibr_flags_to_ate(pcibr_soft_t pcibr_soft, unsigned flags)
88 {
89     bridge_ate_t            attributes;
90
91     /* default if nothing specified:
92      * NOBARRIER
93      * NOPREFETCH
94      * NOPRECISE
95      * COHERENT
96      * Plus the valid bit
97      */
98     attributes = ATE_CO | ATE_V;
99
100     /* Generic macro flags
101      */
102     if (flags & PCIIO_DMA_DATA) {       /* standard data channel */
103         attributes &= ~ATE_BAR;         /* no barrier */
104         attributes |= ATE_PREF;         /* prefetch on */
105     }
106     if (flags & PCIIO_DMA_CMD) {        /* standard command channel */
107         attributes |= ATE_BAR;          /* barrier bit on */
108         attributes &= ~ATE_PREF;        /* disable prefetch */
109     }
110     /* Generic detail flags
111      */
112     if (flags & PCIIO_PREFETCH)
113         attributes |= ATE_PREF;
114     if (flags & PCIIO_NOPREFETCH)
115         attributes &= ~ATE_PREF;
116
117     /* Provider-specific flags
118      */
119     if (flags & PCIBR_BARRIER)
120         attributes |= ATE_BAR;
121     if (flags & PCIBR_NOBARRIER)
122         attributes &= ~ATE_BAR;
123
124     if (flags & PCIBR_PREFETCH)
125         attributes |= ATE_PREF;
126     if (flags & PCIBR_NOPREFETCH)
127         attributes &= ~ATE_PREF;
128
129     if (flags & PCIBR_PRECISE)
130         attributes |= ATE_PREC;
131     if (flags & PCIBR_NOPRECISE)
132         attributes &= ~ATE_PREC;
133
134     /* In PCI-X mode, Prefetch & Precise not supported */
135     if (IS_PCIX(pcibr_soft)) {
136         attributes &= ~(ATE_PREC | ATE_PREF);
137     }
138
139     return (attributes);
140 }
141
142 /*
143  * Setup an Address Translation Entry as specified.  Use either the Bridge
144  * internal maps or the external map RAM, as appropriate.
145  */
146 bridge_ate_p
147 pcibr_ate_addr(pcibr_soft_t pcibr_soft,
148                int ate_index)
149 {
150     if (ate_index < pcibr_soft->bs_int_ate_size) {
151         return (pcireg_int_ate_addr(pcibr_soft, ate_index));
152     } else {
153         printk("pcibr_ate_addr(): INVALID ate_index 0x%x", ate_index);
154         return (bridge_ate_p)0;
155     }
156 }
157
158 /*
159  * Write the ATE.
160  */
161 void
162 ate_write(pcibr_soft_t pcibr_soft, int ate_index, int count, bridge_ate_t ate)
163 {
164     while (count-- > 0) {
165         if (ate_index < pcibr_soft->bs_int_ate_size) {
166             pcireg_int_ate_set(pcibr_soft, ate_index, ate);
167             PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP, pcibr_soft->bs_vhdl,
168                         "ate_write(): ate_index=0x%x, ate=0x%lx\n",
169                         ate_index, (uint64_t)ate));
170         } else {
171             printk("ate_write(): INVALID ate_index 0x%x", ate_index);
172             return;
173         }
174         ate_index++;
175         ate += IOPGSIZE;
176     }
177
178     pcireg_tflush_get(pcibr_soft);      /* wait until Bridge PIO complete */
179 }