OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [ieee1394/] [highlevel.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
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
 
32
struct 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
 
41
static LIST_HEAD(hl_drivers);
42
static DECLARE_RWSEM(hl_drivers_sem);
43
 
44
static LIST_HEAD(hl_irqs);
45
static DEFINE_RWLOCK(hl_irqs_lock);
46
 
47
static DEFINE_RWLOCK(addr_space_lock);
48
 
49
/* addr_space list will have zero and max already included as bounds */
50
static struct hpsb_address_ops dummy_ops = { NULL, NULL, NULL, NULL };
51
static struct hpsb_address_serve dummy_zero_addr, dummy_max_addr;
52
 
53
 
54
static struct hl_host_info *hl_get_hostinfo(struct hpsb_highlevel *hl,
55
                                            struct hpsb_host *host)
56
{
57
        struct hl_host_info *hi = NULL;
58
 
59
        if (!hl || !host)
60
                return NULL;
61
 
62
        read_lock(&hl->host_info_lock);
63
        list_for_each_entry(hi, &hl->host_info_list, list) {
64
                if (hi->host == host) {
65
                        read_unlock(&hl->host_info_lock);
66
                        return hi;
67
                }
68
        }
69
        read_unlock(&hl->host_info_lock);
70
        return NULL;
71
}
72
 
73
/**
74
 * hpsb_get_hostinfo - retrieve a hostinfo pointer bound to this driver/host
75
 *
76
 * Returns a per @host and @hl driver data structure that was previously stored
77
 * by hpsb_create_hostinfo.
78
 */
79
void *hpsb_get_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host)
80
{
81
        struct hl_host_info *hi = hl_get_hostinfo(hl, host);
82
 
83
        return hi ? hi->data : NULL;
84
}
85
 
86
/**
87
 * hpsb_create_hostinfo - allocate a hostinfo pointer bound to this driver/host
88
 *
89
 * Allocate a hostinfo pointer backed by memory with @data_size and bind it to
90
 * to this @hl driver and @host.  If @data_size is zero, then the return here is
91
 * only valid for error checking.
92
 */
93
void *hpsb_create_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
94
                           size_t data_size)
95
{
96
        struct hl_host_info *hi;
97
        void *data;
98
        unsigned long flags;
99
 
100
        hi = hl_get_hostinfo(hl, host);
101
        if (hi) {
102
                HPSB_ERR("%s called hpsb_create_hostinfo when hostinfo already"
103
                         " exists", hl->name);
104
                return NULL;
105
        }
106
 
107
        hi = kzalloc(sizeof(*hi) + data_size, GFP_ATOMIC);
108
        if (!hi)
109
                return NULL;
110
 
111
        if (data_size) {
112
                data = hi->data = hi + 1;
113
                hi->size = data_size;
114
        } else
115
                data = hi;
116
 
117
        hi->host = host;
118
 
119
        write_lock_irqsave(&hl->host_info_lock, flags);
120
        list_add_tail(&hi->list, &hl->host_info_list);
121
        write_unlock_irqrestore(&hl->host_info_lock, flags);
122
 
123
        return data;
124
}
125
 
126
/**
127
 * hpsb_set_hostinfo - set the hostinfo pointer to something useful
128
 *
129
 * Usually follows a call to hpsb_create_hostinfo, where the size is 0.
130
 */
131
int hpsb_set_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
132
                      void *data)
133
{
134
        struct hl_host_info *hi;
135
 
136
        hi = hl_get_hostinfo(hl, host);
137
        if (hi) {
138
                if (!hi->size && !hi->data) {
139
                        hi->data = data;
140
                        return 0;
141
                } else
142
                        HPSB_ERR("%s called hpsb_set_hostinfo when hostinfo "
143
                                 "already has data", hl->name);
144
        } else
145
                HPSB_ERR("%s called hpsb_set_hostinfo when no hostinfo exists",
146
                         hl->name);
147
        return -EINVAL;
148
}
149
 
150
/**
151
 * hpsb_destroy_hostinfo - free and remove a hostinfo pointer
152
 *
153
 * Free and remove the hostinfo pointer bound to this @hl driver and @host.
154
 */
155
void hpsb_destroy_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host)
156
{
157
        struct hl_host_info *hi;
158
 
159
        hi = hl_get_hostinfo(hl, host);
160
        if (hi) {
161
                unsigned long flags;
162
                write_lock_irqsave(&hl->host_info_lock, flags);
163
                list_del(&hi->list);
164
                write_unlock_irqrestore(&hl->host_info_lock, flags);
165
                kfree(hi);
166
        }
167
        return;
168
}
169
 
170
/**
171
 * hpsb_set_hostinfo_key - set an alternate lookup key for an hostinfo
172
 *
173
 * Sets an alternate lookup key for the hostinfo bound to this @hl driver and
174
 * @host.
175
 */
176
void hpsb_set_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host,
177
                           unsigned long key)
178
{
179
        struct hl_host_info *hi;
180
 
181
        hi = hl_get_hostinfo(hl, host);
182
        if (hi)
183
                hi->key = key;
184
        return;
185
}
186
 
187
/**
188
 * hpsb_get_hostinfo_bykey - retrieve a hostinfo pointer by its alternate key
189
 */
190
void *hpsb_get_hostinfo_bykey(struct hpsb_highlevel *hl, unsigned long key)
191
{
192
        struct hl_host_info *hi;
193
        void *data = NULL;
194
 
195
        if (!hl)
196
                return NULL;
197
 
198
        read_lock(&hl->host_info_lock);
199
        list_for_each_entry(hi, &hl->host_info_list, list) {
200
                if (hi->key == key) {
201
                        data = hi->data;
202
                        break;
203
                }
204
        }
205
        read_unlock(&hl->host_info_lock);
206
        return data;
207
}
208
 
209
static int highlevel_for_each_host_reg(struct hpsb_host *host, void *__data)
210
{
211
        struct hpsb_highlevel *hl = __data;
212
 
213
        hl->add_host(host);
214
 
215
        if (host->update_config_rom && hpsb_update_config_rom_image(host) < 0)
216
                HPSB_ERR("Failed to generate Configuration ROM image for host "
217
                         "%s-%d", hl->name, host->id);
218
        return 0;
219
}
220
 
221
/**
222
 * hpsb_register_highlevel - register highlevel driver
223
 *
224
 * The name pointer in @hl has to stay valid at all times because the string is
225
 * not copied.
226
 */
227
void hpsb_register_highlevel(struct hpsb_highlevel *hl)
228
{
229
        unsigned long flags;
230
 
231
        INIT_LIST_HEAD(&hl->addr_list);
232
        INIT_LIST_HEAD(&hl->host_info_list);
233
 
234
        rwlock_init(&hl->host_info_lock);
235
 
236
        down_write(&hl_drivers_sem);
237
        list_add_tail(&hl->hl_list, &hl_drivers);
238
        up_write(&hl_drivers_sem);
239
 
240
        write_lock_irqsave(&hl_irqs_lock, flags);
241
        list_add_tail(&hl->irq_list, &hl_irqs);
242
        write_unlock_irqrestore(&hl_irqs_lock, flags);
243
 
244
        if (hl->add_host)
245
                nodemgr_for_each_host(hl, highlevel_for_each_host_reg);
246
        return;
247
}
248
 
249
static void __delete_addr(struct hpsb_address_serve *as)
250
{
251
        list_del(&as->host_list);
252
        list_del(&as->hl_list);
253
        kfree(as);
254
}
255
 
256
static void __unregister_host(struct hpsb_highlevel *hl, struct hpsb_host *host,
257
                              int update_cr)
258
{
259
        unsigned long flags;
260
        struct list_head *lh, *next;
261
        struct hpsb_address_serve *as;
262
 
263
        /* First, let the highlevel driver unreg */
264
        if (hl->remove_host)
265
                hl->remove_host(host);
266
 
267
        /* Remove any addresses that are matched for this highlevel driver
268
         * and this particular host. */
269
        write_lock_irqsave(&addr_space_lock, flags);
270
        list_for_each_safe (lh, next, &hl->addr_list) {
271
                as = list_entry(lh, struct hpsb_address_serve, hl_list);
272
                if (as->host == host)
273
                        __delete_addr(as);
274
        }
275
        write_unlock_irqrestore(&addr_space_lock, flags);
276
 
277
        /* Now update the config-rom to reflect anything removed by the
278
         * highlevel driver. */
279
        if (update_cr && host->update_config_rom &&
280
            hpsb_update_config_rom_image(host) < 0)
281
                HPSB_ERR("Failed to generate Configuration ROM image for host "
282
                         "%s-%d", hl->name, host->id);
283
 
284
        /* Finally remove all the host info associated between these two. */
285
        hpsb_destroy_hostinfo(hl, host);
286
}
287
 
288
static int highlevel_for_each_host_unreg(struct hpsb_host *host, void *__data)
289
{
290
        struct hpsb_highlevel *hl = __data;
291
 
292
        __unregister_host(hl, host, 1);
293
        return 0;
294
}
295
 
296
/**
297
 * hpsb_unregister_highlevel - unregister highlevel driver
298
 */
299
void hpsb_unregister_highlevel(struct hpsb_highlevel *hl)
300
{
301
        unsigned long flags;
302
 
303
        write_lock_irqsave(&hl_irqs_lock, flags);
304
        list_del(&hl->irq_list);
305
        write_unlock_irqrestore(&hl_irqs_lock, flags);
306
 
307
        down_write(&hl_drivers_sem);
308
        list_del(&hl->hl_list);
309
        up_write(&hl_drivers_sem);
310
 
311
        nodemgr_for_each_host(hl, highlevel_for_each_host_unreg);
312
}
313
 
314
/**
315
 * hpsb_allocate_and_register_addrspace - alloc' and reg' a host address space
316
 *
317
 * @start and @end are 48 bit pointers and have to be quadlet aligned.
318
 * @end points to the first address behind the handled addresses.  This
319
 * function can be called multiple times for a single hpsb_highlevel @hl to
320
 * implement sparse register sets.  The requested region must not overlap any
321
 * previously allocated region, otherwise registering will fail.
322
 *
323
 * It returns true for successful allocation.  Address spaces can be
324
 * unregistered with hpsb_unregister_addrspace.  All remaining address spaces
325
 * are automatically deallocated together with the hpsb_highlevel @hl.
326
 */
327
u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl,
328
                                         struct hpsb_host *host,
329
                                         struct hpsb_address_ops *ops,
330
                                         u64 size, u64 alignment,
331
                                         u64 start, u64 end)
332
{
333
        struct hpsb_address_serve *as, *a1, *a2;
334
        struct list_head *entry;
335
        u64 retval = CSR1212_INVALID_ADDR_SPACE;
336
        unsigned long flags;
337
        u64 align_mask = ~(alignment - 1);
338
 
339
        if ((alignment & 3) || (alignment > 0x800000000000ULL) ||
340
            (hweight64(alignment) != 1)) {
341
                HPSB_ERR("%s called with invalid alignment: 0x%048llx",
342
                         __FUNCTION__, (unsigned long long)alignment);
343
                return retval;
344
        }
345
 
346
        /* default range,
347
         * avoids controller's posted write area (see OHCI 1.1 clause 1.5) */
348
        if (start == CSR1212_INVALID_ADDR_SPACE &&
349
            end   == CSR1212_INVALID_ADDR_SPACE) {
350
                start = host->middle_addr_space;
351
                end   = CSR1212_ALL_SPACE_END;
352
        }
353
 
354
        if (((start|end) & ~align_mask) || (start >= end) ||
355
            (end > CSR1212_ALL_SPACE_END)) {
356
                HPSB_ERR("%s called with invalid addresses "
357
                         "(start = %012Lx  end = %012Lx)", __FUNCTION__,
358
                         (unsigned long long)start,(unsigned long long)end);
359
                return retval;
360
        }
361
 
362
        as = kmalloc(sizeof(*as), GFP_KERNEL);
363
        if (!as)
364
                return retval;
365
 
366
        INIT_LIST_HEAD(&as->host_list);
367
        INIT_LIST_HEAD(&as->hl_list);
368
        as->op = ops;
369
        as->host = host;
370
 
371
        write_lock_irqsave(&addr_space_lock, flags);
372
        list_for_each(entry, &host->addr_space) {
373
                u64 a1sa, a1ea;
374
                u64 a2sa, a2ea;
375
 
376
                a1 = list_entry(entry, struct hpsb_address_serve, host_list);
377
                a2 = list_entry(entry->next, struct hpsb_address_serve,
378
                                host_list);
379
 
380
                a1sa = a1->start & align_mask;
381
                a1ea = (a1->end + alignment -1) & align_mask;
382
                a2sa = a2->start & align_mask;
383
                a2ea = (a2->end + alignment -1) & align_mask;
384
 
385
                if ((a2sa - a1ea >= size) && (a2sa - start >= size) &&
386
                    (a2sa > start)) {
387
                        as->start = max(start, a1ea);
388
                        as->end = as->start + size;
389
                        list_add(&as->host_list, entry);
390
                        list_add_tail(&as->hl_list, &hl->addr_list);
391
                        retval = as->start;
392
                        break;
393
                }
394
        }
395
        write_unlock_irqrestore(&addr_space_lock, flags);
396
 
397
        if (retval == CSR1212_INVALID_ADDR_SPACE)
398
                kfree(as);
399
        return retval;
400
}
401
 
402
/**
403
 * hpsb_register_addrspace - register a host address space
404
 *
405
 * @start and @end are 48 bit pointers and have to be quadlet aligned.
406
 * @end points to the first address behind the handled addresses.  This
407
 * function can be called multiple times for a single hpsb_highlevel @hl to
408
 * implement sparse register sets.  The requested region must not overlap any
409
 * previously allocated region, otherwise registering will fail.
410
 *
411
 * It returns true for successful allocation.  Address spaces can be
412
 * unregistered with hpsb_unregister_addrspace.  All remaining address spaces
413
 * are automatically deallocated together with the hpsb_highlevel @hl.
414
 */
415
int hpsb_register_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
416
                            struct hpsb_address_ops *ops, u64 start, u64 end)
417
{
418
        struct hpsb_address_serve *as;
419
        struct list_head *lh;
420
        int retval = 0;
421
        unsigned long flags;
422
 
423
        if (((start|end) & 3) || (start >= end) ||
424
            (end > CSR1212_ALL_SPACE_END)) {
425
                HPSB_ERR("%s called with invalid addresses", __FUNCTION__);
426
                return 0;
427
        }
428
 
429
        as = kmalloc(sizeof(*as), GFP_ATOMIC);
430
        if (!as)
431
                return 0;
432
 
433
        INIT_LIST_HEAD(&as->host_list);
434
        INIT_LIST_HEAD(&as->hl_list);
435
        as->op = ops;
436
        as->start = start;
437
        as->end = end;
438
        as->host = host;
439
 
440
        write_lock_irqsave(&addr_space_lock, flags);
441
        list_for_each(lh, &host->addr_space) {
442
                struct hpsb_address_serve *as_this =
443
                        list_entry(lh, struct hpsb_address_serve, host_list);
444
                struct hpsb_address_serve *as_next =
445
                        list_entry(lh->next, struct hpsb_address_serve,
446
                                   host_list);
447
 
448
                if (as_this->end > as->start)
449
                        break;
450
 
451
                if (as_next->start >= as->end) {
452
                        list_add(&as->host_list, lh);
453
                        list_add_tail(&as->hl_list, &hl->addr_list);
454
                        retval = 1;
455
                        break;
456
                }
457
        }
458
        write_unlock_irqrestore(&addr_space_lock, flags);
459
 
460
        if (retval == 0)
461
                kfree(as);
462
        return retval;
463
}
464
 
465
int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
466
                              u64 start)
467
{
468
        int retval = 0;
469
        struct hpsb_address_serve *as;
470
        struct list_head *lh, *next;
471
        unsigned long flags;
472
 
473
        write_lock_irqsave(&addr_space_lock, flags);
474
        list_for_each_safe (lh, next, &hl->addr_list) {
475
                as = list_entry(lh, struct hpsb_address_serve, hl_list);
476
                if (as->start == start && as->host == host) {
477
                        __delete_addr(as);
478
                        retval = 1;
479
                        break;
480
                }
481
        }
482
        write_unlock_irqrestore(&addr_space_lock, flags);
483
        return retval;
484
}
485
 
486
static void init_hpsb_highlevel(struct hpsb_host *host)
487
{
488
        INIT_LIST_HEAD(&dummy_zero_addr.host_list);
489
        INIT_LIST_HEAD(&dummy_zero_addr.hl_list);
490
        INIT_LIST_HEAD(&dummy_max_addr.host_list);
491
        INIT_LIST_HEAD(&dummy_max_addr.hl_list);
492
 
493
        dummy_zero_addr.op = dummy_max_addr.op = &dummy_ops;
494
 
495
        dummy_zero_addr.start = dummy_zero_addr.end = 0;
496
        dummy_max_addr.start = dummy_max_addr.end = ((u64) 1) << 48;
497
 
498
        list_add_tail(&dummy_zero_addr.host_list, &host->addr_space);
499
        list_add_tail(&dummy_max_addr.host_list, &host->addr_space);
500
}
501
 
502
void highlevel_add_host(struct hpsb_host *host)
503
{
504
        struct hpsb_highlevel *hl;
505
 
506
        init_hpsb_highlevel(host);
507
 
508
        down_read(&hl_drivers_sem);
509
        list_for_each_entry(hl, &hl_drivers, hl_list) {
510
                if (hl->add_host)
511
                        hl->add_host(host);
512
        }
513
        up_read(&hl_drivers_sem);
514
        if (host->update_config_rom && hpsb_update_config_rom_image(host) < 0)
515
                HPSB_ERR("Failed to generate Configuration ROM image for host "
516
                         "%s-%d", hl->name, host->id);
517
}
518
 
519
void highlevel_remove_host(struct hpsb_host *host)
520
{
521
        struct hpsb_highlevel *hl;
522
 
523
        down_read(&hl_drivers_sem);
524
        list_for_each_entry(hl, &hl_drivers, hl_list)
525
                __unregister_host(hl, host, 0);
526
        up_read(&hl_drivers_sem);
527
}
528
 
529
void highlevel_host_reset(struct hpsb_host *host)
530
{
531
        unsigned long flags;
532
        struct hpsb_highlevel *hl;
533
 
534
        read_lock_irqsave(&hl_irqs_lock, flags);
535
        list_for_each_entry(hl, &hl_irqs, irq_list) {
536
                if (hl->host_reset)
537
                        hl->host_reset(host);
538
        }
539
        read_unlock_irqrestore(&hl_irqs_lock, flags);
540
}
541
 
542
void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction,
543
                           void *data, size_t length)
544
{
545
        unsigned long flags;
546
        struct hpsb_highlevel *hl;
547
        int cts = ((quadlet_t *)data)[0] >> 4;
548
 
549
        read_lock_irqsave(&hl_irqs_lock, flags);
550
        list_for_each_entry(hl, &hl_irqs, irq_list) {
551
                if (hl->fcp_request)
552
                        hl->fcp_request(host, nodeid, direction, cts, data,
553
                                        length);
554
        }
555
        read_unlock_irqrestore(&hl_irqs_lock, flags);
556
}
557
 
558
/*
559
 * highlevel_read, highlevel_write, highlevel_lock, highlevel_lock64:
560
 *
561
 * These functions are called to handle transactions. They are called when a
562
 * packet arrives.  The flags argument contains the second word of the first
563
 * header quadlet of the incoming packet (containing transaction label, retry
564
 * code, transaction code and priority).  These functions either return a
565
 * response code or a negative number.  In the first case a response will be
566
 * generated.  In the latter case, no response will be sent and the driver which
567
 * handled the request will send the response itself.
568
 */
569
int highlevel_read(struct hpsb_host *host, int nodeid, void *data, u64 addr,
570
                   unsigned int length, u16 flags)
571
{
572
        struct hpsb_address_serve *as;
573
        unsigned int partlength;
574
        int rcode = RCODE_ADDRESS_ERROR;
575
 
576
        read_lock(&addr_space_lock);
577
        list_for_each_entry(as, &host->addr_space, host_list) {
578
                if (as->start > addr)
579
                        break;
580
 
581
                if (as->end > addr) {
582
                        partlength = min(as->end - addr, (u64) length);
583
 
584
                        if (as->op->read)
585
                                rcode = as->op->read(host, nodeid, data,
586
                                                     addr, partlength, flags);
587
                        else
588
                                rcode = RCODE_TYPE_ERROR;
589
 
590
                        data += partlength;
591
                        length -= partlength;
592
                        addr += partlength;
593
 
594
                        if ((rcode != RCODE_COMPLETE) || !length)
595
                                break;
596
                }
597
        }
598
        read_unlock(&addr_space_lock);
599
 
600
        if (length && (rcode == RCODE_COMPLETE))
601
                rcode = RCODE_ADDRESS_ERROR;
602
        return rcode;
603
}
604
 
605
int highlevel_write(struct hpsb_host *host, int nodeid, int destid, void *data,
606
                    u64 addr, unsigned int length, u16 flags)
607
{
608
        struct hpsb_address_serve *as;
609
        unsigned int partlength;
610
        int rcode = RCODE_ADDRESS_ERROR;
611
 
612
        read_lock(&addr_space_lock);
613
        list_for_each_entry(as, &host->addr_space, host_list) {
614
                if (as->start > addr)
615
                        break;
616
 
617
                if (as->end > addr) {
618
                        partlength = min(as->end - addr, (u64) length);
619
 
620
                        if (as->op->write)
621
                                rcode = as->op->write(host, nodeid, destid,
622
                                                      data, addr, partlength,
623
                                                      flags);
624
                        else
625
                                rcode = RCODE_TYPE_ERROR;
626
 
627
                        data += partlength;
628
                        length -= partlength;
629
                        addr += partlength;
630
 
631
                        if ((rcode != RCODE_COMPLETE) || !length)
632
                                break;
633
                }
634
        }
635
        read_unlock(&addr_space_lock);
636
 
637
        if (length && (rcode == RCODE_COMPLETE))
638
                rcode = RCODE_ADDRESS_ERROR;
639
        return rcode;
640
}
641
 
642
int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
643
                   u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode,
644
                   u16 flags)
645
{
646
        struct hpsb_address_serve *as;
647
        int rcode = RCODE_ADDRESS_ERROR;
648
 
649
        read_lock(&addr_space_lock);
650
        list_for_each_entry(as, &host->addr_space, host_list) {
651
                if (as->start > addr)
652
                        break;
653
 
654
                if (as->end > addr) {
655
                        if (as->op->lock)
656
                                rcode = as->op->lock(host, nodeid, store, addr,
657
                                                     data, arg, ext_tcode,
658
                                                     flags);
659
                        else
660
                                rcode = RCODE_TYPE_ERROR;
661
                        break;
662
                }
663
        }
664
        read_unlock(&addr_space_lock);
665
        return rcode;
666
}
667
 
668
int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
669
                     u64 addr, octlet_t data, octlet_t arg, int ext_tcode,
670
                     u16 flags)
671
{
672
        struct hpsb_address_serve *as;
673
        int rcode = RCODE_ADDRESS_ERROR;
674
 
675
        read_lock(&addr_space_lock);
676
 
677
        list_for_each_entry(as, &host->addr_space, host_list) {
678
                if (as->start > addr)
679
                        break;
680
 
681
                if (as->end > addr) {
682
                        if (as->op->lock64)
683
                                rcode = as->op->lock64(host, nodeid, store,
684
                                                       addr, data, arg,
685
                                                       ext_tcode, flags);
686
                        else
687
                                rcode = RCODE_TYPE_ERROR;
688
                        break;
689
                }
690
        }
691
        read_unlock(&addr_space_lock);
692
        return rcode;
693
}

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.