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
6 * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved.
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>
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);
26 int pcibr_invalidate_ate; /* by default don't invalidate ATE on free */
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.
34 * Return the start index on success, -1 on failure.
37 pcibr_ate_alloc(pcibr_soft_t pcibr_soft, int count, struct resource *res)
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,
49 /* Failed to allocate */
50 pcibr_unlock(pcibr_soft, flag);
54 /* Save the resource for freeing */
55 pcibr_unlock(pcibr_soft, flag);
61 pcibr_ate_free(pcibr_soft_t pcibr_soft, int index, int count, struct resource *res)
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));
74 flags = pcibr_lock(pcibr_soft);
75 status = release_resource(res);
76 pcibr_unlock(pcibr_soft, flags);
83 * Convert PCI-generic software flags and Bridge-specific software flags
84 * into Bridge-specific Address Translation Entry attribute bits.
87 pcibr_flags_to_ate(pcibr_soft_t pcibr_soft, unsigned flags)
89 bridge_ate_t attributes;
91 /* default if nothing specified:
98 attributes = ATE_CO | ATE_V;
100 /* Generic macro flags
102 if (flags & PCIIO_DMA_DATA) { /* standard data channel */
103 attributes &= ~ATE_BAR; /* no barrier */
104 attributes |= ATE_PREF; /* prefetch on */
106 if (flags & PCIIO_DMA_CMD) { /* standard command channel */
107 attributes |= ATE_BAR; /* barrier bit on */
108 attributes &= ~ATE_PREF; /* disable prefetch */
110 /* Generic detail flags
112 if (flags & PCIIO_PREFETCH)
113 attributes |= ATE_PREF;
114 if (flags & PCIIO_NOPREFETCH)
115 attributes &= ~ATE_PREF;
117 /* Provider-specific flags
119 if (flags & PCIBR_BARRIER)
120 attributes |= ATE_BAR;
121 if (flags & PCIBR_NOBARRIER)
122 attributes &= ~ATE_BAR;
124 if (flags & PCIBR_PREFETCH)
125 attributes |= ATE_PREF;
126 if (flags & PCIBR_NOPREFETCH)
127 attributes &= ~ATE_PREF;
129 if (flags & PCIBR_PRECISE)
130 attributes |= ATE_PREC;
131 if (flags & PCIBR_NOPRECISE)
132 attributes &= ~ATE_PREC;
134 /* In PCI-X mode, Prefetch & Precise not supported */
135 if (IS_PCIX(pcibr_soft)) {
136 attributes &= ~(ATE_PREC | ATE_PREF);
143 * Setup an Address Translation Entry as specified. Use either the Bridge
144 * internal maps or the external map RAM, as appropriate.
147 pcibr_ate_addr(pcibr_soft_t pcibr_soft,
150 if (ate_index < pcibr_soft->bs_int_ate_size) {
151 return (pcireg_int_ate_addr(pcibr_soft, ate_index));
153 printk("pcibr_ate_addr(): INVALID ate_index 0x%x", ate_index);
154 return (bridge_ate_p)0;
162 ate_write(pcibr_soft_t pcibr_soft, int ate_index, int count, bridge_ate_t ate)
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));
171 printk("ate_write(): INVALID ate_index 0x%x", ate_index);
178 pcireg_tflush_get(pcibr_soft); /* wait until Bridge PIO complete */