Merge git://oss.sgi.com:8090/xfs-2.6
[pandora-kernel.git] / drivers / ieee1394 / highlevel.c
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/config.h>
21 #include <linux/slab.h>
22 #include <linux/list.h>
23 #include <linux/bitops.h>
24
25 #include "ieee1394.h"
26 #include "ieee1394_types.h"
27 #include "hosts.h"
28 #include "ieee1394_core.h"
29 #include "highlevel.h"
30 #include "nodemgr.h"
31
32
33 struct hl_host_info {
34         struct list_head list;
35         struct hpsb_host *host;
36         size_t size;
37         unsigned long key;
38         void *data;
39 };
40
41
42 static LIST_HEAD(hl_drivers);
43 static DECLARE_RWSEM(hl_drivers_sem);
44
45 static LIST_HEAD(hl_irqs);
46 static DEFINE_RWLOCK(hl_irqs_lock);
47
48 static DEFINE_RWLOCK(addr_space_lock);
49
50 /* addr_space list will have zero and max already included as bounds */
51 static struct hpsb_address_ops dummy_ops = { NULL, NULL, NULL, NULL };
52 static struct hpsb_address_serve dummy_zero_addr, dummy_max_addr;
53
54
55 static struct hl_host_info *hl_get_hostinfo(struct hpsb_highlevel *hl,
56                                             struct hpsb_host *host)
57 {
58         struct hl_host_info *hi = NULL;
59
60         if (!hl || !host)
61                 return NULL;
62
63         read_lock(&hl->host_info_lock);
64         list_for_each_entry(hi, &hl->host_info_list, list) {
65                 if (hi->host == host) {
66                         read_unlock(&hl->host_info_lock);
67                         return hi;
68                 }
69         }
70         read_unlock(&hl->host_info_lock);
71         return NULL;
72 }
73
74 /* Returns a per host/driver data structure that was previously stored by
75  * hpsb_create_hostinfo. */
76 void *hpsb_get_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host)
77 {
78         struct hl_host_info *hi = hl_get_hostinfo(hl, host);
79
80         return hi ? hi->data : NULL;
81 }
82
83 /* If size is zero, then the return here is only valid for error checking */
84 void *hpsb_create_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
85                            size_t data_size)
86 {
87         struct hl_host_info *hi;
88         void *data;
89         unsigned long flags;
90
91         hi = hl_get_hostinfo(hl, host);
92         if (hi) {
93                 HPSB_ERR("%s called hpsb_create_hostinfo when hostinfo already"
94                          " exists", hl->name);
95                 return NULL;
96         }
97
98         hi = kzalloc(sizeof(*hi) + data_size, GFP_ATOMIC);
99         if (!hi)
100                 return NULL;
101
102         if (data_size) {
103                 data = hi->data = hi + 1;
104                 hi->size = data_size;
105         } else
106                 data = hi;
107
108         hi->host = host;
109
110         write_lock_irqsave(&hl->host_info_lock, flags);
111         list_add_tail(&hi->list, &hl->host_info_list);
112         write_unlock_irqrestore(&hl->host_info_lock, flags);
113
114         return data;
115 }
116
117 int hpsb_set_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
118                       void *data)
119 {
120         struct hl_host_info *hi;
121
122         hi = hl_get_hostinfo(hl, host);
123         if (hi) {
124                 if (!hi->size && !hi->data) {
125                         hi->data = data;
126                         return 0;
127                 } else
128                         HPSB_ERR("%s called hpsb_set_hostinfo when hostinfo "
129                                  "already has data", hl->name);
130         } else
131                 HPSB_ERR("%s called hpsb_set_hostinfo when no hostinfo exists",
132                          hl->name);
133         return -EINVAL;
134 }
135
136 void hpsb_destroy_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host)
137 {
138         struct hl_host_info *hi;
139
140         hi = hl_get_hostinfo(hl, host);
141         if (hi) {
142                 unsigned long flags;
143                 write_lock_irqsave(&hl->host_info_lock, flags);
144                 list_del(&hi->list);
145                 write_unlock_irqrestore(&hl->host_info_lock, flags);
146                 kfree(hi);
147         }
148         return;
149 }
150
151 void hpsb_set_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host,
152                            unsigned long key)
153 {
154         struct hl_host_info *hi;
155
156         hi = hl_get_hostinfo(hl, host);
157         if (hi)
158                 hi->key = key;
159         return;
160 }
161
162 void *hpsb_get_hostinfo_bykey(struct hpsb_highlevel *hl, unsigned long key)
163 {
164         struct hl_host_info *hi;
165         void *data = NULL;
166
167         if (!hl)
168                 return NULL;
169
170         read_lock(&hl->host_info_lock);
171         list_for_each_entry(hi, &hl->host_info_list, list) {
172                 if (hi->key == key) {
173                         data = hi->data;
174                         break;
175                 }
176         }
177         read_unlock(&hl->host_info_lock);
178         return data;
179 }
180
181 static int highlevel_for_each_host_reg(struct hpsb_host *host, void *__data)
182 {
183         struct hpsb_highlevel *hl = __data;
184
185         hl->add_host(host);
186
187         if (host->update_config_rom && hpsb_update_config_rom_image(host) < 0)
188                 HPSB_ERR("Failed to generate Configuration ROM image for host "
189                          "%s-%d", hl->name, host->id);
190         return 0;
191 }
192
193 void hpsb_register_highlevel(struct hpsb_highlevel *hl)
194 {
195         unsigned long flags;
196
197         INIT_LIST_HEAD(&hl->addr_list);
198         INIT_LIST_HEAD(&hl->host_info_list);
199
200         rwlock_init(&hl->host_info_lock);
201
202         down_write(&hl_drivers_sem);
203         list_add_tail(&hl->hl_list, &hl_drivers);
204         up_write(&hl_drivers_sem);
205
206         write_lock_irqsave(&hl_irqs_lock, flags);
207         list_add_tail(&hl->irq_list, &hl_irqs);
208         write_unlock_irqrestore(&hl_irqs_lock, flags);
209
210         if (hl->add_host)
211                 nodemgr_for_each_host(hl, highlevel_for_each_host_reg);
212         return;
213 }
214
215 static void __delete_addr(struct hpsb_address_serve *as)
216 {
217         list_del(&as->host_list);
218         list_del(&as->hl_list);
219         kfree(as);
220 }
221
222 static void __unregister_host(struct hpsb_highlevel *hl, struct hpsb_host *host,
223                               int update_cr)
224 {
225         unsigned long flags;
226         struct list_head *lh, *next;
227         struct hpsb_address_serve *as;
228
229         /* First, let the highlevel driver unreg */
230         if (hl->remove_host)
231                 hl->remove_host(host);
232
233         /* Remove any addresses that are matched for this highlevel driver
234          * and this particular host. */
235         write_lock_irqsave(&addr_space_lock, flags);
236         list_for_each_safe (lh, next, &hl->addr_list) {
237                 as = list_entry(lh, struct hpsb_address_serve, hl_list);
238                 if (as->host == host)
239                         __delete_addr(as);
240         }
241         write_unlock_irqrestore(&addr_space_lock, flags);
242
243         /* Now update the config-rom to reflect anything removed by the
244          * highlevel driver. */
245         if (update_cr && host->update_config_rom &&
246             hpsb_update_config_rom_image(host) < 0)
247                 HPSB_ERR("Failed to generate Configuration ROM image for host "
248                          "%s-%d", hl->name, host->id);
249
250         /* Finally remove all the host info associated between these two. */
251         hpsb_destroy_hostinfo(hl, host);
252 }
253
254 static int highlevel_for_each_host_unreg(struct hpsb_host *host, void *__data)
255 {
256         struct hpsb_highlevel *hl = __data;
257
258         __unregister_host(hl, host, 1);
259         return 0;
260 }
261
262 void hpsb_unregister_highlevel(struct hpsb_highlevel *hl)
263 {
264         unsigned long flags;
265
266         write_lock_irqsave(&hl_irqs_lock, flags);
267         list_del(&hl->irq_list);
268         write_unlock_irqrestore(&hl_irqs_lock, flags);
269
270         down_write(&hl_drivers_sem);
271         list_del(&hl->hl_list);
272         up_write(&hl_drivers_sem);
273
274         nodemgr_for_each_host(hl, highlevel_for_each_host_unreg);
275 }
276
277 u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl,
278                                          struct hpsb_host *host,
279                                          struct hpsb_address_ops *ops,
280                                          u64 size, u64 alignment,
281                                          u64 start, u64 end)
282 {
283         struct hpsb_address_serve *as, *a1, *a2;
284         struct list_head *entry;
285         u64 retval = CSR1212_INVALID_ADDR_SPACE;
286         unsigned long flags;
287         u64 align_mask = ~(alignment - 1);
288
289         if ((alignment & 3) || (alignment > 0x800000000000ULL) ||
290             (hweight64(alignment) != 1)) {
291                 HPSB_ERR("%s called with invalid alignment: 0x%048llx",
292                          __FUNCTION__, (unsigned long long)alignment);
293                 return retval;
294         }
295
296         /* default range,
297          * avoids controller's posted write area (see OHCI 1.1 clause 1.5) */
298         if (start == CSR1212_INVALID_ADDR_SPACE &&
299             end   == CSR1212_INVALID_ADDR_SPACE) {
300                 start = host->middle_addr_space;
301                 end   = CSR1212_ALL_SPACE_END;
302         }
303
304         if (((start|end) & ~align_mask) || (start >= end) ||
305             (end > CSR1212_ALL_SPACE_END)) {
306                 HPSB_ERR("%s called with invalid addresses "
307                          "(start = %012Lx  end = %012Lx)", __FUNCTION__,
308                          (unsigned long long)start,(unsigned long long)end);
309                 return retval;
310         }
311
312         as = kmalloc(sizeof(*as), GFP_KERNEL);
313         if (!as)
314                 return retval;
315
316         INIT_LIST_HEAD(&as->host_list);
317         INIT_LIST_HEAD(&as->hl_list);
318         as->op = ops;
319         as->host = host;
320
321         write_lock_irqsave(&addr_space_lock, flags);
322         list_for_each(entry, &host->addr_space) {
323                 u64 a1sa, a1ea;
324                 u64 a2sa, a2ea;
325
326                 a1 = list_entry(entry, struct hpsb_address_serve, host_list);
327                 a2 = list_entry(entry->next, struct hpsb_address_serve,
328                                 host_list);
329
330                 a1sa = a1->start & align_mask;
331                 a1ea = (a1->end + alignment -1) & align_mask;
332                 a2sa = a2->start & align_mask;
333                 a2ea = (a2->end + alignment -1) & align_mask;
334
335                 if ((a2sa - a1ea >= size) && (a2sa - start >= size) &&
336                     (a2sa > start)) {
337                         as->start = max(start, a1ea);
338                         as->end = as->start + size;
339                         list_add(&as->host_list, entry);
340                         list_add_tail(&as->hl_list, &hl->addr_list);
341                         retval = as->start;
342                         break;
343                 }
344         }
345         write_unlock_irqrestore(&addr_space_lock, flags);
346
347         if (retval == CSR1212_INVALID_ADDR_SPACE)
348                 kfree(as);
349         return retval;
350 }
351
352 int hpsb_register_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
353                             struct hpsb_address_ops *ops, u64 start, u64 end)
354 {
355         struct hpsb_address_serve *as;
356         struct list_head *lh;
357         int retval = 0;
358         unsigned long flags;
359
360         if (((start|end) & 3) || (start >= end) ||
361             (end > CSR1212_ALL_SPACE_END)) {
362                 HPSB_ERR("%s called with invalid addresses", __FUNCTION__);
363                 return 0;
364         }
365
366         as = kmalloc(sizeof(*as), GFP_ATOMIC);
367         if (!as)
368                 return 0;
369
370         INIT_LIST_HEAD(&as->host_list);
371         INIT_LIST_HEAD(&as->hl_list);
372         as->op = ops;
373         as->start = start;
374         as->end = end;
375         as->host = host;
376
377         write_lock_irqsave(&addr_space_lock, flags);
378         list_for_each(lh, &host->addr_space) {
379                 struct hpsb_address_serve *as_this =
380                         list_entry(lh, struct hpsb_address_serve, host_list);
381                 struct hpsb_address_serve *as_next =
382                         list_entry(lh->next, struct hpsb_address_serve,
383                                    host_list);
384
385                 if (as_this->end > as->start)
386                         break;
387
388                 if (as_next->start >= as->end) {
389                         list_add(&as->host_list, lh);
390                         list_add_tail(&as->hl_list, &hl->addr_list);
391                         retval = 1;
392                         break;
393                 }
394         }
395         write_unlock_irqrestore(&addr_space_lock, flags);
396
397         if (retval == 0)
398                 kfree(as);
399         return retval;
400 }
401
402 int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
403                               u64 start)
404 {
405         int retval = 0;
406         struct hpsb_address_serve *as;
407         struct list_head *lh, *next;
408         unsigned long flags;
409
410         write_lock_irqsave(&addr_space_lock, flags);
411         list_for_each_safe (lh, next, &hl->addr_list) {
412                 as = list_entry(lh, struct hpsb_address_serve, hl_list);
413                 if (as->start == start && as->host == host) {
414                         __delete_addr(as);
415                         retval = 1;
416                         break;
417                 }
418         }
419         write_unlock_irqrestore(&addr_space_lock, flags);
420         return retval;
421 }
422
423 int hpsb_listen_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
424                         unsigned int channel)
425 {
426         if (channel > 63) {
427                 HPSB_ERR("%s called with invalid channel", __FUNCTION__);
428                 return -EINVAL;
429         }
430         if (host->iso_listen_count[channel]++ == 0)
431                 return host->driver->devctl(host, ISO_LISTEN_CHANNEL, channel);
432         return 0;
433 }
434
435 void hpsb_unlisten_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
436                            unsigned int channel)
437 {
438         if (channel > 63) {
439                 HPSB_ERR("%s called with invalid channel", __FUNCTION__);
440                 return;
441         }
442         if (--host->iso_listen_count[channel] == 0)
443                 host->driver->devctl(host, ISO_UNLISTEN_CHANNEL, channel);
444 }
445
446 static void init_hpsb_highlevel(struct hpsb_host *host)
447 {
448         INIT_LIST_HEAD(&dummy_zero_addr.host_list);
449         INIT_LIST_HEAD(&dummy_zero_addr.hl_list);
450         INIT_LIST_HEAD(&dummy_max_addr.host_list);
451         INIT_LIST_HEAD(&dummy_max_addr.hl_list);
452
453         dummy_zero_addr.op = dummy_max_addr.op = &dummy_ops;
454
455         dummy_zero_addr.start = dummy_zero_addr.end = 0;
456         dummy_max_addr.start = dummy_max_addr.end = ((u64) 1) << 48;
457
458         list_add_tail(&dummy_zero_addr.host_list, &host->addr_space);
459         list_add_tail(&dummy_max_addr.host_list, &host->addr_space);
460 }
461
462 void highlevel_add_host(struct hpsb_host *host)
463 {
464         struct hpsb_highlevel *hl;
465
466         init_hpsb_highlevel(host);
467
468         down_read(&hl_drivers_sem);
469         list_for_each_entry(hl, &hl_drivers, hl_list) {
470                 if (hl->add_host)
471                         hl->add_host(host);
472         }
473         up_read(&hl_drivers_sem);
474         if (host->update_config_rom && hpsb_update_config_rom_image(host) < 0)
475                 HPSB_ERR("Failed to generate Configuration ROM image for host "
476                          "%s-%d", hl->name, host->id);
477 }
478
479 void highlevel_remove_host(struct hpsb_host *host)
480 {
481         struct hpsb_highlevel *hl;
482
483         down_read(&hl_drivers_sem);
484         list_for_each_entry(hl, &hl_drivers, hl_list)
485                 __unregister_host(hl, host, 0);
486         up_read(&hl_drivers_sem);
487 }
488
489 void highlevel_host_reset(struct hpsb_host *host)
490 {
491         unsigned long flags;
492         struct hpsb_highlevel *hl;
493
494         read_lock_irqsave(&hl_irqs_lock, flags);
495         list_for_each_entry(hl, &hl_irqs, irq_list) {
496                 if (hl->host_reset)
497                         hl->host_reset(host);
498         }
499         read_unlock_irqrestore(&hl_irqs_lock, flags);
500 }
501
502 void highlevel_iso_receive(struct hpsb_host *host, void *data, size_t length)
503 {
504         unsigned long flags;
505         struct hpsb_highlevel *hl;
506         int channel = (((quadlet_t *)data)[0] >> 8) & 0x3f;
507
508         read_lock_irqsave(&hl_irqs_lock, flags);
509         list_for_each_entry(hl, &hl_irqs, irq_list) {
510                 if (hl->iso_receive)
511                         hl->iso_receive(host, channel, data, length);
512         }
513         read_unlock_irqrestore(&hl_irqs_lock, flags);
514 }
515
516 void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction,
517                            void *data, size_t length)
518 {
519         unsigned long flags;
520         struct hpsb_highlevel *hl;
521         int cts = ((quadlet_t *)data)[0] >> 4;
522
523         read_lock_irqsave(&hl_irqs_lock, flags);
524         list_for_each_entry(hl, &hl_irqs, irq_list) {
525                 if (hl->fcp_request)
526                         hl->fcp_request(host, nodeid, direction, cts, data,
527                                         length);
528         }
529         read_unlock_irqrestore(&hl_irqs_lock, flags);
530 }
531
532 int highlevel_read(struct hpsb_host *host, int nodeid, void *data, u64 addr,
533                    unsigned int length, u16 flags)
534 {
535         struct hpsb_address_serve *as;
536         unsigned int partlength;
537         int rcode = RCODE_ADDRESS_ERROR;
538
539         read_lock(&addr_space_lock);
540         list_for_each_entry(as, &host->addr_space, host_list) {
541                 if (as->start > addr)
542                         break;
543
544                 if (as->end > addr) {
545                         partlength = min(as->end - addr, (u64) length);
546
547                         if (as->op->read)
548                                 rcode = as->op->read(host, nodeid, data,
549                                                      addr, partlength, flags);
550                         else
551                                 rcode = RCODE_TYPE_ERROR;
552
553                         data += partlength;
554                         length -= partlength;
555                         addr += partlength;
556
557                         if ((rcode != RCODE_COMPLETE) || !length)
558                                 break;
559                 }
560         }
561         read_unlock(&addr_space_lock);
562
563         if (length && (rcode == RCODE_COMPLETE))
564                 rcode = RCODE_ADDRESS_ERROR;
565         return rcode;
566 }
567
568 int highlevel_write(struct hpsb_host *host, int nodeid, int destid, void *data,
569                     u64 addr, unsigned int length, u16 flags)
570 {
571         struct hpsb_address_serve *as;
572         unsigned int partlength;
573         int rcode = RCODE_ADDRESS_ERROR;
574
575         read_lock(&addr_space_lock);
576         list_for_each_entry(as, &host->addr_space, host_list) {
577                 if (as->start > addr)
578                         break;
579
580                 if (as->end > addr) {
581                         partlength = min(as->end - addr, (u64) length);
582
583                         if (as->op->write)
584                                 rcode = as->op->write(host, nodeid, destid,
585                                                       data, addr, partlength,
586                                                       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_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
606                    u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode,
607                    u16 flags)
608 {
609         struct hpsb_address_serve *as;
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                         if (as->op->lock)
619                                 rcode = as->op->lock(host, nodeid, store, addr,
620                                                      data, arg, ext_tcode,
621                                                      flags);
622                         else
623                                 rcode = RCODE_TYPE_ERROR;
624                         break;
625                 }
626         }
627         read_unlock(&addr_space_lock);
628         return rcode;
629 }
630
631 int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
632                      u64 addr, octlet_t data, octlet_t arg, int ext_tcode,
633                      u16 flags)
634 {
635         struct hpsb_address_serve *as;
636         int rcode = RCODE_ADDRESS_ERROR;
637
638         read_lock(&addr_space_lock);
639
640         list_for_each_entry(as, &host->addr_space, host_list) {
641                 if (as->start > addr)
642                         break;
643
644                 if (as->end > addr) {
645                         if (as->op->lock64)
646                                 rcode = as->op->lock64(host, nodeid, store,
647                                                        addr, data, arg,
648                                                        ext_tcode, flags);
649                         else
650                                 rcode = RCODE_TYPE_ERROR;
651                         break;
652                 }
653         }
654         read_unlock(&addr_space_lock);
655         return rcode;
656 }