source: trunk/packages/xen-common/xen-common/xen/arch/powerpc/dart.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 17 years ago

Add xen and xen-common

File size: 7.5 KB
Line 
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
15 *
16 * Copyright (C) IBM Corp. 2005
17 *
18 * Authors: Jimi Xenidis <jimix@watson.ibm.com>
19 */
20
21#include <xen/config.h>
22#include <xen/types.h>
23#include <xen/mm.h>
24#include <asm/cache.h>
25#include <xen/init.h>
26#include "tce.h"
27#include "iommu.h"
28#include "dart.h"
29#include "oftree.h"
30#include "of-devtree.h"
31
32#undef DEBUG
33#ifdef DEBUG
34#define DBG(fmt...) printk(fmt)
35static int dbg_after;
36#define DBG_SET_AFTER dbg_after = 1;
37#define DBG_AFTER(fmt...) if (dbg_after) DBG(fmt)
38#else
39#define DBG(fmt...)
40#define DBG_SET_AFTER
41#define DBG_AFTER(fmt...)
42#endif
43
44/* Max size of 512 pages */
45#define U3_LOG_MAX_PAGES 9
46
47#define DART_DEF_BASE   0xf8033000UL
48#define DART_NONE 0
49#define DART_U3 3
50#define DART_U4 4
51#define DART_WRITE 0x1
52#define DART_READ 0x2
53
54static ulong dummy_page;
55static ulong dart_entries;
56static struct dart_ops *dops;
57static u32 *dart_table;
58
59union dart_entry {
60    u32 de_word;
61    struct {
62        u32 de_v:1;             /* valid */
63        u32 de_rp:1;             /* read protected */
64        u32 de_wp:1;             /* write protected */
65        u32 _de_res:5;
66        u32 de_ppn:24;         /* 24 bit Physical Page Number
67                                 * representing address [28:51] */
68    } de_bits;
69};
70
71struct dma_window {
72    u32 dw_liobn;
73    u32 dw_base_hi;
74    u64 dw_base;
75    u64 dw_size;
76};
77
78struct dart_info {
79    struct dma_window di_window;
80    ulong di_base;
81    int di_model;
82};
83
84static u32 dart_encode(int perm, ulong rpn)
85{
86    union dart_entry e;
87
88    e.de_word = 0;
89    e.de_bits.de_v = 1;
90    e.de_bits.de_ppn = rpn;
91
92    /* protect the page */
93    e.de_bits.de_rp = 1;
94    e.de_bits.de_wp = 1;
95    if (perm & DART_READ) {
96        e.de_bits.de_rp = 0;
97    }
98    if (perm & DART_WRITE) {
99        e.de_bits.de_wp = 0;
100    }
101    return e.de_word;
102}
103
104static void dart_fill(ulong index, int perm, ulong rpg, ulong num_pg)
105{
106    u32 volatile *entry = dart_table + index;
107    ulong i = 0;
108    ulong last_flush = 0;
109
110    while (1) {
111        entry[i] = dart_encode(perm, rpg);
112        ++i;
113        ++rpg;
114        if (i == num_pg) break;
115
116        if ((((ulong)&entry[i]) % cpu_caches.dline_size) == 0) {
117            last_flush = (ulong)&entry[i - 1];
118            dcbst(last_flush);
119        }
120    }
121    dcbst((ulong) &entry[i - 1]);
122}
123
124static void dart_clear(ulong index, ulong num_pg)
125{
126    u32 *entry = dart_table + index;
127    ulong i = 0;
128    ulong rpg = dummy_page;
129    ulong last_flush = 0;
130
131    while (1) {
132        entry[i] = dart_encode(DART_READ | DART_WRITE, rpg);
133        ++i;
134        if (i == num_pg) break;
135
136        if ((((ulong)&entry[i]) % cpu_caches.dline_size) == 0) {
137            last_flush = (ulong)&entry[i - 1];
138            dcbst(last_flush);
139        }
140    }
141    dcbst((ulong)&entry[i - 1]);
142}
143
144static int dart_put(ulong ioba, union tce tce)
145{
146    ulong index = ioba >> PAGE_SHIFT;
147
148    if (index > dart_entries) {
149        return -1;
150    }
151
152    if (tce.tce_bits.tce_vlps  != 0 || tce.tce_bits.tce_lpx != 0) {
153        panic("no support for large TCEs\n");
154    }
155
156    if (tce.tce_bits.tce_read == 0 &&
157        tce.tce_bits.tce_write == 0) {
158        /* the TCE table is inited by the domain by a bunch of 0
159         * perminssion puts.  We are only interesting in debugging the
160         * ones after the first put */
161        DBG_AFTER(">DART[0x%lx] clear\n", index);
162        dart_clear(index, 1);
163    } else {
164        unsigned perm = 0;
165
166        if (tce.tce_bits.tce_read)
167            perm |= DART_READ;
168        if (tce.tce_bits.tce_write)
169            perm |= DART_WRITE;
170
171        DBG("<DART[0x%lx]: ioba: 0x%lx perm:%x[%c%c] rpn:0x%lx\n",
172            index, ioba, perm,
173            (perm & DART_READ) ? 'R' : '-',
174            (perm & DART_WRITE) ? 'W' : '-',
175            (ulong)tce.tce_bits.tce_rpn);
176        DBG_SET_AFTER;
177
178        dart_fill(index, perm, tce.tce_bits.tce_rpn, 1);
179    }
180    dops->do_inv_entry(tce.tce_bits.tce_rpn);
181   
182    return 0;
183}
184
185static int find_dart(struct dart_info *di)
186{
187    int rc;
188    void *ofd_p;
189    ofdn_t n;
190    char compat[128];
191
192    if (on_systemsim()) {
193        DBG("%s: systemsim does not support a dart\n", __func__);
194        return -1;
195    }
196
197    ofd_p = (void *)oftree;
198    n = ofd_node_find(ofd_p, "/ht");
199    if (n <= 0)
200        return -1;
201
202    /* get the defaults from the HT node model */
203    rc = ofd_getprop(ofd_p, n, "compatible", compat, sizeof (compat));
204    if (rc <= 0)
205        return -1;
206
207    if (ofd_strstr(compat, rc, "u4"))
208        di->di_model = DART_U4;
209    else if (ofd_strstr(compat, rc, "u3"))
210        di->di_model = DART_U3;
211    else {
212        DBG("%s: not a U3 or U4\n", __func__);
213        return -1;
214    }
215       
216    di->di_base = DART_DEF_BASE;
217
218    /* FIXME: this should actually be the HT reg value */
219    di->di_window.dw_liobn = 0;
220    di->di_window.dw_base_hi = 0;
221    di->di_window.dw_base = 0;
222
223    /* lets see if the devtree has more info */
224    n = ofd_node_find(ofd_p, "/dart");
225    if (n > 0) {
226        ulong base;
227
228        rc = ofd_getprop(ofd_p, n, "compatible", compat, sizeof (compat));
229        if (rc > 0) {
230            if (strstr(compat, "u4")) {
231                di->di_model = DART_U4;
232            }
233        }
234
235        rc = ofd_getprop(ofd_p, n, "reg", &base, sizeof (base));
236        if (rc > 0) {
237            di->di_base = base;
238        }
239    }
240    return 0;
241}
242
243static int init_dart(void)
244{
245    ulong log_pgs;
246    void *ofd_p;
247    ofdn_t n;
248    struct dart_info di;
249
250    if (find_dart(&di))
251        return 0;
252
253    /* Max size of 512 pages == 2MB == 1<<21. That siz is good enough for U4 */
254    log_pgs = U3_LOG_MAX_PAGES;
255    dart_table = alloc_xenheap_pages(log_pgs);
256    BUG_ON(dart_table == NULL);
257
258    dart_entries = (1UL << (log_pgs + PAGE_SHIFT)) / sizeof (union dart_entry);
259    di.di_window.dw_size = dart_entries << PAGE_SHIFT;
260
261    /* Linux uses a dummy page, filling "empty" DART entries with a
262       reference to this page to capture stray DMA's */
263    dummy_page = (ulong)alloc_xenheap_pages(0);
264    clear_page((void *)dummy_page);
265    dummy_page >>= PAGE_SHIFT;
266
267    printk("Initializing DART 0x%lx: tbl: %p[0x%lx] entries: 0x%lx\n",
268           di.di_base, dart_table, 1UL << log_pgs, dart_entries);
269           
270    /* register this iommu */
271    iommu_register(di.di_window.dw_liobn, dart_put);
272
273    switch (di.di_model) {
274    case DART_U3:
275        dops = u3_init(di.di_base, (ulong)dart_table, 1UL << log_pgs);
276        break;
277    case DART_U4:
278        dops = u4_init(di.di_base, (ulong)dart_table, 1UL << log_pgs);
279        break;
280    }
281
282    dart_clear(0, dart_entries);
283    dops->do_inv_all();
284
285    /* fix up the devtree */
286    ofd_p = (void *)oftree;
287    n = ofd_node_find(ofd_p, "/ht");
288    if (n > 0) {
289        di.di_window.dw_size = dart_entries << PAGE_SHIFT;
290        ofd_prop_add(ofd_p, n, "ibm,dma-window", &di.di_window,
291                     sizeof (di.di_window));
292    } else {
293        panic("%s: no /ht node\n", __func__);
294    }
295    return 0;
296}
297__initcall(init_dart);
Note: See TracBrowser for help on using the repository browser.