diff options
Diffstat (limited to 'arch/mips/sgi-ip27/ip27-hubio.c')
-rw-r--r-- | arch/mips/sgi-ip27/ip27-hubio.c | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/arch/mips/sgi-ip27/ip27-hubio.c b/arch/mips/sgi-ip27/ip27-hubio.c new file mode 100644 index 000000000000..524b371f9397 --- /dev/null +++ b/arch/mips/sgi-ip27/ip27-hubio.c | |||
@@ -0,0 +1,186 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. | ||
3 | * Copyright (C) 2004 Christoph Hellwig. | ||
4 | * Released under GPL v2. | ||
5 | * | ||
6 | * Support functions for the HUB ASIC - mostly PIO mapping related. | ||
7 | */ | ||
8 | |||
9 | #include <linux/bitops.h> | ||
10 | #include <linux/string.h> | ||
11 | #include <linux/mmzone.h> | ||
12 | #include <asm/sn/addrs.h> | ||
13 | #include <asm/sn/arch.h> | ||
14 | #include <asm/sn/hub.h> | ||
15 | |||
16 | |||
17 | static int force_fire_and_forget = 1; | ||
18 | |||
19 | /** | ||
20 | * hub_pio_map - establish a HUB PIO mapping | ||
21 | * | ||
22 | * @hub: hub to perform PIO mapping on | ||
23 | * @widget: widget ID to perform PIO mapping for | ||
24 | * @xtalk_addr: xtalk_address that needs to be mapped | ||
25 | * @size: size of the PIO mapping | ||
26 | * | ||
27 | **/ | ||
28 | unsigned long hub_pio_map(cnodeid_t cnode, xwidgetnum_t widget, | ||
29 | unsigned long xtalk_addr, size_t size) | ||
30 | { | ||
31 | nasid_t nasid = COMPACT_TO_NASID_NODEID(cnode); | ||
32 | volatile hubreg_t junk; | ||
33 | unsigned i; | ||
34 | |||
35 | /* use small-window mapping if possible */ | ||
36 | if ((xtalk_addr % SWIN_SIZE) + size <= SWIN_SIZE) | ||
37 | return NODE_SWIN_BASE(nasid, widget) + (xtalk_addr % SWIN_SIZE); | ||
38 | |||
39 | if ((xtalk_addr % BWIN_SIZE) + size > BWIN_SIZE) { | ||
40 | printk(KERN_WARNING "PIO mapping at hub %d widget %d addr 0x%lx" | ||
41 | " too big (%ld)\n", | ||
42 | nasid, widget, xtalk_addr, size); | ||
43 | return 0; | ||
44 | } | ||
45 | |||
46 | xtalk_addr &= ~(BWIN_SIZE-1); | ||
47 | for (i = 0; i < HUB_NUM_BIG_WINDOW; i++) { | ||
48 | if (test_and_set_bit(i, hub_data(cnode)->h_bigwin_used)) | ||
49 | continue; | ||
50 | |||
51 | /* | ||
52 | * The code below does a PIO write to setup an ITTE entry. | ||
53 | * | ||
54 | * We need to prevent other CPUs from seeing our updated | ||
55 | * memory shadow of the ITTE (in the piomap) until the ITTE | ||
56 | * entry is actually set up; otherwise, another CPU might | ||
57 | * attempt a PIO prematurely. | ||
58 | * | ||
59 | * Also, the only way we can know that an entry has been | ||
60 | * received by the hub and can be used by future PIO reads/ | ||
61 | * writes is by reading back the ITTE entry after writing it. | ||
62 | * | ||
63 | * For these two reasons, we PIO read back the ITTE entry | ||
64 | * after we write it. | ||
65 | */ | ||
66 | IIO_ITTE_PUT(nasid, i, HUB_PIO_MAP_TO_MEM, widget, xtalk_addr); | ||
67 | junk = HUB_L(IIO_ITTE_GET(nasid, i)); | ||
68 | |||
69 | return NODE_BWIN_BASE(nasid, widget) + (xtalk_addr % BWIN_SIZE); | ||
70 | } | ||
71 | |||
72 | printk(KERN_WARNING "unable to establish PIO mapping for at" | ||
73 | " hub %d widget %d addr 0x%lx\n", | ||
74 | nasid, widget, xtalk_addr); | ||
75 | return 0; | ||
76 | } | ||
77 | |||
78 | |||
79 | /* | ||
80 | * hub_setup_prb(nasid, prbnum, credits, conveyor) | ||
81 | * | ||
82 | * Put a PRB into fire-and-forget mode if conveyor isn't set. Otherwise, | ||
83 | * put it into conveyor belt mode with the specified number of credits. | ||
84 | */ | ||
85 | static void hub_setup_prb(nasid_t nasid, int prbnum, int credits) | ||
86 | { | ||
87 | iprb_t prb; | ||
88 | int prb_offset; | ||
89 | |||
90 | /* | ||
91 | * Get the current register value. | ||
92 | */ | ||
93 | prb_offset = IIO_IOPRB(prbnum); | ||
94 | prb.iprb_regval = REMOTE_HUB_L(nasid, prb_offset); | ||
95 | |||
96 | /* | ||
97 | * Clear out some fields. | ||
98 | */ | ||
99 | prb.iprb_ovflow = 1; | ||
100 | prb.iprb_bnakctr = 0; | ||
101 | prb.iprb_anakctr = 0; | ||
102 | |||
103 | /* | ||
104 | * Enable or disable fire-and-forget mode. | ||
105 | */ | ||
106 | prb.iprb_ff = force_fire_and_forget ? 1 : 0; | ||
107 | |||
108 | /* | ||
109 | * Set the appropriate number of PIO cresits for the widget. | ||
110 | */ | ||
111 | prb.iprb_xtalkctr = credits; | ||
112 | |||
113 | /* | ||
114 | * Store the new value to the register. | ||
115 | */ | ||
116 | REMOTE_HUB_S(nasid, prb_offset, prb.iprb_regval); | ||
117 | } | ||
118 | |||
119 | /** | ||
120 | * hub_set_piomode - set pio mode for a given hub | ||
121 | * | ||
122 | * @nasid: physical node ID for the hub in question | ||
123 | * | ||
124 | * Put the hub into either "PIO conveyor belt" mode or "fire-and-forget" mode. | ||
125 | * To do this, we have to make absolutely sure that no PIOs are in progress | ||
126 | * so we turn off access to all widgets for the duration of the function. | ||
127 | * | ||
128 | * XXX - This code should really check what kind of widget we're talking | ||
129 | * to. Bridges can only handle three requests, but XG will do more. | ||
130 | * How many can crossbow handle to widget 0? We're assuming 1. | ||
131 | * | ||
132 | * XXX - There is a bug in the crossbow that link reset PIOs do not | ||
133 | * return write responses. The easiest solution to this problem is to | ||
134 | * leave widget 0 (xbow) in fire-and-forget mode at all times. This | ||
135 | * only affects pio's to xbow registers, which should be rare. | ||
136 | **/ | ||
137 | static void hub_set_piomode(nasid_t nasid) | ||
138 | { | ||
139 | hubreg_t ii_iowa; | ||
140 | hubii_wcr_t ii_wcr; | ||
141 | unsigned i; | ||
142 | |||
143 | ii_iowa = REMOTE_HUB_L(nasid, IIO_OUTWIDGET_ACCESS); | ||
144 | REMOTE_HUB_S(nasid, IIO_OUTWIDGET_ACCESS, 0); | ||
145 | |||
146 | ii_wcr.wcr_reg_value = REMOTE_HUB_L(nasid, IIO_WCR); | ||
147 | |||
148 | if (ii_wcr.iwcr_dir_con) { | ||
149 | /* | ||
150 | * Assume a bridge here. | ||
151 | */ | ||
152 | hub_setup_prb(nasid, 0, 3); | ||
153 | } else { | ||
154 | /* | ||
155 | * Assume a crossbow here. | ||
156 | */ | ||
157 | hub_setup_prb(nasid, 0, 1); | ||
158 | } | ||
159 | |||
160 | /* | ||
161 | * XXX - Here's where we should take the widget type into | ||
162 | * when account assigning credits. | ||
163 | */ | ||
164 | for (i = HUB_WIDGET_ID_MIN; i <= HUB_WIDGET_ID_MAX; i++) | ||
165 | hub_setup_prb(nasid, i, 3); | ||
166 | |||
167 | REMOTE_HUB_S(nasid, IIO_OUTWIDGET_ACCESS, ii_iowa); | ||
168 | } | ||
169 | |||
170 | /* | ||
171 | * hub_pio_init - PIO-related hub initalization | ||
172 | * | ||
173 | * @hub: hubinfo structure for our hub | ||
174 | */ | ||
175 | void hub_pio_init(cnodeid_t cnode) | ||
176 | { | ||
177 | nasid_t nasid = COMPACT_TO_NASID_NODEID(cnode); | ||
178 | unsigned i; | ||
179 | |||
180 | /* initialize big window piomaps for this hub */ | ||
181 | bitmap_zero(hub_data(cnode)->h_bigwin_used, HUB_NUM_BIG_WINDOW); | ||
182 | for (i = 0; i < HUB_NUM_BIG_WINDOW; i++) | ||
183 | IIO_ITTE_DISABLE(nasid, i); | ||
184 | |||
185 | hub_set_piomode(nasid); | ||
186 | } | ||