This is pre8 ...
[linux-2.6/linux-mips.git] / drivers / ieee1394 / guid.c
blob1aa453292e6665074c44b0d6e688e9cfbe79e2ad
1 /*
2 * IEEE 1394 for Linux
4 * GUID collection and management
6 * Copyright (C) 2000 Andreas E. Bombe
8 * This code is licensed under the GPL. See the file COPYING in the root
9 * directory of the kernel sources for details.
12 #include <linux/kernel.h>
13 #include <linux/list.h>
14 #include <linux/slab.h>
15 #include <asm/byteorder.h>
16 #include <asm/atomic.h>
18 #include "ieee1394_types.h"
19 #include "ieee1394.h"
20 #include "hosts.h"
21 #include "ieee1394_transactions.h"
22 #include "highlevel.h"
23 #include "csr.h"
26 static atomic_t outstanding_requests;
28 static LIST_HEAD(guid_list);
29 rwlock_t guid_lock = RW_LOCK_UNLOCKED;
31 struct guid_entry {
32 struct list_head list;
33 atomic_t refcount;
35 u64 guid;
37 struct hpsb_host *host;
38 nodeid_t node_id;
40 atomic_t generation;
43 struct guid_req {
44 struct hpsb_packet *pkt;
45 struct tq_struct tq;
49 static struct guid_entry *create_guid_entry(void)
51 struct guid_entry *ge;
52 unsigned long flags;
54 ge = kmalloc(sizeof(struct guid_entry), SLAB_ATOMIC);
55 if (!ge) return NULL;
57 INIT_LIST_HEAD(&ge->list);
58 atomic_set(&ge->refcount, 0);
59 ge->guid = (u64) -1;
60 ge->host = NULL;
61 ge->node_id = 0;
62 atomic_set(&ge->generation, -1);
64 write_lock_irqsave(&guid_lock, flags);
65 list_add_tail(&ge->list, &guid_list);
66 write_unlock_irqrestore(&guid_lock, flags);
68 return ge;
71 static struct guid_entry *find_entry(u64 guid)
73 struct list_head *lh;
74 struct guid_entry *ge;
76 lh = guid_list.next;
77 while (lh != &guid_list) {
78 ge = list_entry(lh, struct guid_entry, list);
79 if (ge->guid == guid) return ge;
80 lh = lh->next;
83 return NULL;
86 static void associate_guid(struct hpsb_host *host, nodeid_t nodeid, u64 guid)
88 struct guid_entry *ge;
89 unsigned long flags;
91 HPSB_DEBUG("node %d on host 0x%p has GUID 0x%08x%08x",
92 nodeid & NODE_MASK, host, (unsigned int)(guid >> 32),
93 (unsigned int)(guid & 0xffffffff));
95 read_lock_irqsave(&guid_lock, flags);
96 ge = find_entry(guid);
97 read_unlock_irqrestore(&guid_lock, flags);
99 if (!ge) ge = create_guid_entry();
100 if (!ge) return;
102 ge->host = host;
103 ge->node_id = nodeid;
104 ge->guid = guid;
106 atomic_set(&ge->generation, get_hpsb_generation());
109 static void pkt_complete(struct guid_req *req)
111 struct hpsb_packet *pkt = req->pkt;
112 int rcode = (pkt->header[1] >> 12) & 0xf;
114 if (pkt->ack_code == ACK_PENDING && rcode == RCODE_COMPLETE) {
115 if (*(char *)pkt->data > 1) {
116 associate_guid(pkt->host, pkt->node_id,
117 ((u64)be32_to_cpu(pkt->data[3]) << 32)
118 | be32_to_cpu(pkt->data[4]));
119 } else {
120 HPSB_DEBUG("minimal ROM on node %d",
121 pkt->node_id & NODE_MASK);
123 } else {
124 HPSB_DEBUG("guid transaction error: ack %d, rcode %d",
125 pkt->ack_code, rcode);
128 free_tlabel(pkt->host, pkt->node_id, pkt->tlabel);
129 free_hpsb_packet(pkt);
130 kfree(req);
132 if (atomic_dec_and_test(&outstanding_requests)) {
133 /* FIXME: free unreferenced and inactive GUID entries. */
138 static void host_reset(struct hpsb_host *host)
140 struct guid_req *greq;
141 struct hpsb_packet *pkt;
142 struct selfid *sid = (struct selfid *)host->topology_map;
143 int nodecount = host->node_count;
144 nodeid_t nodeid = LOCAL_BUS;
146 for (; nodecount; nodecount--, nodeid++, sid++) {
147 while (sid->extended) sid++;
148 if (!sid->link_active) continue;
149 if (nodeid == host->node_id) continue;
151 greq = kmalloc(sizeof(struct guid_req), SLAB_ATOMIC);
152 if (!greq) {
153 HPSB_ERR("out of memory in GUID processing");
154 return;
157 pkt = hpsb_make_readbpacket(host, nodeid,
158 CSR_REGISTER_BASE + CSR_CONFIG_ROM,
159 20);
160 if (!pkt) {
161 kfree(greq);
162 HPSB_ERR("out of memory in GUID processing");
163 return;
166 greq->tq.next = NULL;
167 greq->tq.sync = 0;
168 greq->tq.routine = (void (*)(void*))pkt_complete;
169 greq->tq.data = greq;
170 greq->pkt = pkt;
172 queue_task(&greq->tq, &pkt->complete_tq);
174 if (!hpsb_send_packet(pkt)) {
175 free_tlabel(pkt->host, pkt->node_id, pkt->tlabel);
176 free_hpsb_packet(pkt);
177 kfree(greq);
178 HPSB_NOTICE("failed to send packet in GUID processing");
181 HPSB_INFO("GUID request sent to node %d", nodeid & NODE_MASK);
182 atomic_inc(&outstanding_requests);
187 struct guid_entry *hpsb_guid_get_handle(u64 guid)
189 unsigned long flags;
190 struct guid_entry *ge;
192 read_lock_irqsave(&guid_lock, flags);
193 ge = find_entry(guid);
194 if (ge) atomic_inc(&ge->refcount);
195 read_unlock_irqrestore(&guid_lock, flags);
197 return ge;
200 struct hpsb_host *hpsb_guid_localhost(struct guid_entry *ge)
202 if (atomic_read(&ge->generation) != get_hpsb_generation()) return NULL;
203 if (ge->node_id == ge->host->node_id) return ge->host;
204 return NULL;
207 int hpsb_guid_fill_packet(struct guid_entry *ge, struct hpsb_packet *pkt)
209 if (atomic_read(&ge->generation) != get_hpsb_generation()) return 0;
211 pkt->host = ge->host;
212 pkt->node_id = ge->node_id;
213 pkt->generation = atomic_read(&ge->generation);
214 return 1;
218 static struct hpsb_highlevel_ops guid_ops = {
219 host_reset: host_reset,
222 void init_ieee1394_guid(void)
224 atomic_set(&outstanding_requests, 0);
226 if (!hpsb_register_highlevel("GUID manager", &guid_ops)) {
227 HPSB_ERR("out of memory during ieee1394 initialization");