aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ieee1394/highlevel.c
diff options
context:
space:
mode:
authorStefan Richter <stefanr@s5r6.in-berlin.de>2010-10-09 18:12:20 -0400
committerStefan Richter <stefanr@s5r6.in-berlin.de>2010-10-11 08:48:03 -0400
commit66fa12c571d35e3cd62574c65f1785a460105397 (patch)
treeb4f8de3d5ca827d2b134ed628628a7bff46967ca /drivers/ieee1394/highlevel.c
parent1ef5b816c0eaf84f91106cfc0893069c49e86113 (diff)
ieee1394: remove the old IEEE 1394 driver stack
The drivers - ohci1394 (controller driver) - ieee1394 (core) - dv1394, raw1394, video1394 (userspace ABI) - eth1394, sbp2 (protocol drivers) are replaced by - firewire-ohci (controller driver) - firewire-core (core and userspace ABI) - firewire-net, firewire-sbp2 (protocol drivers) which are more featureful, better performing, and more secure than the older drivers; all with a smaller and more modern code base. The driver firedtv in drivers/media/dvb/firewire/ contains backends to both ieee1394 and firewire-core. Its ieee1394 backend code can be removed in an independent commit; firedtv as-is builds and works fine without ieee1394. The driver pcilynx (an incomplete controller driver) is deleted without replacement since PCILynx cards are extremely rare. Owners of these cards use them with the stand-alone bus sniffer driver nosy instead. The drivers nosy and init_ohci1394_dma which do not interact with either of the two IEEE 1394 stacks are not affected by the ieee1394 subsystem removal. There are still some issues with the newer firewire subsystem compared to the older one: - The rare and quirky controllers ALi M52xx, Apple UniNorth v1, NVIDIA NForce2 are even less well supported by firewire-ohci than by ohci1394. I am looking into the M52xx issue. - The experimental firewire-net is reportedly less stable than its experimental cousin eth1394. - Audio playback of a certain group of audio devices (ones based on DICE chipset with EAP; supported by prerelease FFADO code) does not work yet. This issue is still under investigation. - There were some ieee1394 based out-of-the-mainline drivers. Of them, only lisight, an audio driver for iSight webcams, seems still useful. Work is underway to reimplement it on top of firewire-core. All these remainig issues are minor; they should not stand in the way of overall better user experience of IEEE 1394 on Linux, together with a reduction in support efforts and maintenance burden. The coexistence of two IEEE 1394 kernel driver stacks in the mainline since 2.6.22 shall end now, as announced earlier this year. Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers/ieee1394/highlevel.c')
-rw-r--r--drivers/ieee1394/highlevel.c691
1 files changed, 0 insertions, 691 deletions
diff --git a/drivers/ieee1394/highlevel.c b/drivers/ieee1394/highlevel.c
deleted file mode 100644
index 4bc443546e04..000000000000
--- a/drivers/ieee1394/highlevel.c
+++ /dev/null
@@ -1,691 +0,0 @@
1/*
2 * IEEE 1394 for Linux
3 *
4 * Copyright (C) 1999 Andreas E. Bombe
5 *
6 * This code is licensed under the GPL. See the file COPYING in the root
7 * directory of the kernel sources for details.
8 *
9 *
10 * Contributions:
11 *
12 * Christian Toegel <christian.toegel@gmx.at>
13 * unregister address space
14 *
15 * Manfred Weihs <weihs@ict.tuwien.ac.at>
16 * unregister address space
17 *
18 */
19
20#include <linux/slab.h>
21#include <linux/list.h>
22#include <linux/bitops.h>
23
24#include "ieee1394.h"
25#include "ieee1394_types.h"
26#include "hosts.h"
27#include "ieee1394_core.h"
28#include "highlevel.h"
29#include "nodemgr.h"
30
31
32struct hl_host_info {
33 struct list_head list;
34 struct hpsb_host *host;
35 size_t size;
36 unsigned long key;
37 void *data;
38};
39
40
41static LIST_HEAD(hl_drivers);
42static DECLARE_RWSEM(hl_drivers_sem);
43
44static LIST_HEAD(hl_irqs);
45static DEFINE_RWLOCK(hl_irqs_lock);
46
47static DEFINE_RWLOCK(addr_space_lock);
48
49
50static struct hl_host_info *hl_get_hostinfo(struct hpsb_highlevel *hl,
51 struct hpsb_host *host)
52{
53 struct hl_host_info *hi = NULL;
54
55 if (!hl || !host)
56 return NULL;
57
58 read_lock(&hl->host_info_lock);
59 list_for_each_entry(hi, &hl->host_info_list, list) {
60 if (hi->host == host) {
61 read_unlock(&hl->host_info_lock);
62 return hi;
63 }
64 }
65 read_unlock(&hl->host_info_lock);
66 return NULL;
67}
68
69/**
70 * hpsb_get_hostinfo - retrieve a hostinfo pointer bound to this driver/host
71 *
72 * Returns a per @host and @hl driver data structure that was previously stored
73 * by hpsb_create_hostinfo.
74 */
75void *hpsb_get_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host)
76{
77 struct hl_host_info *hi = hl_get_hostinfo(hl, host);
78
79 return hi ? hi->data : NULL;
80}
81
82/**
83 * hpsb_create_hostinfo - allocate a hostinfo pointer bound to this driver/host
84 *
85 * Allocate a hostinfo pointer backed by memory with @data_size and bind it to
86 * to this @hl driver and @host. If @data_size is zero, then the return here is
87 * only valid for error checking.
88 */
89void *hpsb_create_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
90 size_t data_size)
91{
92 struct hl_host_info *hi;
93 void *data;
94 unsigned long flags;
95
96 hi = hl_get_hostinfo(hl, host);
97 if (hi) {
98 HPSB_ERR("%s called hpsb_create_hostinfo when hostinfo already"
99 " exists", hl->name);
100 return NULL;
101 }
102
103 hi = kzalloc(sizeof(*hi) + data_size, GFP_ATOMIC);
104 if (!hi)
105 return NULL;
106
107 if (data_size) {
108 data = hi->data = hi + 1;
109 hi->size = data_size;
110 } else
111 data = hi;
112
113 hi->host = host;
114
115 write_lock_irqsave(&hl->host_info_lock, flags);
116 list_add_tail(&hi->list, &hl->host_info_list);
117 write_unlock_irqrestore(&hl->host_info_lock, flags);
118
119 return data;
120}
121
122/**
123 * hpsb_set_hostinfo - set the hostinfo pointer to something useful
124 *
125 * Usually follows a call to hpsb_create_hostinfo, where the size is 0.
126 */
127int hpsb_set_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
128 void *data)
129{
130 struct hl_host_info *hi;
131
132 hi = hl_get_hostinfo(hl, host);
133 if (hi) {
134 if (!hi->size && !hi->data) {
135 hi->data = data;
136 return 0;
137 } else
138 HPSB_ERR("%s called hpsb_set_hostinfo when hostinfo "
139 "already has data", hl->name);
140 } else
141 HPSB_ERR("%s called hpsb_set_hostinfo when no hostinfo exists",
142 hl->name);
143 return -EINVAL;
144}
145
146/**
147 * hpsb_destroy_hostinfo - free and remove a hostinfo pointer
148 *
149 * Free and remove the hostinfo pointer bound to this @hl driver and @host.
150 */
151void hpsb_destroy_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host)
152{
153 struct hl_host_info *hi;
154
155 hi = hl_get_hostinfo(hl, host);
156 if (hi) {
157 unsigned long flags;
158 write_lock_irqsave(&hl->host_info_lock, flags);
159 list_del(&hi->list);
160 write_unlock_irqrestore(&hl->host_info_lock, flags);
161 kfree(hi);
162 }
163 return;
164}
165
166/**
167 * hpsb_set_hostinfo_key - set an alternate lookup key for an hostinfo
168 *
169 * Sets an alternate lookup key for the hostinfo bound to this @hl driver and
170 * @host.
171 */
172void hpsb_set_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host,
173 unsigned long key)
174{
175 struct hl_host_info *hi;
176
177 hi = hl_get_hostinfo(hl, host);
178 if (hi)
179 hi->key = key;
180 return;
181}
182
183/**
184 * hpsb_get_hostinfo_bykey - retrieve a hostinfo pointer by its alternate key
185 */
186void *hpsb_get_hostinfo_bykey(struct hpsb_highlevel *hl, unsigned long key)
187{
188 struct hl_host_info *hi;
189 void *data = NULL;
190
191 if (!hl)
192 return NULL;
193
194 read_lock(&hl->host_info_lock);
195 list_for_each_entry(hi, &hl->host_info_list, list) {
196 if (hi->key == key) {
197 data = hi->data;
198 break;
199 }
200 }
201 read_unlock(&hl->host_info_lock);
202 return data;
203}
204
205static int highlevel_for_each_host_reg(struct hpsb_host *host, void *__data)
206{
207 struct hpsb_highlevel *hl = __data;
208
209 hl->add_host(host);
210
211 if (host->update_config_rom && hpsb_update_config_rom_image(host) < 0)
212 HPSB_ERR("Failed to generate Configuration ROM image for host "
213 "%s-%d", hl->name, host->id);
214 return 0;
215}
216
217/**
218 * hpsb_register_highlevel - register highlevel driver
219 *
220 * The name pointer in @hl has to stay valid at all times because the string is
221 * not copied.
222 */
223void hpsb_register_highlevel(struct hpsb_highlevel *hl)
224{
225 unsigned long flags;
226
227 hpsb_init_highlevel(hl);
228 INIT_LIST_HEAD(&hl->addr_list);
229
230 down_write(&hl_drivers_sem);
231 list_add_tail(&hl->hl_list, &hl_drivers);
232 up_write(&hl_drivers_sem);
233
234 write_lock_irqsave(&hl_irqs_lock, flags);
235 list_add_tail(&hl->irq_list, &hl_irqs);
236 write_unlock_irqrestore(&hl_irqs_lock, flags);
237
238 if (hl->add_host)
239 nodemgr_for_each_host(hl, highlevel_for_each_host_reg);
240 return;
241}
242
243static void __delete_addr(struct hpsb_address_serve *as)
244{
245 list_del(&as->host_list);
246 list_del(&as->hl_list);
247 kfree(as);
248}
249
250static void __unregister_host(struct hpsb_highlevel *hl, struct hpsb_host *host,
251 int update_cr)
252{
253 unsigned long flags;
254 struct list_head *lh, *next;
255 struct hpsb_address_serve *as;
256
257 /* First, let the highlevel driver unreg */
258 if (hl->remove_host)
259 hl->remove_host(host);
260
261 /* Remove any addresses that are matched for this highlevel driver
262 * and this particular host. */
263 write_lock_irqsave(&addr_space_lock, flags);
264 list_for_each_safe (lh, next, &hl->addr_list) {
265 as = list_entry(lh, struct hpsb_address_serve, hl_list);
266 if (as->host == host)
267 __delete_addr(as);
268 }
269 write_unlock_irqrestore(&addr_space_lock, flags);
270
271 /* Now update the config-rom to reflect anything removed by the
272 * highlevel driver. */
273 if (update_cr && host->update_config_rom &&
274 hpsb_update_config_rom_image(host) < 0)
275 HPSB_ERR("Failed to generate Configuration ROM image for host "
276 "%s-%d", hl->name, host->id);
277
278 /* Finally remove all the host info associated between these two. */
279 hpsb_destroy_hostinfo(hl, host);
280}
281
282static int highlevel_for_each_host_unreg(struct hpsb_host *host, void *__data)
283{
284 struct hpsb_highlevel *hl = __data;
285
286 __unregister_host(hl, host, 1);
287 return 0;
288}
289
290/**
291 * hpsb_unregister_highlevel - unregister highlevel driver
292 */
293void hpsb_unregister_highlevel(struct hpsb_highlevel *hl)
294{
295 unsigned long flags;
296
297 write_lock_irqsave(&hl_irqs_lock, flags);
298 list_del(&hl->irq_list);
299 write_unlock_irqrestore(&hl_irqs_lock, flags);
300
301 down_write(&hl_drivers_sem);
302 list_del(&hl->hl_list);
303 up_write(&hl_drivers_sem);
304
305 nodemgr_for_each_host(hl, highlevel_for_each_host_unreg);
306}
307
308/**
309 * hpsb_allocate_and_register_addrspace - alloc' and reg' a host address space
310 *
311 * @start and @end are 48 bit pointers and have to be quadlet aligned.
312 * @end points to the first address behind the handled addresses. This
313 * function can be called multiple times for a single hpsb_highlevel @hl to
314 * implement sparse register sets. The requested region must not overlap any
315 * previously allocated region, otherwise registering will fail.
316 *
317 * It returns true for successful allocation. Address spaces can be
318 * unregistered with hpsb_unregister_addrspace. All remaining address spaces
319 * are automatically deallocated together with the hpsb_highlevel @hl.
320 */
321u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl,
322 struct hpsb_host *host,
323 const struct hpsb_address_ops *ops,
324 u64 size, u64 alignment,
325 u64 start, u64 end)
326{
327 struct hpsb_address_serve *as, *a1, *a2;
328 struct list_head *entry;
329 u64 retval = CSR1212_INVALID_ADDR_SPACE;
330 unsigned long flags;
331 u64 align_mask = ~(alignment - 1);
332
333 if ((alignment & 3) || (alignment > 0x800000000000ULL) ||
334 (hweight64(alignment) != 1)) {
335 HPSB_ERR("%s called with invalid alignment: 0x%048llx",
336 __func__, (unsigned long long)alignment);
337 return retval;
338 }
339
340 /* default range,
341 * avoids controller's posted write area (see OHCI 1.1 clause 1.5) */
342 if (start == CSR1212_INVALID_ADDR_SPACE &&
343 end == CSR1212_INVALID_ADDR_SPACE) {
344 start = host->middle_addr_space;
345 end = CSR1212_ALL_SPACE_END;
346 }
347
348 if (((start|end) & ~align_mask) || (start >= end) ||
349 (end > CSR1212_ALL_SPACE_END)) {
350 HPSB_ERR("%s called with invalid addresses "
351 "(start = %012Lx end = %012Lx)", __func__,
352 (unsigned long long)start,(unsigned long long)end);
353 return retval;
354 }
355
356 as = kmalloc(sizeof(*as), GFP_KERNEL);
357 if (!as)
358 return retval;
359
360 INIT_LIST_HEAD(&as->host_list);
361 INIT_LIST_HEAD(&as->hl_list);
362 as->op = ops;
363 as->host = host;
364
365 write_lock_irqsave(&addr_space_lock, flags);
366 list_for_each(entry, &host->addr_space) {
367 u64 a1sa, a1ea;
368 u64 a2sa, a2ea;
369
370 a1 = list_entry(entry, struct hpsb_address_serve, host_list);
371 a2 = list_entry(entry->next, struct hpsb_address_serve,
372 host_list);
373
374 a1sa = a1->start & align_mask;
375 a1ea = (a1->end + alignment -1) & align_mask;
376 a2sa = a2->start & align_mask;
377 a2ea = (a2->end + alignment -1) & align_mask;
378
379 if ((a2sa - a1ea >= size) && (a2sa - start >= size) &&
380 (a2sa > start)) {
381 as->start = max(start, a1ea);
382 as->end = as->start + size;
383 list_add(&as->host_list, entry);
384 list_add_tail(&as->hl_list, &hl->addr_list);
385 retval = as->start;
386 break;
387 }
388 }
389 write_unlock_irqrestore(&addr_space_lock, flags);
390
391 if (retval == CSR1212_INVALID_ADDR_SPACE)
392 kfree(as);
393 return retval;
394}
395
396/**
397 * hpsb_register_addrspace - register a host address space
398 *
399 * @start and @end are 48 bit pointers and have to be quadlet aligned.
400 * @end points to the first address behind the handled addresses. This
401 * function can be called multiple times for a single hpsb_highlevel @hl to
402 * implement sparse register sets. The requested region must not overlap any
403 * previously allocated region, otherwise registering will fail.
404 *
405 * It returns true for successful allocation. Address spaces can be
406 * unregistered with hpsb_unregister_addrspace. All remaining address spaces
407 * are automatically deallocated together with the hpsb_highlevel @hl.
408 */
409int hpsb_register_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
410 const struct hpsb_address_ops *ops,
411 u64 start, u64 end)
412{
413 struct hpsb_address_serve *as;
414 struct list_head *lh;
415 int retval = 0;
416 unsigned long flags;
417
418 if (((start|end) & 3) || (start >= end) ||
419 (end > CSR1212_ALL_SPACE_END)) {
420 HPSB_ERR("%s called with invalid addresses", __func__);
421 return 0;
422 }
423
424 as = kmalloc(sizeof(*as), GFP_KERNEL);
425 if (!as)
426 return 0;
427
428 INIT_LIST_HEAD(&as->host_list);
429 INIT_LIST_HEAD(&as->hl_list);
430 as->op = ops;
431 as->start = start;
432 as->end = end;
433 as->host = host;
434
435 write_lock_irqsave(&addr_space_lock, flags);
436 list_for_each(lh, &host->addr_space) {
437 struct hpsb_address_serve *as_this =
438 list_entry(lh, struct hpsb_address_serve, host_list);
439 struct hpsb_address_serve *as_next =
440 list_entry(lh->next, struct hpsb_address_serve,
441 host_list);
442
443 if (as_this->end > as->start)
444 break;
445
446 if (as_next->start >= as->end) {
447 list_add(&as->host_list, lh);
448 list_add_tail(&as->hl_list, &hl->addr_list);
449 retval = 1;
450 break;
451 }
452 }
453 write_unlock_irqrestore(&addr_space_lock, flags);
454
455 if (retval == 0)
456 kfree(as);
457 return retval;
458}
459
460int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
461 u64 start)
462{
463 int retval = 0;
464 struct hpsb_address_serve *as;
465 struct list_head *lh, *next;
466 unsigned long flags;
467
468 write_lock_irqsave(&addr_space_lock, flags);
469 list_for_each_safe (lh, next, &hl->addr_list) {
470 as = list_entry(lh, struct hpsb_address_serve, hl_list);
471 if (as->start == start && as->host == host) {
472 __delete_addr(as);
473 retval = 1;
474 break;
475 }
476 }
477 write_unlock_irqrestore(&addr_space_lock, flags);
478 return retval;
479}
480
481static const struct hpsb_address_ops dummy_ops;
482
483/* dummy address spaces as lower and upper bounds of the host's a.s. list */
484static void init_hpsb_highlevel(struct hpsb_host *host)
485{
486 INIT_LIST_HEAD(&host->dummy_zero_addr.host_list);
487 INIT_LIST_HEAD(&host->dummy_zero_addr.hl_list);
488 INIT_LIST_HEAD(&host->dummy_max_addr.host_list);
489 INIT_LIST_HEAD(&host->dummy_max_addr.hl_list);
490
491 host->dummy_zero_addr.op = host->dummy_max_addr.op = &dummy_ops;
492
493 host->dummy_zero_addr.start = host->dummy_zero_addr.end = 0;
494 host->dummy_max_addr.start = host->dummy_max_addr.end = ((u64) 1) << 48;
495
496 list_add_tail(&host->dummy_zero_addr.host_list, &host->addr_space);
497 list_add_tail(&host->dummy_max_addr.host_list, &host->addr_space);
498}
499
500void highlevel_add_host(struct hpsb_host *host)
501{
502 struct hpsb_highlevel *hl;
503
504 init_hpsb_highlevel(host);
505
506 down_read(&hl_drivers_sem);
507 list_for_each_entry(hl, &hl_drivers, hl_list) {
508 if (hl->add_host)
509 hl->add_host(host);
510 }
511 up_read(&hl_drivers_sem);
512 if (host->update_config_rom && hpsb_update_config_rom_image(host) < 0)
513 HPSB_ERR("Failed to generate Configuration ROM image for host "
514 "%s-%d", hl->name, host->id);
515}
516
517void highlevel_remove_host(struct hpsb_host *host)
518{
519 struct hpsb_highlevel *hl;
520
521 down_read(&hl_drivers_sem);
522 list_for_each_entry(hl, &hl_drivers, hl_list)
523 __unregister_host(hl, host, 0);
524 up_read(&hl_drivers_sem);
525}
526
527void highlevel_host_reset(struct hpsb_host *host)
528{
529 unsigned long flags;
530 struct hpsb_highlevel *hl;
531
532 read_lock_irqsave(&hl_irqs_lock, flags);
533 list_for_each_entry(hl, &hl_irqs, irq_list) {
534 if (hl->host_reset)
535 hl->host_reset(host);
536 }
537 read_unlock_irqrestore(&hl_irqs_lock, flags);
538}
539
540void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction,
541 void *data, size_t length)
542{
543 unsigned long flags;
544 struct hpsb_highlevel *hl;
545 int cts = ((quadlet_t *)data)[0] >> 4;
546
547 read_lock_irqsave(&hl_irqs_lock, flags);
548 list_for_each_entry(hl, &hl_irqs, irq_list) {
549 if (hl->fcp_request)
550 hl->fcp_request(host, nodeid, direction, cts, data,
551 length);
552 }
553 read_unlock_irqrestore(&hl_irqs_lock, flags);
554}
555
556/*
557 * highlevel_read, highlevel_write, highlevel_lock, highlevel_lock64:
558 *
559 * These functions are called to handle transactions. They are called when a
560 * packet arrives. The flags argument contains the second word of the first
561 * header quadlet of the incoming packet (containing transaction label, retry
562 * code, transaction code and priority). These functions either return a
563 * response code or a negative number. In the first case a response will be
564 * generated. In the latter case, no response will be sent and the driver which
565 * handled the request will send the response itself.
566 */
567int highlevel_read(struct hpsb_host *host, int nodeid, void *data, u64 addr,
568 unsigned int length, u16 flags)
569{
570 struct hpsb_address_serve *as;
571 unsigned int partlength;
572 int rcode = RCODE_ADDRESS_ERROR;
573
574 read_lock(&addr_space_lock);
575 list_for_each_entry(as, &host->addr_space, host_list) {
576 if (as->start > addr)
577 break;
578
579 if (as->end > addr) {
580 partlength = min(as->end - addr, (u64) length);
581
582 if (as->op->read)
583 rcode = as->op->read(host, nodeid, data,
584 addr, partlength, flags);
585 else
586 rcode = RCODE_TYPE_ERROR;
587
588 data += partlength;
589 length -= partlength;
590 addr += partlength;
591
592 if ((rcode != RCODE_COMPLETE) || !length)
593 break;
594 }
595 }
596 read_unlock(&addr_space_lock);
597
598 if (length && (rcode == RCODE_COMPLETE))
599 rcode = RCODE_ADDRESS_ERROR;
600 return rcode;
601}
602
603int highlevel_write(struct hpsb_host *host, int nodeid, int destid, void *data,
604 u64 addr, unsigned int length, u16 flags)
605{
606 struct hpsb_address_serve *as;
607 unsigned int partlength;
608 int rcode = RCODE_ADDRESS_ERROR;
609
610 read_lock(&addr_space_lock);
611 list_for_each_entry(as, &host->addr_space, host_list) {
612 if (as->start > addr)
613 break;
614
615 if (as->end > addr) {
616 partlength = min(as->end - addr, (u64) length);
617
618 if (as->op->write)
619 rcode = as->op->write(host, nodeid, destid,
620 data, addr, partlength,
621 flags);
622 else
623 rcode = RCODE_TYPE_ERROR;
624
625 data += partlength;
626 length -= partlength;
627 addr += partlength;
628
629 if ((rcode != RCODE_COMPLETE) || !length)
630 break;
631 }
632 }
633 read_unlock(&addr_space_lock);
634
635 if (length && (rcode == RCODE_COMPLETE))
636 rcode = RCODE_ADDRESS_ERROR;
637 return rcode;
638}
639
640int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
641 u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode,
642 u16 flags)
643{
644 struct hpsb_address_serve *as;
645 int rcode = RCODE_ADDRESS_ERROR;
646
647 read_lock(&addr_space_lock);
648 list_for_each_entry(as, &host->addr_space, host_list) {
649 if (as->start > addr)
650 break;
651
652 if (as->end > addr) {
653 if (as->op->lock)
654 rcode = as->op->lock(host, nodeid, store, addr,
655 data, arg, ext_tcode,
656 flags);
657 else
658 rcode = RCODE_TYPE_ERROR;
659 break;
660 }
661 }
662 read_unlock(&addr_space_lock);
663 return rcode;
664}
665
666int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
667 u64 addr, octlet_t data, octlet_t arg, int ext_tcode,
668 u16 flags)
669{
670 struct hpsb_address_serve *as;
671 int rcode = RCODE_ADDRESS_ERROR;
672
673 read_lock(&addr_space_lock);
674
675 list_for_each_entry(as, &host->addr_space, host_list) {
676 if (as->start > addr)
677 break;
678
679 if (as->end > addr) {
680 if (as->op->lock64)
681 rcode = as->op->lock64(host, nodeid, store,
682 addr, data, arg,
683 ext_tcode, flags);
684 else
685 rcode = RCODE_TYPE_ERROR;
686 break;
687 }
688 }
689 read_unlock(&addr_space_lock);
690 return rcode;
691}