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