diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/ieee1394/csr.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/ieee1394/csr.c')
-rw-r--r-- | drivers/ieee1394/csr.c | 857 |
1 files changed, 857 insertions, 0 deletions
diff --git a/drivers/ieee1394/csr.c b/drivers/ieee1394/csr.c new file mode 100644 index 000000000000..1b98684aebcd --- /dev/null +++ b/drivers/ieee1394/csr.c | |||
@@ -0,0 +1,857 @@ | |||
1 | /* | ||
2 | * IEEE 1394 for Linux | ||
3 | * | ||
4 | * CSR implementation, iso/bus manager implementation. | ||
5 | * | ||
6 | * Copyright (C) 1999 Andreas E. Bombe | ||
7 | * 2002 Manfred Weihs <weihs@ict.tuwien.ac.at> | ||
8 | * | ||
9 | * This code is licensed under the GPL. See the file COPYING in the root | ||
10 | * directory of the kernel sources for details. | ||
11 | * | ||
12 | * | ||
13 | * Contributions: | ||
14 | * | ||
15 | * Manfred Weihs <weihs@ict.tuwien.ac.at> | ||
16 | * configuration ROM manipulation | ||
17 | * | ||
18 | */ | ||
19 | |||
20 | #include <linux/string.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/moduleparam.h> | ||
23 | #include <linux/param.h> | ||
24 | #include <linux/spinlock.h> | ||
25 | |||
26 | #include "csr1212.h" | ||
27 | #include "ieee1394_types.h" | ||
28 | #include "hosts.h" | ||
29 | #include "ieee1394.h" | ||
30 | #include "highlevel.h" | ||
31 | |||
32 | /* Module Parameters */ | ||
33 | /* this module parameter can be used to disable mapping of the FCP registers */ | ||
34 | |||
35 | static int fcp = 1; | ||
36 | module_param(fcp, int, 0444); | ||
37 | MODULE_PARM_DESC(fcp, "Map FCP registers (default = 1, disable = 0)."); | ||
38 | |||
39 | static struct csr1212_keyval *node_cap = NULL; | ||
40 | |||
41 | static void add_host(struct hpsb_host *host); | ||
42 | static void remove_host(struct hpsb_host *host); | ||
43 | static void host_reset(struct hpsb_host *host); | ||
44 | static int read_maps(struct hpsb_host *host, int nodeid, quadlet_t *buffer, | ||
45 | u64 addr, size_t length, u16 fl); | ||
46 | static int write_fcp(struct hpsb_host *host, int nodeid, int dest, | ||
47 | quadlet_t *data, u64 addr, size_t length, u16 flags); | ||
48 | static int read_regs(struct hpsb_host *host, int nodeid, quadlet_t *buf, | ||
49 | u64 addr, size_t length, u16 flags); | ||
50 | static int write_regs(struct hpsb_host *host, int nodeid, int destid, | ||
51 | quadlet_t *data, u64 addr, size_t length, u16 flags); | ||
52 | static int lock_regs(struct hpsb_host *host, int nodeid, quadlet_t *store, | ||
53 | u64 addr, quadlet_t data, quadlet_t arg, int extcode, u16 fl); | ||
54 | static int lock64_regs(struct hpsb_host *host, int nodeid, octlet_t * store, | ||
55 | u64 addr, octlet_t data, octlet_t arg, int extcode, u16 fl); | ||
56 | static int read_config_rom(struct hpsb_host *host, int nodeid, quadlet_t *buffer, | ||
57 | u64 addr, size_t length, u16 fl); | ||
58 | static u64 allocate_addr_range(u64 size, u32 alignment, void *__host); | ||
59 | static void release_addr_range(u64 addr, void *__host); | ||
60 | |||
61 | static struct hpsb_highlevel csr_highlevel = { | ||
62 | .name = "standard registers", | ||
63 | .add_host = add_host, | ||
64 | .remove_host = remove_host, | ||
65 | .host_reset = host_reset, | ||
66 | }; | ||
67 | |||
68 | static struct hpsb_address_ops map_ops = { | ||
69 | .read = read_maps, | ||
70 | }; | ||
71 | |||
72 | static struct hpsb_address_ops fcp_ops = { | ||
73 | .write = write_fcp, | ||
74 | }; | ||
75 | |||
76 | static struct hpsb_address_ops reg_ops = { | ||
77 | .read = read_regs, | ||
78 | .write = write_regs, | ||
79 | .lock = lock_regs, | ||
80 | .lock64 = lock64_regs, | ||
81 | }; | ||
82 | |||
83 | static struct hpsb_address_ops config_rom_ops = { | ||
84 | .read = read_config_rom, | ||
85 | }; | ||
86 | |||
87 | struct csr1212_bus_ops csr_bus_ops = { | ||
88 | .allocate_addr_range = allocate_addr_range, | ||
89 | .release_addr = release_addr_range, | ||
90 | }; | ||
91 | |||
92 | |||
93 | static u16 csr_crc16(unsigned *data, int length) | ||
94 | { | ||
95 | int check=0, i; | ||
96 | int shift, sum, next=0; | ||
97 | |||
98 | for (i = length; i; i--) { | ||
99 | for (next = check, shift = 28; shift >= 0; shift -= 4 ) { | ||
100 | sum = ((next >> 12) ^ (be32_to_cpu(*data) >> shift)) & 0xf; | ||
101 | next = (next << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum); | ||
102 | } | ||
103 | check = next & 0xffff; | ||
104 | data++; | ||
105 | } | ||
106 | |||
107 | return check; | ||
108 | } | ||
109 | |||
110 | static void host_reset(struct hpsb_host *host) | ||
111 | { | ||
112 | host->csr.state &= 0x300; | ||
113 | |||
114 | host->csr.bus_manager_id = 0x3f; | ||
115 | host->csr.bandwidth_available = 4915; | ||
116 | host->csr.channels_available_hi = 0xfffffffe; /* pre-alloc ch 31 per 1394a-2000 */ | ||
117 | host->csr.channels_available_lo = ~0; | ||
118 | host->csr.broadcast_channel = 0x80000000 | 31; | ||
119 | |||
120 | if (host->is_irm) { | ||
121 | if (host->driver->hw_csr_reg) { | ||
122 | host->driver->hw_csr_reg(host, 2, 0xfffffffe, ~0); | ||
123 | } | ||
124 | } | ||
125 | |||
126 | host->csr.node_ids = host->node_id << 16; | ||
127 | |||
128 | if (!host->is_root) { | ||
129 | /* clear cmstr bit */ | ||
130 | host->csr.state &= ~0x100; | ||
131 | } | ||
132 | |||
133 | host->csr.topology_map[1] = | ||
134 | cpu_to_be32(be32_to_cpu(host->csr.topology_map[1]) + 1); | ||
135 | host->csr.topology_map[2] = cpu_to_be32(host->node_count << 16 | ||
136 | | host->selfid_count); | ||
137 | host->csr.topology_map[0] = | ||
138 | cpu_to_be32((host->selfid_count + 2) << 16 | ||
139 | | csr_crc16(host->csr.topology_map + 1, | ||
140 | host->selfid_count + 2)); | ||
141 | |||
142 | host->csr.speed_map[1] = | ||
143 | cpu_to_be32(be32_to_cpu(host->csr.speed_map[1]) + 1); | ||
144 | host->csr.speed_map[0] = cpu_to_be32(0x3f1 << 16 | ||
145 | | csr_crc16(host->csr.speed_map+1, | ||
146 | 0x3f1)); | ||
147 | } | ||
148 | |||
149 | /* | ||
150 | * HI == seconds (bits 0:2) | ||
151 | * LO == fraction units of 1/8000 of a second, as per 1394 (bits 19:31) | ||
152 | * | ||
153 | * Convert to units and then to HZ, for comparison to jiffies. | ||
154 | * | ||
155 | * By default this will end up being 800 units, or 100ms (125usec per | ||
156 | * unit). | ||
157 | * | ||
158 | * NOTE: The spec says 1/8000, but also says we can compute based on 1/8192 | ||
159 | * like CSR specifies. Should make our math less complex. | ||
160 | */ | ||
161 | static inline void calculate_expire(struct csr_control *csr) | ||
162 | { | ||
163 | unsigned long units; | ||
164 | |||
165 | /* Take the seconds, and convert to units */ | ||
166 | units = (unsigned long)(csr->split_timeout_hi & 0x07) << 13; | ||
167 | |||
168 | /* Add in the fractional units */ | ||
169 | units += (unsigned long)(csr->split_timeout_lo >> 19); | ||
170 | |||
171 | /* Convert to jiffies */ | ||
172 | csr->expire = (unsigned long)(units * HZ) >> 13UL; | ||
173 | |||
174 | /* Just to keep from rounding low */ | ||
175 | csr->expire++; | ||
176 | |||
177 | HPSB_VERBOSE("CSR: setting expire to %lu, HZ=%u", csr->expire, HZ); | ||
178 | } | ||
179 | |||
180 | |||
181 | static void add_host(struct hpsb_host *host) | ||
182 | { | ||
183 | struct csr1212_keyval *root; | ||
184 | quadlet_t bus_info[CSR_BUS_INFO_SIZE]; | ||
185 | |||
186 | hpsb_register_addrspace(&csr_highlevel, host, ®_ops, | ||
187 | CSR_REGISTER_BASE, | ||
188 | CSR_REGISTER_BASE + CSR_CONFIG_ROM); | ||
189 | hpsb_register_addrspace(&csr_highlevel, host, &config_rom_ops, | ||
190 | CSR_REGISTER_BASE + CSR_CONFIG_ROM, | ||
191 | CSR_REGISTER_BASE + CSR_CONFIG_ROM_END); | ||
192 | if (fcp) { | ||
193 | hpsb_register_addrspace(&csr_highlevel, host, &fcp_ops, | ||
194 | CSR_REGISTER_BASE + CSR_FCP_COMMAND, | ||
195 | CSR_REGISTER_BASE + CSR_FCP_END); | ||
196 | } | ||
197 | hpsb_register_addrspace(&csr_highlevel, host, &map_ops, | ||
198 | CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP, | ||
199 | CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP_END); | ||
200 | hpsb_register_addrspace(&csr_highlevel, host, &map_ops, | ||
201 | CSR_REGISTER_BASE + CSR_SPEED_MAP, | ||
202 | CSR_REGISTER_BASE + CSR_SPEED_MAP_END); | ||
203 | |||
204 | spin_lock_init(&host->csr.lock); | ||
205 | |||
206 | host->csr.state = 0; | ||
207 | host->csr.node_ids = 0; | ||
208 | host->csr.split_timeout_hi = 0; | ||
209 | host->csr.split_timeout_lo = 800 << 19; | ||
210 | calculate_expire(&host->csr); | ||
211 | host->csr.cycle_time = 0; | ||
212 | host->csr.bus_time = 0; | ||
213 | host->csr.bus_manager_id = 0x3f; | ||
214 | host->csr.bandwidth_available = 4915; | ||
215 | host->csr.channels_available_hi = 0xfffffffe; /* pre-alloc ch 31 per 1394a-2000 */ | ||
216 | host->csr.channels_available_lo = ~0; | ||
217 | host->csr.broadcast_channel = 0x80000000 | 31; | ||
218 | |||
219 | if (host->is_irm) { | ||
220 | if (host->driver->hw_csr_reg) { | ||
221 | host->driver->hw_csr_reg(host, 2, 0xfffffffe, ~0); | ||
222 | } | ||
223 | } | ||
224 | |||
225 | if (host->csr.max_rec >= 9) | ||
226 | host->csr.max_rom = 2; | ||
227 | else if (host->csr.max_rec >= 5) | ||
228 | host->csr.max_rom = 1; | ||
229 | else | ||
230 | host->csr.max_rom = 0; | ||
231 | |||
232 | host->csr.generation = 2; | ||
233 | |||
234 | bus_info[1] = __constant_cpu_to_be32(0x31333934); | ||
235 | bus_info[2] = cpu_to_be32((1 << CSR_IRMC_SHIFT) | | ||
236 | (1 << CSR_CMC_SHIFT) | | ||
237 | (1 << CSR_ISC_SHIFT) | | ||
238 | (0 << CSR_BMC_SHIFT) | | ||
239 | (0 << CSR_PMC_SHIFT) | | ||
240 | (host->csr.cyc_clk_acc << CSR_CYC_CLK_ACC_SHIFT) | | ||
241 | (host->csr.max_rec << CSR_MAX_REC_SHIFT) | | ||
242 | (host->csr.max_rom << CSR_MAX_ROM_SHIFT) | | ||
243 | (host->csr.generation << CSR_GENERATION_SHIFT) | | ||
244 | host->csr.lnk_spd); | ||
245 | |||
246 | bus_info[3] = cpu_to_be32(host->csr.guid_hi); | ||
247 | bus_info[4] = cpu_to_be32(host->csr.guid_lo); | ||
248 | |||
249 | /* The hardware copy of the bus info block will be set later when a | ||
250 | * bus reset is issued. */ | ||
251 | |||
252 | csr1212_init_local_csr(host->csr.rom, bus_info, host->csr.max_rom); | ||
253 | |||
254 | root = host->csr.rom->root_kv; | ||
255 | |||
256 | if(csr1212_attach_keyval_to_directory(root, node_cap) != CSR1212_SUCCESS) { | ||
257 | HPSB_ERR("Failed to attach Node Capabilities to root directory"); | ||
258 | } | ||
259 | |||
260 | host->update_config_rom = 1; | ||
261 | } | ||
262 | |||
263 | static void remove_host(struct hpsb_host *host) | ||
264 | { | ||
265 | quadlet_t bus_info[CSR_BUS_INFO_SIZE]; | ||
266 | |||
267 | bus_info[1] = __constant_cpu_to_be32(0x31333934); | ||
268 | bus_info[2] = cpu_to_be32((0 << CSR_IRMC_SHIFT) | | ||
269 | (0 << CSR_CMC_SHIFT) | | ||
270 | (0 << CSR_ISC_SHIFT) | | ||
271 | (0 << CSR_BMC_SHIFT) | | ||
272 | (0 << CSR_PMC_SHIFT) | | ||
273 | (host->csr.cyc_clk_acc << CSR_CYC_CLK_ACC_SHIFT) | | ||
274 | (host->csr.max_rec << CSR_MAX_REC_SHIFT) | | ||
275 | (0 << CSR_MAX_ROM_SHIFT) | | ||
276 | (0 << CSR_GENERATION_SHIFT) | | ||
277 | host->csr.lnk_spd); | ||
278 | |||
279 | bus_info[3] = cpu_to_be32(host->csr.guid_hi); | ||
280 | bus_info[4] = cpu_to_be32(host->csr.guid_lo); | ||
281 | |||
282 | csr1212_detach_keyval_from_directory(host->csr.rom->root_kv, node_cap); | ||
283 | |||
284 | csr1212_init_local_csr(host->csr.rom, bus_info, 0); | ||
285 | host->update_config_rom = 1; | ||
286 | } | ||
287 | |||
288 | |||
289 | int hpsb_update_config_rom(struct hpsb_host *host, const quadlet_t *new_rom, | ||
290 | size_t buffersize, unsigned char rom_version) | ||
291 | { | ||
292 | unsigned long flags; | ||
293 | int ret; | ||
294 | |||
295 | HPSB_NOTICE("hpsb_update_config_rom() is deprecated"); | ||
296 | |||
297 | spin_lock_irqsave(&host->csr.lock, flags); | ||
298 | if (rom_version != host->csr.generation) | ||
299 | ret = -1; | ||
300 | else if (buffersize > host->csr.rom->cache_head->size) | ||
301 | ret = -2; | ||
302 | else { | ||
303 | /* Just overwrite the generated ConfigROM image with new data, | ||
304 | * it can be regenerated later. */ | ||
305 | memcpy(host->csr.rom->cache_head->data, new_rom, buffersize); | ||
306 | host->csr.rom->cache_head->len = buffersize; | ||
307 | |||
308 | if (host->driver->set_hw_config_rom) | ||
309 | host->driver->set_hw_config_rom(host, host->csr.rom->bus_info_data); | ||
310 | /* Increment the generation number to keep some sort of sync | ||
311 | * with the newer ConfigROM manipulation method. */ | ||
312 | host->csr.generation++; | ||
313 | if (host->csr.generation > 0xf || host->csr.generation < 2) | ||
314 | host->csr.generation = 2; | ||
315 | ret=0; | ||
316 | } | ||
317 | spin_unlock_irqrestore(&host->csr.lock, flags); | ||
318 | return ret; | ||
319 | } | ||
320 | |||
321 | |||
322 | /* Read topology / speed maps and configuration ROM */ | ||
323 | static int read_maps(struct hpsb_host *host, int nodeid, quadlet_t *buffer, | ||
324 | u64 addr, size_t length, u16 fl) | ||
325 | { | ||
326 | unsigned long flags; | ||
327 | int csraddr = addr - CSR_REGISTER_BASE; | ||
328 | const char *src; | ||
329 | |||
330 | spin_lock_irqsave(&host->csr.lock, flags); | ||
331 | |||
332 | if (csraddr < CSR_SPEED_MAP) { | ||
333 | src = ((char *)host->csr.topology_map) + csraddr | ||
334 | - CSR_TOPOLOGY_MAP; | ||
335 | } else { | ||
336 | src = ((char *)host->csr.speed_map) + csraddr - CSR_SPEED_MAP; | ||
337 | } | ||
338 | |||
339 | memcpy(buffer, src, length); | ||
340 | spin_unlock_irqrestore(&host->csr.lock, flags); | ||
341 | return RCODE_COMPLETE; | ||
342 | } | ||
343 | |||
344 | |||
345 | #define out if (--length == 0) break | ||
346 | |||
347 | static int read_regs(struct hpsb_host *host, int nodeid, quadlet_t *buf, | ||
348 | u64 addr, size_t length, u16 flags) | ||
349 | { | ||
350 | int csraddr = addr - CSR_REGISTER_BASE; | ||
351 | int oldcycle; | ||
352 | quadlet_t ret; | ||
353 | |||
354 | if ((csraddr | length) & 0x3) | ||
355 | return RCODE_TYPE_ERROR; | ||
356 | |||
357 | length /= 4; | ||
358 | |||
359 | switch (csraddr) { | ||
360 | case CSR_STATE_CLEAR: | ||
361 | *(buf++) = cpu_to_be32(host->csr.state); | ||
362 | out; | ||
363 | case CSR_STATE_SET: | ||
364 | *(buf++) = cpu_to_be32(host->csr.state); | ||
365 | out; | ||
366 | case CSR_NODE_IDS: | ||
367 | *(buf++) = cpu_to_be32(host->csr.node_ids); | ||
368 | out; | ||
369 | |||
370 | case CSR_RESET_START: | ||
371 | return RCODE_TYPE_ERROR; | ||
372 | |||
373 | /* address gap - handled by default below */ | ||
374 | |||
375 | case CSR_SPLIT_TIMEOUT_HI: | ||
376 | *(buf++) = cpu_to_be32(host->csr.split_timeout_hi); | ||
377 | out; | ||
378 | case CSR_SPLIT_TIMEOUT_LO: | ||
379 | *(buf++) = cpu_to_be32(host->csr.split_timeout_lo); | ||
380 | out; | ||
381 | |||
382 | /* address gap */ | ||
383 | return RCODE_ADDRESS_ERROR; | ||
384 | |||
385 | case CSR_CYCLE_TIME: | ||
386 | oldcycle = host->csr.cycle_time; | ||
387 | host->csr.cycle_time = | ||
388 | host->driver->devctl(host, GET_CYCLE_COUNTER, 0); | ||
389 | |||
390 | if (oldcycle > host->csr.cycle_time) { | ||
391 | /* cycle time wrapped around */ | ||
392 | host->csr.bus_time += 1 << 7; | ||
393 | } | ||
394 | *(buf++) = cpu_to_be32(host->csr.cycle_time); | ||
395 | out; | ||
396 | case CSR_BUS_TIME: | ||
397 | oldcycle = host->csr.cycle_time; | ||
398 | host->csr.cycle_time = | ||
399 | host->driver->devctl(host, GET_CYCLE_COUNTER, 0); | ||
400 | |||
401 | if (oldcycle > host->csr.cycle_time) { | ||
402 | /* cycle time wrapped around */ | ||
403 | host->csr.bus_time += (1 << 7); | ||
404 | } | ||
405 | *(buf++) = cpu_to_be32(host->csr.bus_time | ||
406 | | (host->csr.cycle_time >> 25)); | ||
407 | out; | ||
408 | |||
409 | /* address gap */ | ||
410 | return RCODE_ADDRESS_ERROR; | ||
411 | |||
412 | case CSR_BUSY_TIMEOUT: | ||
413 | /* not yet implemented */ | ||
414 | return RCODE_ADDRESS_ERROR; | ||
415 | |||
416 | case CSR_BUS_MANAGER_ID: | ||
417 | if (host->driver->hw_csr_reg) | ||
418 | ret = host->driver->hw_csr_reg(host, 0, 0, 0); | ||
419 | else | ||
420 | ret = host->csr.bus_manager_id; | ||
421 | |||
422 | *(buf++) = cpu_to_be32(ret); | ||
423 | out; | ||
424 | case CSR_BANDWIDTH_AVAILABLE: | ||
425 | if (host->driver->hw_csr_reg) | ||
426 | ret = host->driver->hw_csr_reg(host, 1, 0, 0); | ||
427 | else | ||
428 | ret = host->csr.bandwidth_available; | ||
429 | |||
430 | *(buf++) = cpu_to_be32(ret); | ||
431 | out; | ||
432 | case CSR_CHANNELS_AVAILABLE_HI: | ||
433 | if (host->driver->hw_csr_reg) | ||
434 | ret = host->driver->hw_csr_reg(host, 2, 0, 0); | ||
435 | else | ||
436 | ret = host->csr.channels_available_hi; | ||
437 | |||
438 | *(buf++) = cpu_to_be32(ret); | ||
439 | out; | ||
440 | case CSR_CHANNELS_AVAILABLE_LO: | ||
441 | if (host->driver->hw_csr_reg) | ||
442 | ret = host->driver->hw_csr_reg(host, 3, 0, 0); | ||
443 | else | ||
444 | ret = host->csr.channels_available_lo; | ||
445 | |||
446 | *(buf++) = cpu_to_be32(ret); | ||
447 | out; | ||
448 | |||
449 | case CSR_BROADCAST_CHANNEL: | ||
450 | *(buf++) = cpu_to_be32(host->csr.broadcast_channel); | ||
451 | out; | ||
452 | |||
453 | /* address gap to end - fall through to default */ | ||
454 | default: | ||
455 | return RCODE_ADDRESS_ERROR; | ||
456 | } | ||
457 | |||
458 | return RCODE_COMPLETE; | ||
459 | } | ||
460 | |||
461 | static int write_regs(struct hpsb_host *host, int nodeid, int destid, | ||
462 | quadlet_t *data, u64 addr, size_t length, u16 flags) | ||
463 | { | ||
464 | int csraddr = addr - CSR_REGISTER_BASE; | ||
465 | |||
466 | if ((csraddr | length) & 0x3) | ||
467 | return RCODE_TYPE_ERROR; | ||
468 | |||
469 | length /= 4; | ||
470 | |||
471 | switch (csraddr) { | ||
472 | case CSR_STATE_CLEAR: | ||
473 | /* FIXME FIXME FIXME */ | ||
474 | printk("doh, someone wants to mess with state clear\n"); | ||
475 | out; | ||
476 | case CSR_STATE_SET: | ||
477 | printk("doh, someone wants to mess with state set\n"); | ||
478 | out; | ||
479 | |||
480 | case CSR_NODE_IDS: | ||
481 | host->csr.node_ids &= NODE_MASK << 16; | ||
482 | host->csr.node_ids |= be32_to_cpu(*(data++)) & (BUS_MASK << 16); | ||
483 | host->node_id = host->csr.node_ids >> 16; | ||
484 | host->driver->devctl(host, SET_BUS_ID, host->node_id >> 6); | ||
485 | out; | ||
486 | |||
487 | case CSR_RESET_START: | ||
488 | /* FIXME - perform command reset */ | ||
489 | out; | ||
490 | |||
491 | /* address gap */ | ||
492 | return RCODE_ADDRESS_ERROR; | ||
493 | |||
494 | case CSR_SPLIT_TIMEOUT_HI: | ||
495 | host->csr.split_timeout_hi = | ||
496 | be32_to_cpu(*(data++)) & 0x00000007; | ||
497 | calculate_expire(&host->csr); | ||
498 | out; | ||
499 | case CSR_SPLIT_TIMEOUT_LO: | ||
500 | host->csr.split_timeout_lo = | ||
501 | be32_to_cpu(*(data++)) & 0xfff80000; | ||
502 | calculate_expire(&host->csr); | ||
503 | out; | ||
504 | |||
505 | /* address gap */ | ||
506 | return RCODE_ADDRESS_ERROR; | ||
507 | |||
508 | case CSR_CYCLE_TIME: | ||
509 | /* should only be set by cycle start packet, automatically */ | ||
510 | host->csr.cycle_time = be32_to_cpu(*data); | ||
511 | host->driver->devctl(host, SET_CYCLE_COUNTER, | ||
512 | be32_to_cpu(*(data++))); | ||
513 | out; | ||
514 | case CSR_BUS_TIME: | ||
515 | host->csr.bus_time = be32_to_cpu(*(data++)) & 0xffffff80; | ||
516 | out; | ||
517 | |||
518 | /* address gap */ | ||
519 | return RCODE_ADDRESS_ERROR; | ||
520 | |||
521 | case CSR_BUSY_TIMEOUT: | ||
522 | /* not yet implemented */ | ||
523 | return RCODE_ADDRESS_ERROR; | ||
524 | |||
525 | case CSR_BUS_MANAGER_ID: | ||
526 | case CSR_BANDWIDTH_AVAILABLE: | ||
527 | case CSR_CHANNELS_AVAILABLE_HI: | ||
528 | case CSR_CHANNELS_AVAILABLE_LO: | ||
529 | /* these are not writable, only lockable */ | ||
530 | return RCODE_TYPE_ERROR; | ||
531 | |||
532 | case CSR_BROADCAST_CHANNEL: | ||
533 | /* only the valid bit can be written */ | ||
534 | host->csr.broadcast_channel = (host->csr.broadcast_channel & ~0x40000000) | ||
535 | | (be32_to_cpu(*data) & 0x40000000); | ||
536 | out; | ||
537 | |||
538 | /* address gap to end - fall through */ | ||
539 | default: | ||
540 | return RCODE_ADDRESS_ERROR; | ||
541 | } | ||
542 | |||
543 | return RCODE_COMPLETE; | ||
544 | } | ||
545 | |||
546 | #undef out | ||
547 | |||
548 | |||
549 | static int lock_regs(struct hpsb_host *host, int nodeid, quadlet_t *store, | ||
550 | u64 addr, quadlet_t data, quadlet_t arg, int extcode, u16 fl) | ||
551 | { | ||
552 | int csraddr = addr - CSR_REGISTER_BASE; | ||
553 | unsigned long flags; | ||
554 | quadlet_t *regptr = NULL; | ||
555 | |||
556 | if (csraddr & 0x3) | ||
557 | return RCODE_TYPE_ERROR; | ||
558 | |||
559 | if (csraddr < CSR_BUS_MANAGER_ID || csraddr > CSR_CHANNELS_AVAILABLE_LO | ||
560 | || extcode != EXTCODE_COMPARE_SWAP) | ||
561 | goto unsupported_lockreq; | ||
562 | |||
563 | data = be32_to_cpu(data); | ||
564 | arg = be32_to_cpu(arg); | ||
565 | |||
566 | /* Is somebody releasing the broadcast_channel on us? */ | ||
567 | if (csraddr == CSR_CHANNELS_AVAILABLE_HI && (data & 0x1)) { | ||
568 | /* Note: this is may not be the right way to handle | ||
569 | * the problem, so we should look into the proper way | ||
570 | * eventually. */ | ||
571 | HPSB_WARN("Node [" NODE_BUS_FMT "] wants to release " | ||
572 | "broadcast channel 31. Ignoring.", | ||
573 | NODE_BUS_ARGS(host, nodeid)); | ||
574 | |||
575 | data &= ~0x1; /* keep broadcast channel allocated */ | ||
576 | } | ||
577 | |||
578 | if (host->driver->hw_csr_reg) { | ||
579 | quadlet_t old; | ||
580 | |||
581 | old = host->driver-> | ||
582 | hw_csr_reg(host, (csraddr - CSR_BUS_MANAGER_ID) >> 2, | ||
583 | data, arg); | ||
584 | |||
585 | *store = cpu_to_be32(old); | ||
586 | return RCODE_COMPLETE; | ||
587 | } | ||
588 | |||
589 | spin_lock_irqsave(&host->csr.lock, flags); | ||
590 | |||
591 | switch (csraddr) { | ||
592 | case CSR_BUS_MANAGER_ID: | ||
593 | regptr = &host->csr.bus_manager_id; | ||
594 | *store = cpu_to_be32(*regptr); | ||
595 | if (*regptr == arg) | ||
596 | *regptr = data; | ||
597 | break; | ||
598 | |||
599 | case CSR_BANDWIDTH_AVAILABLE: | ||
600 | { | ||
601 | quadlet_t bandwidth; | ||
602 | quadlet_t old; | ||
603 | quadlet_t new; | ||
604 | |||
605 | regptr = &host->csr.bandwidth_available; | ||
606 | old = *regptr; | ||
607 | |||
608 | /* bandwidth available algorithm adapted from IEEE 1394a-2000 spec */ | ||
609 | if (arg > 0x1fff) { | ||
610 | *store = cpu_to_be32(old); /* change nothing */ | ||
611 | break; | ||
612 | } | ||
613 | data &= 0x1fff; | ||
614 | if (arg >= data) { | ||
615 | /* allocate bandwidth */ | ||
616 | bandwidth = arg - data; | ||
617 | if (old >= bandwidth) { | ||
618 | new = old - bandwidth; | ||
619 | *store = cpu_to_be32(arg); | ||
620 | *regptr = new; | ||
621 | } else { | ||
622 | *store = cpu_to_be32(old); | ||
623 | } | ||
624 | } else { | ||
625 | /* deallocate bandwidth */ | ||
626 | bandwidth = data - arg; | ||
627 | if (old + bandwidth < 0x2000) { | ||
628 | new = old + bandwidth; | ||
629 | *store = cpu_to_be32(arg); | ||
630 | *regptr = new; | ||
631 | } else { | ||
632 | *store = cpu_to_be32(old); | ||
633 | } | ||
634 | } | ||
635 | break; | ||
636 | } | ||
637 | |||
638 | case CSR_CHANNELS_AVAILABLE_HI: | ||
639 | { | ||
640 | /* Lock algorithm for CHANNELS_AVAILABLE as recommended by 1394a-2000 */ | ||
641 | quadlet_t affected_channels = arg ^ data; | ||
642 | |||
643 | regptr = &host->csr.channels_available_hi; | ||
644 | |||
645 | if ((arg & affected_channels) == (*regptr & affected_channels)) { | ||
646 | *regptr ^= affected_channels; | ||
647 | *store = cpu_to_be32(arg); | ||
648 | } else { | ||
649 | *store = cpu_to_be32(*regptr); | ||
650 | } | ||
651 | |||
652 | break; | ||
653 | } | ||
654 | |||
655 | case CSR_CHANNELS_AVAILABLE_LO: | ||
656 | { | ||
657 | /* Lock algorithm for CHANNELS_AVAILABLE as recommended by 1394a-2000 */ | ||
658 | quadlet_t affected_channels = arg ^ data; | ||
659 | |||
660 | regptr = &host->csr.channels_available_lo; | ||
661 | |||
662 | if ((arg & affected_channels) == (*regptr & affected_channels)) { | ||
663 | *regptr ^= affected_channels; | ||
664 | *store = cpu_to_be32(arg); | ||
665 | } else { | ||
666 | *store = cpu_to_be32(*regptr); | ||
667 | } | ||
668 | break; | ||
669 | } | ||
670 | } | ||
671 | |||
672 | spin_unlock_irqrestore(&host->csr.lock, flags); | ||
673 | |||
674 | return RCODE_COMPLETE; | ||
675 | |||
676 | unsupported_lockreq: | ||
677 | switch (csraddr) { | ||
678 | case CSR_STATE_CLEAR: | ||
679 | case CSR_STATE_SET: | ||
680 | case CSR_RESET_START: | ||
681 | case CSR_NODE_IDS: | ||
682 | case CSR_SPLIT_TIMEOUT_HI: | ||
683 | case CSR_SPLIT_TIMEOUT_LO: | ||
684 | case CSR_CYCLE_TIME: | ||
685 | case CSR_BUS_TIME: | ||
686 | case CSR_BROADCAST_CHANNEL: | ||
687 | return RCODE_TYPE_ERROR; | ||
688 | |||
689 | case CSR_BUSY_TIMEOUT: | ||
690 | /* not yet implemented - fall through */ | ||
691 | default: | ||
692 | return RCODE_ADDRESS_ERROR; | ||
693 | } | ||
694 | } | ||
695 | |||
696 | static int lock64_regs(struct hpsb_host *host, int nodeid, octlet_t * store, | ||
697 | u64 addr, octlet_t data, octlet_t arg, int extcode, u16 fl) | ||
698 | { | ||
699 | int csraddr = addr - CSR_REGISTER_BASE; | ||
700 | unsigned long flags; | ||
701 | |||
702 | data = be64_to_cpu(data); | ||
703 | arg = be64_to_cpu(arg); | ||
704 | |||
705 | if (csraddr & 0x3) | ||
706 | return RCODE_TYPE_ERROR; | ||
707 | |||
708 | if (csraddr != CSR_CHANNELS_AVAILABLE | ||
709 | || extcode != EXTCODE_COMPARE_SWAP) | ||
710 | goto unsupported_lock64req; | ||
711 | |||
712 | /* Is somebody releasing the broadcast_channel on us? */ | ||
713 | if (csraddr == CSR_CHANNELS_AVAILABLE_HI && (data & 0x100000000ULL)) { | ||
714 | /* Note: this is may not be the right way to handle | ||
715 | * the problem, so we should look into the proper way | ||
716 | * eventually. */ | ||
717 | HPSB_WARN("Node [" NODE_BUS_FMT "] wants to release " | ||
718 | "broadcast channel 31. Ignoring.", | ||
719 | NODE_BUS_ARGS(host, nodeid)); | ||
720 | |||
721 | data &= ~0x100000000ULL; /* keep broadcast channel allocated */ | ||
722 | } | ||
723 | |||
724 | if (host->driver->hw_csr_reg) { | ||
725 | quadlet_t data_hi, data_lo; | ||
726 | quadlet_t arg_hi, arg_lo; | ||
727 | quadlet_t old_hi, old_lo; | ||
728 | |||
729 | data_hi = data >> 32; | ||
730 | data_lo = data & 0xFFFFFFFF; | ||
731 | arg_hi = arg >> 32; | ||
732 | arg_lo = arg & 0xFFFFFFFF; | ||
733 | |||
734 | old_hi = host->driver->hw_csr_reg(host, (csraddr - CSR_BUS_MANAGER_ID) >> 2, | ||
735 | data_hi, arg_hi); | ||
736 | |||
737 | old_lo = host->driver->hw_csr_reg(host, ((csraddr + 4) - CSR_BUS_MANAGER_ID) >> 2, | ||
738 | data_lo, arg_lo); | ||
739 | |||
740 | *store = cpu_to_be64(((octlet_t)old_hi << 32) | old_lo); | ||
741 | } else { | ||
742 | octlet_t old; | ||
743 | octlet_t affected_channels = arg ^ data; | ||
744 | |||
745 | spin_lock_irqsave(&host->csr.lock, flags); | ||
746 | |||
747 | old = ((octlet_t)host->csr.channels_available_hi << 32) | host->csr.channels_available_lo; | ||
748 | |||
749 | if ((arg & affected_channels) == (old & affected_channels)) { | ||
750 | host->csr.channels_available_hi ^= (affected_channels >> 32); | ||
751 | host->csr.channels_available_lo ^= (affected_channels & 0xffffffff); | ||
752 | *store = cpu_to_be64(arg); | ||
753 | } else { | ||
754 | *store = cpu_to_be64(old); | ||
755 | } | ||
756 | |||
757 | spin_unlock_irqrestore(&host->csr.lock, flags); | ||
758 | } | ||
759 | |||
760 | /* Is somebody erroneously releasing the broadcast_channel on us? */ | ||
761 | if (host->csr.channels_available_hi & 0x1) | ||
762 | host->csr.channels_available_hi &= ~0x1; | ||
763 | |||
764 | return RCODE_COMPLETE; | ||
765 | |||
766 | unsupported_lock64req: | ||
767 | switch (csraddr) { | ||
768 | case CSR_STATE_CLEAR: | ||
769 | case CSR_STATE_SET: | ||
770 | case CSR_RESET_START: | ||
771 | case CSR_NODE_IDS: | ||
772 | case CSR_SPLIT_TIMEOUT_HI: | ||
773 | case CSR_SPLIT_TIMEOUT_LO: | ||
774 | case CSR_CYCLE_TIME: | ||
775 | case CSR_BUS_TIME: | ||
776 | case CSR_BUS_MANAGER_ID: | ||
777 | case CSR_BROADCAST_CHANNEL: | ||
778 | case CSR_BUSY_TIMEOUT: | ||
779 | case CSR_BANDWIDTH_AVAILABLE: | ||
780 | return RCODE_TYPE_ERROR; | ||
781 | |||
782 | default: | ||
783 | return RCODE_ADDRESS_ERROR; | ||
784 | } | ||
785 | } | ||
786 | |||
787 | static int write_fcp(struct hpsb_host *host, int nodeid, int dest, | ||
788 | quadlet_t *data, u64 addr, size_t length, u16 flags) | ||
789 | { | ||
790 | int csraddr = addr - CSR_REGISTER_BASE; | ||
791 | |||
792 | if (length > 512) | ||
793 | return RCODE_TYPE_ERROR; | ||
794 | |||
795 | switch (csraddr) { | ||
796 | case CSR_FCP_COMMAND: | ||
797 | highlevel_fcp_request(host, nodeid, 0, (u8 *)data, length); | ||
798 | break; | ||
799 | case CSR_FCP_RESPONSE: | ||
800 | highlevel_fcp_request(host, nodeid, 1, (u8 *)data, length); | ||
801 | break; | ||
802 | default: | ||
803 | return RCODE_TYPE_ERROR; | ||
804 | } | ||
805 | |||
806 | return RCODE_COMPLETE; | ||
807 | } | ||
808 | |||
809 | static int read_config_rom(struct hpsb_host *host, int nodeid, quadlet_t *buffer, | ||
810 | u64 addr, size_t length, u16 fl) | ||
811 | { | ||
812 | u32 offset = addr - CSR1212_REGISTER_SPACE_BASE; | ||
813 | |||
814 | if (csr1212_read(host->csr.rom, offset, buffer, length) == CSR1212_SUCCESS) | ||
815 | return RCODE_COMPLETE; | ||
816 | else | ||
817 | return RCODE_ADDRESS_ERROR; | ||
818 | } | ||
819 | |||
820 | static u64 allocate_addr_range(u64 size, u32 alignment, void *__host) | ||
821 | { | ||
822 | struct hpsb_host *host = (struct hpsb_host*)__host; | ||
823 | |||
824 | return hpsb_allocate_and_register_addrspace(&csr_highlevel, | ||
825 | host, | ||
826 | &config_rom_ops, | ||
827 | size, alignment, | ||
828 | CSR1212_UNITS_SPACE_BASE, | ||
829 | CSR1212_UNITS_SPACE_END); | ||
830 | } | ||
831 | |||
832 | static void release_addr_range(u64 addr, void *__host) | ||
833 | { | ||
834 | struct hpsb_host *host = (struct hpsb_host*)__host; | ||
835 | hpsb_unregister_addrspace(&csr_highlevel, host, addr); | ||
836 | } | ||
837 | |||
838 | |||
839 | int init_csr(void) | ||
840 | { | ||
841 | node_cap = csr1212_new_immediate(CSR1212_KV_ID_NODE_CAPABILITIES, 0x0083c0); | ||
842 | if (!node_cap) { | ||
843 | HPSB_ERR("Failed to allocate memory for Node Capabilties ConfigROM entry!"); | ||
844 | return -ENOMEM; | ||
845 | } | ||
846 | |||
847 | hpsb_register_highlevel(&csr_highlevel); | ||
848 | |||
849 | return 0; | ||
850 | } | ||
851 | |||
852 | void cleanup_csr(void) | ||
853 | { | ||
854 | if (node_cap) | ||
855 | csr1212_release_keyval(node_cap); | ||
856 | hpsb_unregister_highlevel(&csr_highlevel); | ||
857 | } | ||