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