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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [ieee1394/] [highlevel.c] - Blame information for rev 1275

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
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/config.h>
21
#include <linux/slab.h>
22
#include <linux/list.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
 
30
 
31
struct hl_host_info {
32
        struct list_head list;
33
        struct hpsb_host *host;
34
        size_t size;
35
        unsigned long key;
36
        void *data;
37
};
38
 
39
 
40
static LIST_HEAD(hl_drivers);
41
static rwlock_t hl_drivers_lock = RW_LOCK_UNLOCKED;
42
 
43
static LIST_HEAD(addr_space);
44
static rwlock_t addr_space_lock = RW_LOCK_UNLOCKED;
45
 
46
/* addr_space list will have zero and max already included as bounds */
47
static struct hpsb_address_ops dummy_ops = { NULL, NULL, NULL, NULL };
48
static struct hpsb_address_serve dummy_zero_addr, dummy_max_addr;
49
 
50
 
51
static struct hl_host_info *hl_get_hostinfo(struct hpsb_highlevel *hl,
52
                                              struct hpsb_host *host)
53
{
54
        struct hl_host_info *hi = NULL;
55
        struct list_head *lh;
56
 
57
        if (!hl || !host)
58
                return NULL;
59
 
60
        read_lock(&hl->host_info_lock);
61
        list_for_each (lh, &hl->host_info_list) {
62
                hi = list_entry(lh, struct hl_host_info, list);
63
                if (hi->host == host)
64
                        break;
65
                hi = NULL;
66
        }
67
        read_unlock(&hl->host_info_lock);
68
 
69
        return hi;
70
}
71
 
72
 
73
/* Returns a per host/driver data structure that was previously stored by
74
 * hpsb_create_hostinfo. */
75
void *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
        if (hi)
80
                return hi->data;
81
 
82
        return NULL;
83
}
84
 
85
 
86
/* If size is zero, then the return here is only valid for error checking */
87
void *hpsb_create_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
88
                           size_t data_size)
89
{
90
        struct hl_host_info *hi;
91
        void *data;
92
        unsigned long flags;
93
 
94
        hi = hl_get_hostinfo(hl, host);
95
        if (hi) {
96
                HPSB_ERR("%s called hpsb_create_hostinfo when hostinfo already exists",
97
                         hl->name);
98
                return NULL;
99
        }
100
 
101
        hi = kmalloc(sizeof(*hi) + data_size, GFP_KERNEL);
102
        if (!hi)
103
                return NULL;
104
 
105
        memset(hi, 0, sizeof(*hi) + data_size);
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
int hpsb_set_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
124
                      void *data)
125
{
126
        struct hl_host_info *hi;
127
 
128
        hi = hl_get_hostinfo(hl, host);
129
        if (hi) {
130
                if (!hi->size && !hi->data) {
131
                        hi->data = data;
132
                        return 0;
133
                } else
134
                        HPSB_ERR("%s called hpsb_set_hostinfo when hostinfo already has data",
135
                                 hl->name);
136
        } else
137
                HPSB_ERR("%s called hpsb_set_hostinfo when no hostinfo exists",
138
                         hl->name);
139
 
140
        return -EINVAL;
141
}
142
 
143
 
144
void hpsb_destroy_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host)
145
{
146
        struct hl_host_info *hi;
147
 
148
        hi = hl_get_hostinfo(hl, host);
149
        if (hi) {
150
                unsigned long flags;
151
                write_lock_irqsave(&hl->host_info_lock, flags);
152
                list_del(&hi->list);
153
                write_unlock_irqrestore(&hl->host_info_lock, flags);
154
                kfree(hi);
155
        }
156
 
157
        return;
158
}
159
 
160
 
161
void hpsb_set_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host, unsigned long key)
162
{
163
        struct hl_host_info *hi;
164
 
165
        hi = hl_get_hostinfo(hl, host);
166
        if (hi)
167
                hi->key = key;
168
 
169
        return;
170
}
171
 
172
 
173
unsigned long hpsb_get_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host)
174
{
175
        struct hl_host_info *hi;
176
 
177
        hi = hl_get_hostinfo(hl, host);
178
        if (hi)
179
                return hi->key;
180
 
181
        return 0;
182
}
183
 
184
 
185
void *hpsb_get_hostinfo_bykey(struct hpsb_highlevel *hl, unsigned long key)
186
{
187
        struct list_head *lh;
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 (lh, &hl->host_info_list) {
196
                hi = list_entry(lh, struct hl_host_info, list);
197
                if (hi->key == key) {
198
                        data = hi->data;
199
                        break;
200
                }
201
        }
202
        read_unlock(&hl->host_info_lock);
203
 
204
        return data;
205
}
206
 
207
 
208
struct hpsb_host *hpsb_get_host_bykey(struct hpsb_highlevel *hl, unsigned long key)
209
{
210
        struct list_head *lh;
211
        struct hl_host_info *hi;
212
        struct hpsb_host *host = NULL;
213
 
214
        if (!hl)
215
                return NULL;
216
 
217
        read_lock(&hl->host_info_lock);
218
        list_for_each (lh, &hl->host_info_list) {
219
                hi = list_entry(lh, struct hl_host_info, list);
220
                if (hi->key == key) {
221
                        host = hi->host;
222
                        break;
223
                }
224
        }
225
        read_unlock(&hl->host_info_lock);
226
 
227
        return host;
228
}
229
 
230
 
231
void hpsb_register_highlevel(struct hpsb_highlevel *hl)
232
{
233
        struct list_head *lh;
234
        unsigned long flags;
235
 
236
        INIT_LIST_HEAD(&hl->addr_list);
237
        INIT_LIST_HEAD(&hl->host_info_list);
238
 
239
        rwlock_init(&hl->host_info_lock);
240
 
241
        write_lock_irqsave(&hl_drivers_lock, flags);
242
        list_add_tail(&hl->hl_list, &hl_drivers);
243
        write_unlock_irqrestore(&hl_drivers_lock, flags);
244
 
245
        if (hl->add_host) {
246
                down(&hpsb_hosts_lock);
247
                list_for_each (lh, &hpsb_hosts) {
248
                        struct hpsb_host *host = list_entry(lh, struct hpsb_host, host_list);
249
                        hl->add_host(host);
250
                }
251
                up(&hpsb_hosts_lock);
252
        }
253
 
254
        return;
255
}
256
 
257
void hpsb_unregister_highlevel(struct hpsb_highlevel *hl)
258
{
259
        struct list_head *lh, *next;
260
        struct hpsb_address_serve *as;
261
        unsigned long flags;
262
 
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, addr_list);
266
                list_del(&as->as_list);
267
                kfree(as);
268
        }
269
        write_unlock_irqrestore(&addr_space_lock, flags);
270
 
271
        write_lock_irqsave(&hl_drivers_lock, flags);
272
        list_del(&hl->hl_list);
273
        write_unlock_irqrestore(&hl_drivers_lock, flags);
274
 
275
        if (hl->remove_host) {
276
                down(&hpsb_hosts_lock);
277
                list_for_each(lh, &hpsb_hosts) {
278
                        struct hpsb_host *host = list_entry(lh, struct hpsb_host, host_list);
279
 
280
                        hl->remove_host(host);
281
                        hpsb_destroy_hostinfo(hl, host);
282
                }
283
                up(&hpsb_hosts_lock);
284
        }
285
}
286
 
287
int hpsb_register_addrspace(struct hpsb_highlevel *hl,
288
                            struct hpsb_address_ops *ops, u64 start, u64 end)
289
{
290
        struct hpsb_address_serve *as;
291
        struct list_head *entry;
292
        int retval = 0;
293
        unsigned long flags;
294
 
295
        if (((start|end) & 3) || (start >= end) || (end > 0x1000000000000ULL)) {
296
                HPSB_ERR("%s called with invalid addresses", __FUNCTION__);
297
                return 0;
298
        }
299
 
300
        as = (struct hpsb_address_serve *)
301
                kmalloc(sizeof(struct hpsb_address_serve), GFP_KERNEL);
302
        if (as == NULL) {
303
                return 0;
304
        }
305
 
306
        INIT_LIST_HEAD(&as->as_list);
307
        INIT_LIST_HEAD(&as->addr_list);
308
        as->op = ops;
309
        as->start = start;
310
        as->end = end;
311
 
312
        write_lock_irqsave(&addr_space_lock, flags);
313
        entry = addr_space.next;
314
 
315
        while (list_entry(entry, struct hpsb_address_serve, as_list)->end
316
               <= start) {
317
                if (list_entry(entry->next, struct hpsb_address_serve, as_list)
318
                    ->start >= end) {
319
                        list_add(&as->as_list, entry);
320
                        list_add_tail(&as->addr_list, &hl->addr_list);
321
                        retval = 1;
322
                        break;
323
                }
324
                entry = entry->next;
325
        }
326
        write_unlock_irqrestore(&addr_space_lock, flags);
327
 
328
        if (retval == 0) {
329
                kfree(as);
330
        }
331
 
332
        return retval;
333
}
334
 
335
int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, u64 start)
336
{
337
        int retval = 0;
338
        struct hpsb_address_serve *as;
339
        struct list_head *entry;
340
        unsigned long flags;
341
 
342
        write_lock_irqsave(&addr_space_lock, flags);
343
 
344
        entry = hl->addr_list.next;
345
 
346
        while (entry != &hl->addr_list) {
347
                as = list_entry(entry, struct hpsb_address_serve, addr_list);
348
                entry = entry->next;
349
                if (as->start == start) {
350
                        list_del(&as->as_list);
351
                        list_del(&as->addr_list);
352
                        kfree(as);
353
                        retval = 1;
354
                        break;
355
                }
356
        }
357
 
358
        write_unlock_irqrestore(&addr_space_lock, flags);
359
 
360
        return retval;
361
}
362
 
363
int hpsb_listen_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
364
                         unsigned int channel)
365
{
366
        if (channel > 63) {
367
                HPSB_ERR("%s called with invalid channel", __FUNCTION__);
368
                return -EINVAL;
369
        }
370
 
371
        if (host->iso_listen_count[channel]++ == 0) {
372
                return host->driver->devctl(host, ISO_LISTEN_CHANNEL, channel);
373
        }
374
 
375
        return 0;
376
}
377
 
378
void hpsb_unlisten_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
379
                           unsigned int channel)
380
{
381
        if (channel > 63) {
382
                HPSB_ERR("%s called with invalid channel", __FUNCTION__);
383
                return;
384
        }
385
 
386
        if (--host->iso_listen_count[channel] == 0) {
387
                host->driver->devctl(host, ISO_UNLISTEN_CHANNEL, channel);
388
        }
389
}
390
 
391
 
392
void highlevel_add_host(struct hpsb_host *host)
393
{
394
        struct list_head *entry;
395
        struct hpsb_highlevel *hl;
396
 
397
        read_lock(&hl_drivers_lock);
398
        list_for_each(entry, &hl_drivers) {
399
                hl = list_entry(entry, struct hpsb_highlevel, hl_list);
400
                if (hl->add_host)
401
                        hl->add_host(host);
402
        }
403
        read_unlock(&hl_drivers_lock);
404
}
405
 
406
void highlevel_remove_host(struct hpsb_host *host)
407
{
408
        struct list_head *entry;
409
        struct hpsb_highlevel *hl;
410
 
411
        read_lock(&hl_drivers_lock);
412
        list_for_each(entry, &hl_drivers) {
413
                hl = list_entry(entry, struct hpsb_highlevel, hl_list);
414
 
415
                if (hl->remove_host) {
416
                        hl->remove_host(host);
417
                        hpsb_destroy_hostinfo(hl, host);
418
                }
419
        }
420
        read_unlock(&hl_drivers_lock);
421
}
422
 
423
void highlevel_host_reset(struct hpsb_host *host)
424
{
425
        struct list_head *entry;
426
        struct hpsb_highlevel *hl;
427
 
428
        read_lock(&hl_drivers_lock);
429
        list_for_each(entry, &hl_drivers) {
430
                hl = list_entry(entry, struct hpsb_highlevel, hl_list);
431
 
432
                if (hl->host_reset)
433
                        hl->host_reset(host);
434
        }
435
        read_unlock(&hl_drivers_lock);
436
}
437
 
438
void highlevel_iso_receive(struct hpsb_host *host, void *data,
439
                           size_t length)
440
{
441
        struct list_head *entry;
442
        struct hpsb_highlevel *hl;
443
        int channel = (((quadlet_t *)data)[0] >> 8) & 0x3f;
444
 
445
        read_lock(&hl_drivers_lock);
446
        entry = hl_drivers.next;
447
 
448
        while (entry != &hl_drivers) {
449
                hl = list_entry(entry, struct hpsb_highlevel, hl_list);
450
                if (hl->iso_receive) {
451
                        hl->iso_receive(host, channel, data, length);
452
                }
453
                entry = entry->next;
454
        }
455
        read_unlock(&hl_drivers_lock);
456
}
457
 
458
void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction,
459
                           void *data, size_t length)
460
{
461
        struct list_head *entry;
462
        struct hpsb_highlevel *hl;
463
        int cts = ((quadlet_t *)data)[0] >> 4;
464
 
465
        read_lock(&hl_drivers_lock);
466
        entry = hl_drivers.next;
467
 
468
        while (entry != &hl_drivers) {
469
                hl = list_entry(entry, struct hpsb_highlevel, hl_list);
470
                if (hl->fcp_request) {
471
                        hl->fcp_request(host, nodeid, direction, cts, data,
472
                                            length);
473
                }
474
                entry = entry->next;
475
        }
476
        read_unlock(&hl_drivers_lock);
477
}
478
 
479
int highlevel_read(struct hpsb_host *host, int nodeid, void *data,
480
                   u64 addr, unsigned int length, u16 flags)
481
{
482
        struct hpsb_address_serve *as;
483
        struct list_head *entry;
484
        unsigned int partlength;
485
        int rcode = RCODE_ADDRESS_ERROR;
486
 
487
        read_lock(&addr_space_lock);
488
 
489
        entry = addr_space.next;
490
        as = list_entry(entry, struct hpsb_address_serve, as_list);
491
 
492
        while (as->start <= addr) {
493
                if (as->end > addr) {
494
                        partlength = min(as->end - addr, (u64) length);
495
 
496
                        if (as->op->read) {
497
                                rcode = as->op->read(host, nodeid, data,
498
                                                     addr, partlength, flags);
499
                        } else {
500
                                rcode = RCODE_TYPE_ERROR;
501
                        }
502
 
503
                        (u8 *)data += partlength;
504
                        length -= partlength;
505
                        addr += partlength;
506
 
507
                        if ((rcode != RCODE_COMPLETE) || !length) {
508
                                break;
509
                        }
510
                }
511
 
512
                entry = entry->next;
513
                as = list_entry(entry, struct hpsb_address_serve, as_list);
514
        }
515
 
516
        read_unlock(&addr_space_lock);
517
 
518
        if (length && (rcode == RCODE_COMPLETE)) {
519
                rcode = RCODE_ADDRESS_ERROR;
520
        }
521
 
522
        return rcode;
523
}
524
 
525
int highlevel_write(struct hpsb_host *host, int nodeid, int destid,
526
                    void *data, u64 addr, unsigned int length, u16 flags)
527
{
528
        struct hpsb_address_serve *as;
529
        struct list_head *entry;
530
        unsigned int partlength;
531
        int rcode = RCODE_ADDRESS_ERROR;
532
 
533
        read_lock(&addr_space_lock);
534
 
535
        entry = addr_space.next;
536
        as = list_entry(entry, struct hpsb_address_serve, as_list);
537
 
538
        while (as->start <= addr) {
539
                if (as->end > addr) {
540
                        partlength = min(as->end - addr, (u64) length);
541
 
542
                        if (as->op->write) {
543
                                rcode = as->op->write(host, nodeid, destid,
544
                                                      data, addr, partlength, flags);
545
                        } else {
546
                                rcode = RCODE_TYPE_ERROR;
547
                        }
548
 
549
                        (u8 *)data += partlength;
550
                        length -= partlength;
551
                        addr += partlength;
552
 
553
                        if ((rcode != RCODE_COMPLETE) || !length) {
554
                                break;
555
                        }
556
                }
557
 
558
                entry = entry->next;
559
                as = list_entry(entry, struct hpsb_address_serve, as_list);
560
        }
561
 
562
        read_unlock(&addr_space_lock);
563
 
564
        if (length && (rcode == RCODE_COMPLETE)) {
565
                rcode = RCODE_ADDRESS_ERROR;
566
        }
567
 
568
        return rcode;
569
}
570
 
571
 
572
int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
573
                   u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags)
574
{
575
        struct hpsb_address_serve *as;
576
        struct list_head *entry;
577
        int rcode = RCODE_ADDRESS_ERROR;
578
 
579
        read_lock(&addr_space_lock);
580
 
581
        entry = addr_space.next;
582
        as = list_entry(entry, struct hpsb_address_serve, as_list);
583
 
584
        while (as->start <= addr) {
585
                if (as->end > addr) {
586
                        if (as->op->lock) {
587
                                rcode = as->op->lock(host, nodeid, store, addr,
588
                                                     data, arg, ext_tcode, flags);
589
                        } else {
590
                                rcode = RCODE_TYPE_ERROR;
591
                        }
592
 
593
                        break;
594
                }
595
 
596
                entry = entry->next;
597
                as = list_entry(entry, struct hpsb_address_serve, as_list);
598
        }
599
 
600
        read_unlock(&addr_space_lock);
601
 
602
        return rcode;
603
}
604
 
605
int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
606
                     u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags)
607
{
608
        struct hpsb_address_serve *as;
609
        struct list_head *entry;
610
        int rcode = RCODE_ADDRESS_ERROR;
611
 
612
        read_lock(&addr_space_lock);
613
 
614
        entry = addr_space.next;
615
        as = list_entry(entry, struct hpsb_address_serve, as_list);
616
 
617
        while (as->start <= addr) {
618
                if (as->end > addr) {
619
                        if (as->op->lock64) {
620
                                rcode = as->op->lock64(host, nodeid, store,
621
                                                       addr, data, arg,
622
                                                       ext_tcode, flags);
623
                        } else {
624
                                rcode = RCODE_TYPE_ERROR;
625
                        }
626
 
627
                        break;
628
                }
629
 
630
                entry = entry->next;
631
                as = list_entry(entry, struct hpsb_address_serve, as_list);
632
        }
633
 
634
        read_unlock(&addr_space_lock);
635
 
636
        return rcode;
637
}
638
 
639
void init_hpsb_highlevel(void)
640
{
641
        INIT_LIST_HEAD(&dummy_zero_addr.as_list);
642
        INIT_LIST_HEAD(&dummy_zero_addr.addr_list);
643
        INIT_LIST_HEAD(&dummy_max_addr.as_list);
644
        INIT_LIST_HEAD(&dummy_max_addr.addr_list);
645
 
646
        dummy_zero_addr.op = dummy_max_addr.op = &dummy_ops;
647
 
648
        dummy_zero_addr.start = dummy_zero_addr.end = 0;
649
        dummy_max_addr.start = dummy_max_addr.end = ((u64) 1) << 48;
650
 
651
        list_add_tail(&dummy_zero_addr.as_list, &addr_space);
652
        list_add_tail(&dummy_max_addr.as_list, &addr_space);
653
}

powered by: WebSVN 2.1.0

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