Commit 5878730be4e3d0c9527d6f2f688874e38acacc98
Committed by
Stefan Richter
1 parent
60a74a6ff8
Exists in
master
and in
7 other branches
firewire: core: Update WARN uses
Add missing newlines. Signed-off-by: Joe Perches <joe@perches.com> Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Showing 1 changed file with 3 additions and 3 deletions Inline Diff
drivers/firewire/core-transaction.c
1 | /* | 1 | /* |
2 | * Core IEEE1394 transaction logic | 2 | * Core IEEE1394 transaction logic |
3 | * | 3 | * |
4 | * Copyright (C) 2004-2006 Kristian Hoegsberg <krh@bitplanet.net> | 4 | * Copyright (C) 2004-2006 Kristian Hoegsberg <krh@bitplanet.net> |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by | 7 | * it under the terms of the GNU General Public License as published by |
8 | * the Free Software Foundation; either version 2 of the License, or | 8 | * the Free Software Foundation; either version 2 of the License, or |
9 | * (at your option) any later version. | 9 | * (at your option) any later version. |
10 | * | 10 | * |
11 | * This program is distributed in the hope that it will be useful, | 11 | * This program is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | * GNU General Public License for more details. | 14 | * GNU General Public License for more details. |
15 | * | 15 | * |
16 | * You should have received a copy of the GNU General Public License | 16 | * You should have received a copy of the GNU General Public License |
17 | * along with this program; if not, write to the Free Software Foundation, | 17 | * along with this program; if not, write to the Free Software Foundation, |
18 | * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | 18 | * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <linux/bug.h> | 21 | #include <linux/bug.h> |
22 | #include <linux/completion.h> | 22 | #include <linux/completion.h> |
23 | #include <linux/device.h> | 23 | #include <linux/device.h> |
24 | #include <linux/errno.h> | 24 | #include <linux/errno.h> |
25 | #include <linux/firewire.h> | 25 | #include <linux/firewire.h> |
26 | #include <linux/firewire-constants.h> | 26 | #include <linux/firewire-constants.h> |
27 | #include <linux/fs.h> | 27 | #include <linux/fs.h> |
28 | #include <linux/init.h> | 28 | #include <linux/init.h> |
29 | #include <linux/idr.h> | 29 | #include <linux/idr.h> |
30 | #include <linux/jiffies.h> | 30 | #include <linux/jiffies.h> |
31 | #include <linux/kernel.h> | 31 | #include <linux/kernel.h> |
32 | #include <linux/list.h> | 32 | #include <linux/list.h> |
33 | #include <linux/module.h> | 33 | #include <linux/module.h> |
34 | #include <linux/slab.h> | 34 | #include <linux/slab.h> |
35 | #include <linux/spinlock.h> | 35 | #include <linux/spinlock.h> |
36 | #include <linux/string.h> | 36 | #include <linux/string.h> |
37 | #include <linux/timer.h> | 37 | #include <linux/timer.h> |
38 | #include <linux/types.h> | 38 | #include <linux/types.h> |
39 | 39 | ||
40 | #include <asm/byteorder.h> | 40 | #include <asm/byteorder.h> |
41 | 41 | ||
42 | #include "core.h" | 42 | #include "core.h" |
43 | 43 | ||
44 | #define HEADER_PRI(pri) ((pri) << 0) | 44 | #define HEADER_PRI(pri) ((pri) << 0) |
45 | #define HEADER_TCODE(tcode) ((tcode) << 4) | 45 | #define HEADER_TCODE(tcode) ((tcode) << 4) |
46 | #define HEADER_RETRY(retry) ((retry) << 8) | 46 | #define HEADER_RETRY(retry) ((retry) << 8) |
47 | #define HEADER_TLABEL(tlabel) ((tlabel) << 10) | 47 | #define HEADER_TLABEL(tlabel) ((tlabel) << 10) |
48 | #define HEADER_DESTINATION(destination) ((destination) << 16) | 48 | #define HEADER_DESTINATION(destination) ((destination) << 16) |
49 | #define HEADER_SOURCE(source) ((source) << 16) | 49 | #define HEADER_SOURCE(source) ((source) << 16) |
50 | #define HEADER_RCODE(rcode) ((rcode) << 12) | 50 | #define HEADER_RCODE(rcode) ((rcode) << 12) |
51 | #define HEADER_OFFSET_HIGH(offset_high) ((offset_high) << 0) | 51 | #define HEADER_OFFSET_HIGH(offset_high) ((offset_high) << 0) |
52 | #define HEADER_DATA_LENGTH(length) ((length) << 16) | 52 | #define HEADER_DATA_LENGTH(length) ((length) << 16) |
53 | #define HEADER_EXTENDED_TCODE(tcode) ((tcode) << 0) | 53 | #define HEADER_EXTENDED_TCODE(tcode) ((tcode) << 0) |
54 | 54 | ||
55 | #define HEADER_GET_TCODE(q) (((q) >> 4) & 0x0f) | 55 | #define HEADER_GET_TCODE(q) (((q) >> 4) & 0x0f) |
56 | #define HEADER_GET_TLABEL(q) (((q) >> 10) & 0x3f) | 56 | #define HEADER_GET_TLABEL(q) (((q) >> 10) & 0x3f) |
57 | #define HEADER_GET_RCODE(q) (((q) >> 12) & 0x0f) | 57 | #define HEADER_GET_RCODE(q) (((q) >> 12) & 0x0f) |
58 | #define HEADER_GET_DESTINATION(q) (((q) >> 16) & 0xffff) | 58 | #define HEADER_GET_DESTINATION(q) (((q) >> 16) & 0xffff) |
59 | #define HEADER_GET_SOURCE(q) (((q) >> 16) & 0xffff) | 59 | #define HEADER_GET_SOURCE(q) (((q) >> 16) & 0xffff) |
60 | #define HEADER_GET_OFFSET_HIGH(q) (((q) >> 0) & 0xffff) | 60 | #define HEADER_GET_OFFSET_HIGH(q) (((q) >> 0) & 0xffff) |
61 | #define HEADER_GET_DATA_LENGTH(q) (((q) >> 16) & 0xffff) | 61 | #define HEADER_GET_DATA_LENGTH(q) (((q) >> 16) & 0xffff) |
62 | #define HEADER_GET_EXTENDED_TCODE(q) (((q) >> 0) & 0xffff) | 62 | #define HEADER_GET_EXTENDED_TCODE(q) (((q) >> 0) & 0xffff) |
63 | 63 | ||
64 | #define HEADER_DESTINATION_IS_BROADCAST(q) \ | 64 | #define HEADER_DESTINATION_IS_BROADCAST(q) \ |
65 | (((q) & HEADER_DESTINATION(0x3f)) == HEADER_DESTINATION(0x3f)) | 65 | (((q) & HEADER_DESTINATION(0x3f)) == HEADER_DESTINATION(0x3f)) |
66 | 66 | ||
67 | #define PHY_PACKET_CONFIG 0x0 | 67 | #define PHY_PACKET_CONFIG 0x0 |
68 | #define PHY_PACKET_LINK_ON 0x1 | 68 | #define PHY_PACKET_LINK_ON 0x1 |
69 | #define PHY_PACKET_SELF_ID 0x2 | 69 | #define PHY_PACKET_SELF_ID 0x2 |
70 | 70 | ||
71 | #define PHY_CONFIG_GAP_COUNT(gap_count) (((gap_count) << 16) | (1 << 22)) | 71 | #define PHY_CONFIG_GAP_COUNT(gap_count) (((gap_count) << 16) | (1 << 22)) |
72 | #define PHY_CONFIG_ROOT_ID(node_id) ((((node_id) & 0x3f) << 24) | (1 << 23)) | 72 | #define PHY_CONFIG_ROOT_ID(node_id) ((((node_id) & 0x3f) << 24) | (1 << 23)) |
73 | #define PHY_IDENTIFIER(id) ((id) << 30) | 73 | #define PHY_IDENTIFIER(id) ((id) << 30) |
74 | 74 | ||
75 | static int close_transaction(struct fw_transaction *transaction, | 75 | static int close_transaction(struct fw_transaction *transaction, |
76 | struct fw_card *card, int rcode) | 76 | struct fw_card *card, int rcode) |
77 | { | 77 | { |
78 | struct fw_transaction *t; | 78 | struct fw_transaction *t; |
79 | unsigned long flags; | 79 | unsigned long flags; |
80 | 80 | ||
81 | spin_lock_irqsave(&card->lock, flags); | 81 | spin_lock_irqsave(&card->lock, flags); |
82 | list_for_each_entry(t, &card->transaction_list, link) { | 82 | list_for_each_entry(t, &card->transaction_list, link) { |
83 | if (t == transaction) { | 83 | if (t == transaction) { |
84 | if (!del_timer(&t->split_timeout_timer)) { | 84 | if (!del_timer(&t->split_timeout_timer)) { |
85 | spin_unlock_irqrestore(&card->lock, flags); | 85 | spin_unlock_irqrestore(&card->lock, flags); |
86 | goto timed_out; | 86 | goto timed_out; |
87 | } | 87 | } |
88 | list_del_init(&t->link); | 88 | list_del_init(&t->link); |
89 | card->tlabel_mask &= ~(1ULL << t->tlabel); | 89 | card->tlabel_mask &= ~(1ULL << t->tlabel); |
90 | break; | 90 | break; |
91 | } | 91 | } |
92 | } | 92 | } |
93 | spin_unlock_irqrestore(&card->lock, flags); | 93 | spin_unlock_irqrestore(&card->lock, flags); |
94 | 94 | ||
95 | if (&t->link != &card->transaction_list) { | 95 | if (&t->link != &card->transaction_list) { |
96 | t->callback(card, rcode, NULL, 0, t->callback_data); | 96 | t->callback(card, rcode, NULL, 0, t->callback_data); |
97 | return 0; | 97 | return 0; |
98 | } | 98 | } |
99 | 99 | ||
100 | timed_out: | 100 | timed_out: |
101 | return -ENOENT; | 101 | return -ENOENT; |
102 | } | 102 | } |
103 | 103 | ||
104 | /* | 104 | /* |
105 | * Only valid for transactions that are potentially pending (ie have | 105 | * Only valid for transactions that are potentially pending (ie have |
106 | * been sent). | 106 | * been sent). |
107 | */ | 107 | */ |
108 | int fw_cancel_transaction(struct fw_card *card, | 108 | int fw_cancel_transaction(struct fw_card *card, |
109 | struct fw_transaction *transaction) | 109 | struct fw_transaction *transaction) |
110 | { | 110 | { |
111 | /* | 111 | /* |
112 | * Cancel the packet transmission if it's still queued. That | 112 | * Cancel the packet transmission if it's still queued. That |
113 | * will call the packet transmission callback which cancels | 113 | * will call the packet transmission callback which cancels |
114 | * the transaction. | 114 | * the transaction. |
115 | */ | 115 | */ |
116 | 116 | ||
117 | if (card->driver->cancel_packet(card, &transaction->packet) == 0) | 117 | if (card->driver->cancel_packet(card, &transaction->packet) == 0) |
118 | return 0; | 118 | return 0; |
119 | 119 | ||
120 | /* | 120 | /* |
121 | * If the request packet has already been sent, we need to see | 121 | * If the request packet has already been sent, we need to see |
122 | * if the transaction is still pending and remove it in that case. | 122 | * if the transaction is still pending and remove it in that case. |
123 | */ | 123 | */ |
124 | 124 | ||
125 | return close_transaction(transaction, card, RCODE_CANCELLED); | 125 | return close_transaction(transaction, card, RCODE_CANCELLED); |
126 | } | 126 | } |
127 | EXPORT_SYMBOL(fw_cancel_transaction); | 127 | EXPORT_SYMBOL(fw_cancel_transaction); |
128 | 128 | ||
129 | static void split_transaction_timeout_callback(unsigned long data) | 129 | static void split_transaction_timeout_callback(unsigned long data) |
130 | { | 130 | { |
131 | struct fw_transaction *t = (struct fw_transaction *)data; | 131 | struct fw_transaction *t = (struct fw_transaction *)data; |
132 | struct fw_card *card = t->card; | 132 | struct fw_card *card = t->card; |
133 | unsigned long flags; | 133 | unsigned long flags; |
134 | 134 | ||
135 | spin_lock_irqsave(&card->lock, flags); | 135 | spin_lock_irqsave(&card->lock, flags); |
136 | if (list_empty(&t->link)) { | 136 | if (list_empty(&t->link)) { |
137 | spin_unlock_irqrestore(&card->lock, flags); | 137 | spin_unlock_irqrestore(&card->lock, flags); |
138 | return; | 138 | return; |
139 | } | 139 | } |
140 | list_del(&t->link); | 140 | list_del(&t->link); |
141 | card->tlabel_mask &= ~(1ULL << t->tlabel); | 141 | card->tlabel_mask &= ~(1ULL << t->tlabel); |
142 | spin_unlock_irqrestore(&card->lock, flags); | 142 | spin_unlock_irqrestore(&card->lock, flags); |
143 | 143 | ||
144 | card->driver->cancel_packet(card, &t->packet); | 144 | card->driver->cancel_packet(card, &t->packet); |
145 | 145 | ||
146 | /* | 146 | /* |
147 | * At this point cancel_packet will never call the transaction | 147 | * At this point cancel_packet will never call the transaction |
148 | * callback, since we just took the transaction out of the list. | 148 | * callback, since we just took the transaction out of the list. |
149 | * So do it here. | 149 | * So do it here. |
150 | */ | 150 | */ |
151 | t->callback(card, RCODE_CANCELLED, NULL, 0, t->callback_data); | 151 | t->callback(card, RCODE_CANCELLED, NULL, 0, t->callback_data); |
152 | } | 152 | } |
153 | 153 | ||
154 | static void transmit_complete_callback(struct fw_packet *packet, | 154 | static void transmit_complete_callback(struct fw_packet *packet, |
155 | struct fw_card *card, int status) | 155 | struct fw_card *card, int status) |
156 | { | 156 | { |
157 | struct fw_transaction *t = | 157 | struct fw_transaction *t = |
158 | container_of(packet, struct fw_transaction, packet); | 158 | container_of(packet, struct fw_transaction, packet); |
159 | 159 | ||
160 | switch (status) { | 160 | switch (status) { |
161 | case ACK_COMPLETE: | 161 | case ACK_COMPLETE: |
162 | close_transaction(t, card, RCODE_COMPLETE); | 162 | close_transaction(t, card, RCODE_COMPLETE); |
163 | break; | 163 | break; |
164 | case ACK_PENDING: | 164 | case ACK_PENDING: |
165 | t->timestamp = packet->timestamp; | 165 | t->timestamp = packet->timestamp; |
166 | break; | 166 | break; |
167 | case ACK_BUSY_X: | 167 | case ACK_BUSY_X: |
168 | case ACK_BUSY_A: | 168 | case ACK_BUSY_A: |
169 | case ACK_BUSY_B: | 169 | case ACK_BUSY_B: |
170 | close_transaction(t, card, RCODE_BUSY); | 170 | close_transaction(t, card, RCODE_BUSY); |
171 | break; | 171 | break; |
172 | case ACK_DATA_ERROR: | 172 | case ACK_DATA_ERROR: |
173 | close_transaction(t, card, RCODE_DATA_ERROR); | 173 | close_transaction(t, card, RCODE_DATA_ERROR); |
174 | break; | 174 | break; |
175 | case ACK_TYPE_ERROR: | 175 | case ACK_TYPE_ERROR: |
176 | close_transaction(t, card, RCODE_TYPE_ERROR); | 176 | close_transaction(t, card, RCODE_TYPE_ERROR); |
177 | break; | 177 | break; |
178 | default: | 178 | default: |
179 | /* | 179 | /* |
180 | * In this case the ack is really a juju specific | 180 | * In this case the ack is really a juju specific |
181 | * rcode, so just forward that to the callback. | 181 | * rcode, so just forward that to the callback. |
182 | */ | 182 | */ |
183 | close_transaction(t, card, status); | 183 | close_transaction(t, card, status); |
184 | break; | 184 | break; |
185 | } | 185 | } |
186 | } | 186 | } |
187 | 187 | ||
188 | static void fw_fill_request(struct fw_packet *packet, int tcode, int tlabel, | 188 | static void fw_fill_request(struct fw_packet *packet, int tcode, int tlabel, |
189 | int destination_id, int source_id, int generation, int speed, | 189 | int destination_id, int source_id, int generation, int speed, |
190 | unsigned long long offset, void *payload, size_t length) | 190 | unsigned long long offset, void *payload, size_t length) |
191 | { | 191 | { |
192 | int ext_tcode; | 192 | int ext_tcode; |
193 | 193 | ||
194 | if (tcode == TCODE_STREAM_DATA) { | 194 | if (tcode == TCODE_STREAM_DATA) { |
195 | packet->header[0] = | 195 | packet->header[0] = |
196 | HEADER_DATA_LENGTH(length) | | 196 | HEADER_DATA_LENGTH(length) | |
197 | destination_id | | 197 | destination_id | |
198 | HEADER_TCODE(TCODE_STREAM_DATA); | 198 | HEADER_TCODE(TCODE_STREAM_DATA); |
199 | packet->header_length = 4; | 199 | packet->header_length = 4; |
200 | packet->payload = payload; | 200 | packet->payload = payload; |
201 | packet->payload_length = length; | 201 | packet->payload_length = length; |
202 | 202 | ||
203 | goto common; | 203 | goto common; |
204 | } | 204 | } |
205 | 205 | ||
206 | if (tcode > 0x10) { | 206 | if (tcode > 0x10) { |
207 | ext_tcode = tcode & ~0x10; | 207 | ext_tcode = tcode & ~0x10; |
208 | tcode = TCODE_LOCK_REQUEST; | 208 | tcode = TCODE_LOCK_REQUEST; |
209 | } else | 209 | } else |
210 | ext_tcode = 0; | 210 | ext_tcode = 0; |
211 | 211 | ||
212 | packet->header[0] = | 212 | packet->header[0] = |
213 | HEADER_RETRY(RETRY_X) | | 213 | HEADER_RETRY(RETRY_X) | |
214 | HEADER_TLABEL(tlabel) | | 214 | HEADER_TLABEL(tlabel) | |
215 | HEADER_TCODE(tcode) | | 215 | HEADER_TCODE(tcode) | |
216 | HEADER_DESTINATION(destination_id); | 216 | HEADER_DESTINATION(destination_id); |
217 | packet->header[1] = | 217 | packet->header[1] = |
218 | HEADER_OFFSET_HIGH(offset >> 32) | HEADER_SOURCE(source_id); | 218 | HEADER_OFFSET_HIGH(offset >> 32) | HEADER_SOURCE(source_id); |
219 | packet->header[2] = | 219 | packet->header[2] = |
220 | offset; | 220 | offset; |
221 | 221 | ||
222 | switch (tcode) { | 222 | switch (tcode) { |
223 | case TCODE_WRITE_QUADLET_REQUEST: | 223 | case TCODE_WRITE_QUADLET_REQUEST: |
224 | packet->header[3] = *(u32 *)payload; | 224 | packet->header[3] = *(u32 *)payload; |
225 | packet->header_length = 16; | 225 | packet->header_length = 16; |
226 | packet->payload_length = 0; | 226 | packet->payload_length = 0; |
227 | break; | 227 | break; |
228 | 228 | ||
229 | case TCODE_LOCK_REQUEST: | 229 | case TCODE_LOCK_REQUEST: |
230 | case TCODE_WRITE_BLOCK_REQUEST: | 230 | case TCODE_WRITE_BLOCK_REQUEST: |
231 | packet->header[3] = | 231 | packet->header[3] = |
232 | HEADER_DATA_LENGTH(length) | | 232 | HEADER_DATA_LENGTH(length) | |
233 | HEADER_EXTENDED_TCODE(ext_tcode); | 233 | HEADER_EXTENDED_TCODE(ext_tcode); |
234 | packet->header_length = 16; | 234 | packet->header_length = 16; |
235 | packet->payload = payload; | 235 | packet->payload = payload; |
236 | packet->payload_length = length; | 236 | packet->payload_length = length; |
237 | break; | 237 | break; |
238 | 238 | ||
239 | case TCODE_READ_QUADLET_REQUEST: | 239 | case TCODE_READ_QUADLET_REQUEST: |
240 | packet->header_length = 12; | 240 | packet->header_length = 12; |
241 | packet->payload_length = 0; | 241 | packet->payload_length = 0; |
242 | break; | 242 | break; |
243 | 243 | ||
244 | case TCODE_READ_BLOCK_REQUEST: | 244 | case TCODE_READ_BLOCK_REQUEST: |
245 | packet->header[3] = | 245 | packet->header[3] = |
246 | HEADER_DATA_LENGTH(length) | | 246 | HEADER_DATA_LENGTH(length) | |
247 | HEADER_EXTENDED_TCODE(ext_tcode); | 247 | HEADER_EXTENDED_TCODE(ext_tcode); |
248 | packet->header_length = 16; | 248 | packet->header_length = 16; |
249 | packet->payload_length = 0; | 249 | packet->payload_length = 0; |
250 | break; | 250 | break; |
251 | 251 | ||
252 | default: | 252 | default: |
253 | WARN(1, "wrong tcode %d", tcode); | 253 | WARN(1, "wrong tcode %d\n", tcode); |
254 | } | 254 | } |
255 | common: | 255 | common: |
256 | packet->speed = speed; | 256 | packet->speed = speed; |
257 | packet->generation = generation; | 257 | packet->generation = generation; |
258 | packet->ack = 0; | 258 | packet->ack = 0; |
259 | packet->payload_mapped = false; | 259 | packet->payload_mapped = false; |
260 | } | 260 | } |
261 | 261 | ||
262 | static int allocate_tlabel(struct fw_card *card) | 262 | static int allocate_tlabel(struct fw_card *card) |
263 | { | 263 | { |
264 | int tlabel; | 264 | int tlabel; |
265 | 265 | ||
266 | tlabel = card->current_tlabel; | 266 | tlabel = card->current_tlabel; |
267 | while (card->tlabel_mask & (1ULL << tlabel)) { | 267 | while (card->tlabel_mask & (1ULL << tlabel)) { |
268 | tlabel = (tlabel + 1) & 0x3f; | 268 | tlabel = (tlabel + 1) & 0x3f; |
269 | if (tlabel == card->current_tlabel) | 269 | if (tlabel == card->current_tlabel) |
270 | return -EBUSY; | 270 | return -EBUSY; |
271 | } | 271 | } |
272 | 272 | ||
273 | card->current_tlabel = (tlabel + 1) & 0x3f; | 273 | card->current_tlabel = (tlabel + 1) & 0x3f; |
274 | card->tlabel_mask |= 1ULL << tlabel; | 274 | card->tlabel_mask |= 1ULL << tlabel; |
275 | 275 | ||
276 | return tlabel; | 276 | return tlabel; |
277 | } | 277 | } |
278 | 278 | ||
279 | /** | 279 | /** |
280 | * fw_send_request() - submit a request packet for transmission | 280 | * fw_send_request() - submit a request packet for transmission |
281 | * @card: interface to send the request at | 281 | * @card: interface to send the request at |
282 | * @t: transaction instance to which the request belongs | 282 | * @t: transaction instance to which the request belongs |
283 | * @tcode: transaction code | 283 | * @tcode: transaction code |
284 | * @destination_id: destination node ID, consisting of bus_ID and phy_ID | 284 | * @destination_id: destination node ID, consisting of bus_ID and phy_ID |
285 | * @generation: bus generation in which request and response are valid | 285 | * @generation: bus generation in which request and response are valid |
286 | * @speed: transmission speed | 286 | * @speed: transmission speed |
287 | * @offset: 48bit wide offset into destination's address space | 287 | * @offset: 48bit wide offset into destination's address space |
288 | * @payload: data payload for the request subaction | 288 | * @payload: data payload for the request subaction |
289 | * @length: length of the payload, in bytes | 289 | * @length: length of the payload, in bytes |
290 | * @callback: function to be called when the transaction is completed | 290 | * @callback: function to be called when the transaction is completed |
291 | * @callback_data: data to be passed to the transaction completion callback | 291 | * @callback_data: data to be passed to the transaction completion callback |
292 | * | 292 | * |
293 | * Submit a request packet into the asynchronous request transmission queue. | 293 | * Submit a request packet into the asynchronous request transmission queue. |
294 | * Can be called from atomic context. If you prefer a blocking API, use | 294 | * Can be called from atomic context. If you prefer a blocking API, use |
295 | * fw_run_transaction() in a context that can sleep. | 295 | * fw_run_transaction() in a context that can sleep. |
296 | * | 296 | * |
297 | * In case of lock requests, specify one of the firewire-core specific %TCODE_ | 297 | * In case of lock requests, specify one of the firewire-core specific %TCODE_ |
298 | * constants instead of %TCODE_LOCK_REQUEST in @tcode. | 298 | * constants instead of %TCODE_LOCK_REQUEST in @tcode. |
299 | * | 299 | * |
300 | * Make sure that the value in @destination_id is not older than the one in | 300 | * Make sure that the value in @destination_id is not older than the one in |
301 | * @generation. Otherwise the request is in danger to be sent to a wrong node. | 301 | * @generation. Otherwise the request is in danger to be sent to a wrong node. |
302 | * | 302 | * |
303 | * In case of asynchronous stream packets i.e. %TCODE_STREAM_DATA, the caller | 303 | * In case of asynchronous stream packets i.e. %TCODE_STREAM_DATA, the caller |
304 | * needs to synthesize @destination_id with fw_stream_packet_destination_id(). | 304 | * needs to synthesize @destination_id with fw_stream_packet_destination_id(). |
305 | * It will contain tag, channel, and sy data instead of a node ID then. | 305 | * It will contain tag, channel, and sy data instead of a node ID then. |
306 | * | 306 | * |
307 | * The payload buffer at @data is going to be DMA-mapped except in case of | 307 | * The payload buffer at @data is going to be DMA-mapped except in case of |
308 | * quadlet-sized payload or of local (loopback) requests. Hence make sure that | 308 | * quadlet-sized payload or of local (loopback) requests. Hence make sure that |
309 | * the buffer complies with the restrictions for DMA-mapped memory. The | 309 | * the buffer complies with the restrictions for DMA-mapped memory. The |
310 | * @payload must not be freed before the @callback is called. | 310 | * @payload must not be freed before the @callback is called. |
311 | * | 311 | * |
312 | * In case of request types without payload, @data is NULL and @length is 0. | 312 | * In case of request types without payload, @data is NULL and @length is 0. |
313 | * | 313 | * |
314 | * After the transaction is completed successfully or unsuccessfully, the | 314 | * After the transaction is completed successfully or unsuccessfully, the |
315 | * @callback will be called. Among its parameters is the response code which | 315 | * @callback will be called. Among its parameters is the response code which |
316 | * is either one of the rcodes per IEEE 1394 or, in case of internal errors, | 316 | * is either one of the rcodes per IEEE 1394 or, in case of internal errors, |
317 | * the firewire-core specific %RCODE_SEND_ERROR. The other firewire-core | 317 | * the firewire-core specific %RCODE_SEND_ERROR. The other firewire-core |
318 | * specific rcodes (%RCODE_CANCELLED, %RCODE_BUSY, %RCODE_GENERATION, | 318 | * specific rcodes (%RCODE_CANCELLED, %RCODE_BUSY, %RCODE_GENERATION, |
319 | * %RCODE_NO_ACK) denote transaction timeout, busy responder, stale request | 319 | * %RCODE_NO_ACK) denote transaction timeout, busy responder, stale request |
320 | * generation, or missing ACK respectively. | 320 | * generation, or missing ACK respectively. |
321 | * | 321 | * |
322 | * Note some timing corner cases: fw_send_request() may complete much earlier | 322 | * Note some timing corner cases: fw_send_request() may complete much earlier |
323 | * than when the request packet actually hits the wire. On the other hand, | 323 | * than when the request packet actually hits the wire. On the other hand, |
324 | * transaction completion and hence execution of @callback may happen even | 324 | * transaction completion and hence execution of @callback may happen even |
325 | * before fw_send_request() returns. | 325 | * before fw_send_request() returns. |
326 | */ | 326 | */ |
327 | void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode, | 327 | void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode, |
328 | int destination_id, int generation, int speed, | 328 | int destination_id, int generation, int speed, |
329 | unsigned long long offset, void *payload, size_t length, | 329 | unsigned long long offset, void *payload, size_t length, |
330 | fw_transaction_callback_t callback, void *callback_data) | 330 | fw_transaction_callback_t callback, void *callback_data) |
331 | { | 331 | { |
332 | unsigned long flags; | 332 | unsigned long flags; |
333 | int tlabel; | 333 | int tlabel; |
334 | 334 | ||
335 | /* | 335 | /* |
336 | * Allocate tlabel from the bitmap and put the transaction on | 336 | * Allocate tlabel from the bitmap and put the transaction on |
337 | * the list while holding the card spinlock. | 337 | * the list while holding the card spinlock. |
338 | */ | 338 | */ |
339 | 339 | ||
340 | spin_lock_irqsave(&card->lock, flags); | 340 | spin_lock_irqsave(&card->lock, flags); |
341 | 341 | ||
342 | tlabel = allocate_tlabel(card); | 342 | tlabel = allocate_tlabel(card); |
343 | if (tlabel < 0) { | 343 | if (tlabel < 0) { |
344 | spin_unlock_irqrestore(&card->lock, flags); | 344 | spin_unlock_irqrestore(&card->lock, flags); |
345 | callback(card, RCODE_SEND_ERROR, NULL, 0, callback_data); | 345 | callback(card, RCODE_SEND_ERROR, NULL, 0, callback_data); |
346 | return; | 346 | return; |
347 | } | 347 | } |
348 | 348 | ||
349 | t->node_id = destination_id; | 349 | t->node_id = destination_id; |
350 | t->tlabel = tlabel; | 350 | t->tlabel = tlabel; |
351 | t->card = card; | 351 | t->card = card; |
352 | setup_timer(&t->split_timeout_timer, | 352 | setup_timer(&t->split_timeout_timer, |
353 | split_transaction_timeout_callback, (unsigned long)t); | 353 | split_transaction_timeout_callback, (unsigned long)t); |
354 | /* FIXME: start this timer later, relative to t->timestamp */ | 354 | /* FIXME: start this timer later, relative to t->timestamp */ |
355 | mod_timer(&t->split_timeout_timer, | 355 | mod_timer(&t->split_timeout_timer, |
356 | jiffies + card->split_timeout_jiffies); | 356 | jiffies + card->split_timeout_jiffies); |
357 | t->callback = callback; | 357 | t->callback = callback; |
358 | t->callback_data = callback_data; | 358 | t->callback_data = callback_data; |
359 | 359 | ||
360 | fw_fill_request(&t->packet, tcode, t->tlabel, | 360 | fw_fill_request(&t->packet, tcode, t->tlabel, |
361 | destination_id, card->node_id, generation, | 361 | destination_id, card->node_id, generation, |
362 | speed, offset, payload, length); | 362 | speed, offset, payload, length); |
363 | t->packet.callback = transmit_complete_callback; | 363 | t->packet.callback = transmit_complete_callback; |
364 | 364 | ||
365 | list_add_tail(&t->link, &card->transaction_list); | 365 | list_add_tail(&t->link, &card->transaction_list); |
366 | 366 | ||
367 | spin_unlock_irqrestore(&card->lock, flags); | 367 | spin_unlock_irqrestore(&card->lock, flags); |
368 | 368 | ||
369 | card->driver->send_request(card, &t->packet); | 369 | card->driver->send_request(card, &t->packet); |
370 | } | 370 | } |
371 | EXPORT_SYMBOL(fw_send_request); | 371 | EXPORT_SYMBOL(fw_send_request); |
372 | 372 | ||
373 | struct transaction_callback_data { | 373 | struct transaction_callback_data { |
374 | struct completion done; | 374 | struct completion done; |
375 | void *payload; | 375 | void *payload; |
376 | int rcode; | 376 | int rcode; |
377 | }; | 377 | }; |
378 | 378 | ||
379 | static void transaction_callback(struct fw_card *card, int rcode, | 379 | static void transaction_callback(struct fw_card *card, int rcode, |
380 | void *payload, size_t length, void *data) | 380 | void *payload, size_t length, void *data) |
381 | { | 381 | { |
382 | struct transaction_callback_data *d = data; | 382 | struct transaction_callback_data *d = data; |
383 | 383 | ||
384 | if (rcode == RCODE_COMPLETE) | 384 | if (rcode == RCODE_COMPLETE) |
385 | memcpy(d->payload, payload, length); | 385 | memcpy(d->payload, payload, length); |
386 | d->rcode = rcode; | 386 | d->rcode = rcode; |
387 | complete(&d->done); | 387 | complete(&d->done); |
388 | } | 388 | } |
389 | 389 | ||
390 | /** | 390 | /** |
391 | * fw_run_transaction() - send request and sleep until transaction is completed | 391 | * fw_run_transaction() - send request and sleep until transaction is completed |
392 | * | 392 | * |
393 | * Returns the RCODE. See fw_send_request() for parameter documentation. | 393 | * Returns the RCODE. See fw_send_request() for parameter documentation. |
394 | * Unlike fw_send_request(), @data points to the payload of the request or/and | 394 | * Unlike fw_send_request(), @data points to the payload of the request or/and |
395 | * to the payload of the response. | 395 | * to the payload of the response. |
396 | */ | 396 | */ |
397 | int fw_run_transaction(struct fw_card *card, int tcode, int destination_id, | 397 | int fw_run_transaction(struct fw_card *card, int tcode, int destination_id, |
398 | int generation, int speed, unsigned long long offset, | 398 | int generation, int speed, unsigned long long offset, |
399 | void *payload, size_t length) | 399 | void *payload, size_t length) |
400 | { | 400 | { |
401 | struct transaction_callback_data d; | 401 | struct transaction_callback_data d; |
402 | struct fw_transaction t; | 402 | struct fw_transaction t; |
403 | 403 | ||
404 | init_timer_on_stack(&t.split_timeout_timer); | 404 | init_timer_on_stack(&t.split_timeout_timer); |
405 | init_completion(&d.done); | 405 | init_completion(&d.done); |
406 | d.payload = payload; | 406 | d.payload = payload; |
407 | fw_send_request(card, &t, tcode, destination_id, generation, speed, | 407 | fw_send_request(card, &t, tcode, destination_id, generation, speed, |
408 | offset, payload, length, transaction_callback, &d); | 408 | offset, payload, length, transaction_callback, &d); |
409 | wait_for_completion(&d.done); | 409 | wait_for_completion(&d.done); |
410 | destroy_timer_on_stack(&t.split_timeout_timer); | 410 | destroy_timer_on_stack(&t.split_timeout_timer); |
411 | 411 | ||
412 | return d.rcode; | 412 | return d.rcode; |
413 | } | 413 | } |
414 | EXPORT_SYMBOL(fw_run_transaction); | 414 | EXPORT_SYMBOL(fw_run_transaction); |
415 | 415 | ||
416 | static DEFINE_MUTEX(phy_config_mutex); | 416 | static DEFINE_MUTEX(phy_config_mutex); |
417 | static DECLARE_COMPLETION(phy_config_done); | 417 | static DECLARE_COMPLETION(phy_config_done); |
418 | 418 | ||
419 | static void transmit_phy_packet_callback(struct fw_packet *packet, | 419 | static void transmit_phy_packet_callback(struct fw_packet *packet, |
420 | struct fw_card *card, int status) | 420 | struct fw_card *card, int status) |
421 | { | 421 | { |
422 | complete(&phy_config_done); | 422 | complete(&phy_config_done); |
423 | } | 423 | } |
424 | 424 | ||
425 | static struct fw_packet phy_config_packet = { | 425 | static struct fw_packet phy_config_packet = { |
426 | .header_length = 8, | 426 | .header_length = 8, |
427 | .payload_length = 0, | 427 | .payload_length = 0, |
428 | .speed = SCODE_100, | 428 | .speed = SCODE_100, |
429 | .callback = transmit_phy_packet_callback, | 429 | .callback = transmit_phy_packet_callback, |
430 | }; | 430 | }; |
431 | 431 | ||
432 | void fw_send_phy_config(struct fw_card *card, | 432 | void fw_send_phy_config(struct fw_card *card, |
433 | int node_id, int generation, int gap_count) | 433 | int node_id, int generation, int gap_count) |
434 | { | 434 | { |
435 | long timeout = DIV_ROUND_UP(HZ, 10); | 435 | long timeout = DIV_ROUND_UP(HZ, 10); |
436 | u32 data = PHY_IDENTIFIER(PHY_PACKET_CONFIG); | 436 | u32 data = PHY_IDENTIFIER(PHY_PACKET_CONFIG); |
437 | 437 | ||
438 | if (node_id != FW_PHY_CONFIG_NO_NODE_ID) | 438 | if (node_id != FW_PHY_CONFIG_NO_NODE_ID) |
439 | data |= PHY_CONFIG_ROOT_ID(node_id); | 439 | data |= PHY_CONFIG_ROOT_ID(node_id); |
440 | 440 | ||
441 | if (gap_count == FW_PHY_CONFIG_CURRENT_GAP_COUNT) { | 441 | if (gap_count == FW_PHY_CONFIG_CURRENT_GAP_COUNT) { |
442 | gap_count = card->driver->read_phy_reg(card, 1); | 442 | gap_count = card->driver->read_phy_reg(card, 1); |
443 | if (gap_count < 0) | 443 | if (gap_count < 0) |
444 | return; | 444 | return; |
445 | 445 | ||
446 | gap_count &= 63; | 446 | gap_count &= 63; |
447 | if (gap_count == 63) | 447 | if (gap_count == 63) |
448 | return; | 448 | return; |
449 | } | 449 | } |
450 | data |= PHY_CONFIG_GAP_COUNT(gap_count); | 450 | data |= PHY_CONFIG_GAP_COUNT(gap_count); |
451 | 451 | ||
452 | mutex_lock(&phy_config_mutex); | 452 | mutex_lock(&phy_config_mutex); |
453 | 453 | ||
454 | phy_config_packet.header[0] = data; | 454 | phy_config_packet.header[0] = data; |
455 | phy_config_packet.header[1] = ~data; | 455 | phy_config_packet.header[1] = ~data; |
456 | phy_config_packet.generation = generation; | 456 | phy_config_packet.generation = generation; |
457 | INIT_COMPLETION(phy_config_done); | 457 | INIT_COMPLETION(phy_config_done); |
458 | 458 | ||
459 | card->driver->send_request(card, &phy_config_packet); | 459 | card->driver->send_request(card, &phy_config_packet); |
460 | wait_for_completion_timeout(&phy_config_done, timeout); | 460 | wait_for_completion_timeout(&phy_config_done, timeout); |
461 | 461 | ||
462 | mutex_unlock(&phy_config_mutex); | 462 | mutex_unlock(&phy_config_mutex); |
463 | } | 463 | } |
464 | 464 | ||
465 | static struct fw_address_handler *lookup_overlapping_address_handler( | 465 | static struct fw_address_handler *lookup_overlapping_address_handler( |
466 | struct list_head *list, unsigned long long offset, size_t length) | 466 | struct list_head *list, unsigned long long offset, size_t length) |
467 | { | 467 | { |
468 | struct fw_address_handler *handler; | 468 | struct fw_address_handler *handler; |
469 | 469 | ||
470 | list_for_each_entry(handler, list, link) { | 470 | list_for_each_entry(handler, list, link) { |
471 | if (handler->offset < offset + length && | 471 | if (handler->offset < offset + length && |
472 | offset < handler->offset + handler->length) | 472 | offset < handler->offset + handler->length) |
473 | return handler; | 473 | return handler; |
474 | } | 474 | } |
475 | 475 | ||
476 | return NULL; | 476 | return NULL; |
477 | } | 477 | } |
478 | 478 | ||
479 | static bool is_enclosing_handler(struct fw_address_handler *handler, | 479 | static bool is_enclosing_handler(struct fw_address_handler *handler, |
480 | unsigned long long offset, size_t length) | 480 | unsigned long long offset, size_t length) |
481 | { | 481 | { |
482 | return handler->offset <= offset && | 482 | return handler->offset <= offset && |
483 | offset + length <= handler->offset + handler->length; | 483 | offset + length <= handler->offset + handler->length; |
484 | } | 484 | } |
485 | 485 | ||
486 | static struct fw_address_handler *lookup_enclosing_address_handler( | 486 | static struct fw_address_handler *lookup_enclosing_address_handler( |
487 | struct list_head *list, unsigned long long offset, size_t length) | 487 | struct list_head *list, unsigned long long offset, size_t length) |
488 | { | 488 | { |
489 | struct fw_address_handler *handler; | 489 | struct fw_address_handler *handler; |
490 | 490 | ||
491 | list_for_each_entry(handler, list, link) { | 491 | list_for_each_entry(handler, list, link) { |
492 | if (is_enclosing_handler(handler, offset, length)) | 492 | if (is_enclosing_handler(handler, offset, length)) |
493 | return handler; | 493 | return handler; |
494 | } | 494 | } |
495 | 495 | ||
496 | return NULL; | 496 | return NULL; |
497 | } | 497 | } |
498 | 498 | ||
499 | static DEFINE_SPINLOCK(address_handler_lock); | 499 | static DEFINE_SPINLOCK(address_handler_lock); |
500 | static LIST_HEAD(address_handler_list); | 500 | static LIST_HEAD(address_handler_list); |
501 | 501 | ||
502 | const struct fw_address_region fw_high_memory_region = | 502 | const struct fw_address_region fw_high_memory_region = |
503 | { .start = 0x000100000000ULL, .end = 0xffffe0000000ULL, }; | 503 | { .start = 0x000100000000ULL, .end = 0xffffe0000000ULL, }; |
504 | EXPORT_SYMBOL(fw_high_memory_region); | 504 | EXPORT_SYMBOL(fw_high_memory_region); |
505 | 505 | ||
506 | #if 0 | 506 | #if 0 |
507 | const struct fw_address_region fw_low_memory_region = | 507 | const struct fw_address_region fw_low_memory_region = |
508 | { .start = 0x000000000000ULL, .end = 0x000100000000ULL, }; | 508 | { .start = 0x000000000000ULL, .end = 0x000100000000ULL, }; |
509 | const struct fw_address_region fw_private_region = | 509 | const struct fw_address_region fw_private_region = |
510 | { .start = 0xffffe0000000ULL, .end = 0xfffff0000000ULL, }; | 510 | { .start = 0xffffe0000000ULL, .end = 0xfffff0000000ULL, }; |
511 | const struct fw_address_region fw_csr_region = | 511 | const struct fw_address_region fw_csr_region = |
512 | { .start = CSR_REGISTER_BASE, | 512 | { .start = CSR_REGISTER_BASE, |
513 | .end = CSR_REGISTER_BASE | CSR_CONFIG_ROM_END, }; | 513 | .end = CSR_REGISTER_BASE | CSR_CONFIG_ROM_END, }; |
514 | const struct fw_address_region fw_unit_space_region = | 514 | const struct fw_address_region fw_unit_space_region = |
515 | { .start = 0xfffff0000900ULL, .end = 0x1000000000000ULL, }; | 515 | { .start = 0xfffff0000900ULL, .end = 0x1000000000000ULL, }; |
516 | #endif /* 0 */ | 516 | #endif /* 0 */ |
517 | 517 | ||
518 | static bool is_in_fcp_region(u64 offset, size_t length) | 518 | static bool is_in_fcp_region(u64 offset, size_t length) |
519 | { | 519 | { |
520 | return offset >= (CSR_REGISTER_BASE | CSR_FCP_COMMAND) && | 520 | return offset >= (CSR_REGISTER_BASE | CSR_FCP_COMMAND) && |
521 | offset + length <= (CSR_REGISTER_BASE | CSR_FCP_END); | 521 | offset + length <= (CSR_REGISTER_BASE | CSR_FCP_END); |
522 | } | 522 | } |
523 | 523 | ||
524 | /** | 524 | /** |
525 | * fw_core_add_address_handler() - register for incoming requests | 525 | * fw_core_add_address_handler() - register for incoming requests |
526 | * @handler: callback | 526 | * @handler: callback |
527 | * @region: region in the IEEE 1212 node space address range | 527 | * @region: region in the IEEE 1212 node space address range |
528 | * | 528 | * |
529 | * region->start, ->end, and handler->length have to be quadlet-aligned. | 529 | * region->start, ->end, and handler->length have to be quadlet-aligned. |
530 | * | 530 | * |
531 | * When a request is received that falls within the specified address range, | 531 | * When a request is received that falls within the specified address range, |
532 | * the specified callback is invoked. The parameters passed to the callback | 532 | * the specified callback is invoked. The parameters passed to the callback |
533 | * give the details of the particular request. | 533 | * give the details of the particular request. |
534 | * | 534 | * |
535 | * Return value: 0 on success, non-zero otherwise. | 535 | * Return value: 0 on success, non-zero otherwise. |
536 | * | 536 | * |
537 | * The start offset of the handler's address region is determined by | 537 | * The start offset of the handler's address region is determined by |
538 | * fw_core_add_address_handler() and is returned in handler->offset. | 538 | * fw_core_add_address_handler() and is returned in handler->offset. |
539 | * | 539 | * |
540 | * Address allocations are exclusive, except for the FCP registers. | 540 | * Address allocations are exclusive, except for the FCP registers. |
541 | */ | 541 | */ |
542 | int fw_core_add_address_handler(struct fw_address_handler *handler, | 542 | int fw_core_add_address_handler(struct fw_address_handler *handler, |
543 | const struct fw_address_region *region) | 543 | const struct fw_address_region *region) |
544 | { | 544 | { |
545 | struct fw_address_handler *other; | 545 | struct fw_address_handler *other; |
546 | unsigned long flags; | 546 | unsigned long flags; |
547 | int ret = -EBUSY; | 547 | int ret = -EBUSY; |
548 | 548 | ||
549 | if (region->start & 0xffff000000000003ULL || | 549 | if (region->start & 0xffff000000000003ULL || |
550 | region->start >= region->end || | 550 | region->start >= region->end || |
551 | region->end > 0x0001000000000000ULL || | 551 | region->end > 0x0001000000000000ULL || |
552 | handler->length & 3 || | 552 | handler->length & 3 || |
553 | handler->length == 0) | 553 | handler->length == 0) |
554 | return -EINVAL; | 554 | return -EINVAL; |
555 | 555 | ||
556 | spin_lock_irqsave(&address_handler_lock, flags); | 556 | spin_lock_irqsave(&address_handler_lock, flags); |
557 | 557 | ||
558 | handler->offset = region->start; | 558 | handler->offset = region->start; |
559 | while (handler->offset + handler->length <= region->end) { | 559 | while (handler->offset + handler->length <= region->end) { |
560 | if (is_in_fcp_region(handler->offset, handler->length)) | 560 | if (is_in_fcp_region(handler->offset, handler->length)) |
561 | other = NULL; | 561 | other = NULL; |
562 | else | 562 | else |
563 | other = lookup_overlapping_address_handler | 563 | other = lookup_overlapping_address_handler |
564 | (&address_handler_list, | 564 | (&address_handler_list, |
565 | handler->offset, handler->length); | 565 | handler->offset, handler->length); |
566 | if (other != NULL) { | 566 | if (other != NULL) { |
567 | handler->offset += other->length; | 567 | handler->offset += other->length; |
568 | } else { | 568 | } else { |
569 | list_add_tail(&handler->link, &address_handler_list); | 569 | list_add_tail(&handler->link, &address_handler_list); |
570 | ret = 0; | 570 | ret = 0; |
571 | break; | 571 | break; |
572 | } | 572 | } |
573 | } | 573 | } |
574 | 574 | ||
575 | spin_unlock_irqrestore(&address_handler_lock, flags); | 575 | spin_unlock_irqrestore(&address_handler_lock, flags); |
576 | 576 | ||
577 | return ret; | 577 | return ret; |
578 | } | 578 | } |
579 | EXPORT_SYMBOL(fw_core_add_address_handler); | 579 | EXPORT_SYMBOL(fw_core_add_address_handler); |
580 | 580 | ||
581 | /** | 581 | /** |
582 | * fw_core_remove_address_handler() - unregister an address handler | 582 | * fw_core_remove_address_handler() - unregister an address handler |
583 | */ | 583 | */ |
584 | void fw_core_remove_address_handler(struct fw_address_handler *handler) | 584 | void fw_core_remove_address_handler(struct fw_address_handler *handler) |
585 | { | 585 | { |
586 | unsigned long flags; | 586 | unsigned long flags; |
587 | 587 | ||
588 | spin_lock_irqsave(&address_handler_lock, flags); | 588 | spin_lock_irqsave(&address_handler_lock, flags); |
589 | list_del(&handler->link); | 589 | list_del(&handler->link); |
590 | spin_unlock_irqrestore(&address_handler_lock, flags); | 590 | spin_unlock_irqrestore(&address_handler_lock, flags); |
591 | } | 591 | } |
592 | EXPORT_SYMBOL(fw_core_remove_address_handler); | 592 | EXPORT_SYMBOL(fw_core_remove_address_handler); |
593 | 593 | ||
594 | struct fw_request { | 594 | struct fw_request { |
595 | struct fw_packet response; | 595 | struct fw_packet response; |
596 | u32 request_header[4]; | 596 | u32 request_header[4]; |
597 | int ack; | 597 | int ack; |
598 | u32 length; | 598 | u32 length; |
599 | u32 data[0]; | 599 | u32 data[0]; |
600 | }; | 600 | }; |
601 | 601 | ||
602 | static void free_response_callback(struct fw_packet *packet, | 602 | static void free_response_callback(struct fw_packet *packet, |
603 | struct fw_card *card, int status) | 603 | struct fw_card *card, int status) |
604 | { | 604 | { |
605 | struct fw_request *request; | 605 | struct fw_request *request; |
606 | 606 | ||
607 | request = container_of(packet, struct fw_request, response); | 607 | request = container_of(packet, struct fw_request, response); |
608 | kfree(request); | 608 | kfree(request); |
609 | } | 609 | } |
610 | 610 | ||
611 | int fw_get_response_length(struct fw_request *r) | 611 | int fw_get_response_length(struct fw_request *r) |
612 | { | 612 | { |
613 | int tcode, ext_tcode, data_length; | 613 | int tcode, ext_tcode, data_length; |
614 | 614 | ||
615 | tcode = HEADER_GET_TCODE(r->request_header[0]); | 615 | tcode = HEADER_GET_TCODE(r->request_header[0]); |
616 | 616 | ||
617 | switch (tcode) { | 617 | switch (tcode) { |
618 | case TCODE_WRITE_QUADLET_REQUEST: | 618 | case TCODE_WRITE_QUADLET_REQUEST: |
619 | case TCODE_WRITE_BLOCK_REQUEST: | 619 | case TCODE_WRITE_BLOCK_REQUEST: |
620 | return 0; | 620 | return 0; |
621 | 621 | ||
622 | case TCODE_READ_QUADLET_REQUEST: | 622 | case TCODE_READ_QUADLET_REQUEST: |
623 | return 4; | 623 | return 4; |
624 | 624 | ||
625 | case TCODE_READ_BLOCK_REQUEST: | 625 | case TCODE_READ_BLOCK_REQUEST: |
626 | data_length = HEADER_GET_DATA_LENGTH(r->request_header[3]); | 626 | data_length = HEADER_GET_DATA_LENGTH(r->request_header[3]); |
627 | return data_length; | 627 | return data_length; |
628 | 628 | ||
629 | case TCODE_LOCK_REQUEST: | 629 | case TCODE_LOCK_REQUEST: |
630 | ext_tcode = HEADER_GET_EXTENDED_TCODE(r->request_header[3]); | 630 | ext_tcode = HEADER_GET_EXTENDED_TCODE(r->request_header[3]); |
631 | data_length = HEADER_GET_DATA_LENGTH(r->request_header[3]); | 631 | data_length = HEADER_GET_DATA_LENGTH(r->request_header[3]); |
632 | switch (ext_tcode) { | 632 | switch (ext_tcode) { |
633 | case EXTCODE_FETCH_ADD: | 633 | case EXTCODE_FETCH_ADD: |
634 | case EXTCODE_LITTLE_ADD: | 634 | case EXTCODE_LITTLE_ADD: |
635 | return data_length; | 635 | return data_length; |
636 | default: | 636 | default: |
637 | return data_length / 2; | 637 | return data_length / 2; |
638 | } | 638 | } |
639 | 639 | ||
640 | default: | 640 | default: |
641 | WARN(1, "wrong tcode %d", tcode); | 641 | WARN(1, "wrong tcode %d\n", tcode); |
642 | return 0; | 642 | return 0; |
643 | } | 643 | } |
644 | } | 644 | } |
645 | 645 | ||
646 | void fw_fill_response(struct fw_packet *response, u32 *request_header, | 646 | void fw_fill_response(struct fw_packet *response, u32 *request_header, |
647 | int rcode, void *payload, size_t length) | 647 | int rcode, void *payload, size_t length) |
648 | { | 648 | { |
649 | int tcode, tlabel, extended_tcode, source, destination; | 649 | int tcode, tlabel, extended_tcode, source, destination; |
650 | 650 | ||
651 | tcode = HEADER_GET_TCODE(request_header[0]); | 651 | tcode = HEADER_GET_TCODE(request_header[0]); |
652 | tlabel = HEADER_GET_TLABEL(request_header[0]); | 652 | tlabel = HEADER_GET_TLABEL(request_header[0]); |
653 | source = HEADER_GET_DESTINATION(request_header[0]); | 653 | source = HEADER_GET_DESTINATION(request_header[0]); |
654 | destination = HEADER_GET_SOURCE(request_header[1]); | 654 | destination = HEADER_GET_SOURCE(request_header[1]); |
655 | extended_tcode = HEADER_GET_EXTENDED_TCODE(request_header[3]); | 655 | extended_tcode = HEADER_GET_EXTENDED_TCODE(request_header[3]); |
656 | 656 | ||
657 | response->header[0] = | 657 | response->header[0] = |
658 | HEADER_RETRY(RETRY_1) | | 658 | HEADER_RETRY(RETRY_1) | |
659 | HEADER_TLABEL(tlabel) | | 659 | HEADER_TLABEL(tlabel) | |
660 | HEADER_DESTINATION(destination); | 660 | HEADER_DESTINATION(destination); |
661 | response->header[1] = | 661 | response->header[1] = |
662 | HEADER_SOURCE(source) | | 662 | HEADER_SOURCE(source) | |
663 | HEADER_RCODE(rcode); | 663 | HEADER_RCODE(rcode); |
664 | response->header[2] = 0; | 664 | response->header[2] = 0; |
665 | 665 | ||
666 | switch (tcode) { | 666 | switch (tcode) { |
667 | case TCODE_WRITE_QUADLET_REQUEST: | 667 | case TCODE_WRITE_QUADLET_REQUEST: |
668 | case TCODE_WRITE_BLOCK_REQUEST: | 668 | case TCODE_WRITE_BLOCK_REQUEST: |
669 | response->header[0] |= HEADER_TCODE(TCODE_WRITE_RESPONSE); | 669 | response->header[0] |= HEADER_TCODE(TCODE_WRITE_RESPONSE); |
670 | response->header_length = 12; | 670 | response->header_length = 12; |
671 | response->payload_length = 0; | 671 | response->payload_length = 0; |
672 | break; | 672 | break; |
673 | 673 | ||
674 | case TCODE_READ_QUADLET_REQUEST: | 674 | case TCODE_READ_QUADLET_REQUEST: |
675 | response->header[0] |= | 675 | response->header[0] |= |
676 | HEADER_TCODE(TCODE_READ_QUADLET_RESPONSE); | 676 | HEADER_TCODE(TCODE_READ_QUADLET_RESPONSE); |
677 | if (payload != NULL) | 677 | if (payload != NULL) |
678 | response->header[3] = *(u32 *)payload; | 678 | response->header[3] = *(u32 *)payload; |
679 | else | 679 | else |
680 | response->header[3] = 0; | 680 | response->header[3] = 0; |
681 | response->header_length = 16; | 681 | response->header_length = 16; |
682 | response->payload_length = 0; | 682 | response->payload_length = 0; |
683 | break; | 683 | break; |
684 | 684 | ||
685 | case TCODE_READ_BLOCK_REQUEST: | 685 | case TCODE_READ_BLOCK_REQUEST: |
686 | case TCODE_LOCK_REQUEST: | 686 | case TCODE_LOCK_REQUEST: |
687 | response->header[0] |= HEADER_TCODE(tcode + 2); | 687 | response->header[0] |= HEADER_TCODE(tcode + 2); |
688 | response->header[3] = | 688 | response->header[3] = |
689 | HEADER_DATA_LENGTH(length) | | 689 | HEADER_DATA_LENGTH(length) | |
690 | HEADER_EXTENDED_TCODE(extended_tcode); | 690 | HEADER_EXTENDED_TCODE(extended_tcode); |
691 | response->header_length = 16; | 691 | response->header_length = 16; |
692 | response->payload = payload; | 692 | response->payload = payload; |
693 | response->payload_length = length; | 693 | response->payload_length = length; |
694 | break; | 694 | break; |
695 | 695 | ||
696 | default: | 696 | default: |
697 | WARN(1, "wrong tcode %d", tcode); | 697 | WARN(1, "wrong tcode %d\n", tcode); |
698 | } | 698 | } |
699 | 699 | ||
700 | response->payload_mapped = false; | 700 | response->payload_mapped = false; |
701 | } | 701 | } |
702 | EXPORT_SYMBOL(fw_fill_response); | 702 | EXPORT_SYMBOL(fw_fill_response); |
703 | 703 | ||
704 | static u32 compute_split_timeout_timestamp(struct fw_card *card, | 704 | static u32 compute_split_timeout_timestamp(struct fw_card *card, |
705 | u32 request_timestamp) | 705 | u32 request_timestamp) |
706 | { | 706 | { |
707 | unsigned int cycles; | 707 | unsigned int cycles; |
708 | u32 timestamp; | 708 | u32 timestamp; |
709 | 709 | ||
710 | cycles = card->split_timeout_cycles; | 710 | cycles = card->split_timeout_cycles; |
711 | cycles += request_timestamp & 0x1fff; | 711 | cycles += request_timestamp & 0x1fff; |
712 | 712 | ||
713 | timestamp = request_timestamp & ~0x1fff; | 713 | timestamp = request_timestamp & ~0x1fff; |
714 | timestamp += (cycles / 8000) << 13; | 714 | timestamp += (cycles / 8000) << 13; |
715 | timestamp |= cycles % 8000; | 715 | timestamp |= cycles % 8000; |
716 | 716 | ||
717 | return timestamp; | 717 | return timestamp; |
718 | } | 718 | } |
719 | 719 | ||
720 | static struct fw_request *allocate_request(struct fw_card *card, | 720 | static struct fw_request *allocate_request(struct fw_card *card, |
721 | struct fw_packet *p) | 721 | struct fw_packet *p) |
722 | { | 722 | { |
723 | struct fw_request *request; | 723 | struct fw_request *request; |
724 | u32 *data, length; | 724 | u32 *data, length; |
725 | int request_tcode; | 725 | int request_tcode; |
726 | 726 | ||
727 | request_tcode = HEADER_GET_TCODE(p->header[0]); | 727 | request_tcode = HEADER_GET_TCODE(p->header[0]); |
728 | switch (request_tcode) { | 728 | switch (request_tcode) { |
729 | case TCODE_WRITE_QUADLET_REQUEST: | 729 | case TCODE_WRITE_QUADLET_REQUEST: |
730 | data = &p->header[3]; | 730 | data = &p->header[3]; |
731 | length = 4; | 731 | length = 4; |
732 | break; | 732 | break; |
733 | 733 | ||
734 | case TCODE_WRITE_BLOCK_REQUEST: | 734 | case TCODE_WRITE_BLOCK_REQUEST: |
735 | case TCODE_LOCK_REQUEST: | 735 | case TCODE_LOCK_REQUEST: |
736 | data = p->payload; | 736 | data = p->payload; |
737 | length = HEADER_GET_DATA_LENGTH(p->header[3]); | 737 | length = HEADER_GET_DATA_LENGTH(p->header[3]); |
738 | break; | 738 | break; |
739 | 739 | ||
740 | case TCODE_READ_QUADLET_REQUEST: | 740 | case TCODE_READ_QUADLET_REQUEST: |
741 | data = NULL; | 741 | data = NULL; |
742 | length = 4; | 742 | length = 4; |
743 | break; | 743 | break; |
744 | 744 | ||
745 | case TCODE_READ_BLOCK_REQUEST: | 745 | case TCODE_READ_BLOCK_REQUEST: |
746 | data = NULL; | 746 | data = NULL; |
747 | length = HEADER_GET_DATA_LENGTH(p->header[3]); | 747 | length = HEADER_GET_DATA_LENGTH(p->header[3]); |
748 | break; | 748 | break; |
749 | 749 | ||
750 | default: | 750 | default: |
751 | fw_error("ERROR - corrupt request received - %08x %08x %08x\n", | 751 | fw_error("ERROR - corrupt request received - %08x %08x %08x\n", |
752 | p->header[0], p->header[1], p->header[2]); | 752 | p->header[0], p->header[1], p->header[2]); |
753 | return NULL; | 753 | return NULL; |
754 | } | 754 | } |
755 | 755 | ||
756 | request = kmalloc(sizeof(*request) + length, GFP_ATOMIC); | 756 | request = kmalloc(sizeof(*request) + length, GFP_ATOMIC); |
757 | if (request == NULL) | 757 | if (request == NULL) |
758 | return NULL; | 758 | return NULL; |
759 | 759 | ||
760 | request->response.speed = p->speed; | 760 | request->response.speed = p->speed; |
761 | request->response.timestamp = | 761 | request->response.timestamp = |
762 | compute_split_timeout_timestamp(card, p->timestamp); | 762 | compute_split_timeout_timestamp(card, p->timestamp); |
763 | request->response.generation = p->generation; | 763 | request->response.generation = p->generation; |
764 | request->response.ack = 0; | 764 | request->response.ack = 0; |
765 | request->response.callback = free_response_callback; | 765 | request->response.callback = free_response_callback; |
766 | request->ack = p->ack; | 766 | request->ack = p->ack; |
767 | request->length = length; | 767 | request->length = length; |
768 | if (data) | 768 | if (data) |
769 | memcpy(request->data, data, length); | 769 | memcpy(request->data, data, length); |
770 | 770 | ||
771 | memcpy(request->request_header, p->header, sizeof(p->header)); | 771 | memcpy(request->request_header, p->header, sizeof(p->header)); |
772 | 772 | ||
773 | return request; | 773 | return request; |
774 | } | 774 | } |
775 | 775 | ||
776 | void fw_send_response(struct fw_card *card, | 776 | void fw_send_response(struct fw_card *card, |
777 | struct fw_request *request, int rcode) | 777 | struct fw_request *request, int rcode) |
778 | { | 778 | { |
779 | if (WARN_ONCE(!request, "invalid for FCP address handlers")) | 779 | if (WARN_ONCE(!request, "invalid for FCP address handlers")) |
780 | return; | 780 | return; |
781 | 781 | ||
782 | /* unified transaction or broadcast transaction: don't respond */ | 782 | /* unified transaction or broadcast transaction: don't respond */ |
783 | if (request->ack != ACK_PENDING || | 783 | if (request->ack != ACK_PENDING || |
784 | HEADER_DESTINATION_IS_BROADCAST(request->request_header[0])) { | 784 | HEADER_DESTINATION_IS_BROADCAST(request->request_header[0])) { |
785 | kfree(request); | 785 | kfree(request); |
786 | return; | 786 | return; |
787 | } | 787 | } |
788 | 788 | ||
789 | if (rcode == RCODE_COMPLETE) | 789 | if (rcode == RCODE_COMPLETE) |
790 | fw_fill_response(&request->response, request->request_header, | 790 | fw_fill_response(&request->response, request->request_header, |
791 | rcode, request->data, | 791 | rcode, request->data, |
792 | fw_get_response_length(request)); | 792 | fw_get_response_length(request)); |
793 | else | 793 | else |
794 | fw_fill_response(&request->response, request->request_header, | 794 | fw_fill_response(&request->response, request->request_header, |
795 | rcode, NULL, 0); | 795 | rcode, NULL, 0); |
796 | 796 | ||
797 | card->driver->send_response(card, &request->response); | 797 | card->driver->send_response(card, &request->response); |
798 | } | 798 | } |
799 | EXPORT_SYMBOL(fw_send_response); | 799 | EXPORT_SYMBOL(fw_send_response); |
800 | 800 | ||
801 | static void handle_exclusive_region_request(struct fw_card *card, | 801 | static void handle_exclusive_region_request(struct fw_card *card, |
802 | struct fw_packet *p, | 802 | struct fw_packet *p, |
803 | struct fw_request *request, | 803 | struct fw_request *request, |
804 | unsigned long long offset) | 804 | unsigned long long offset) |
805 | { | 805 | { |
806 | struct fw_address_handler *handler; | 806 | struct fw_address_handler *handler; |
807 | unsigned long flags; | 807 | unsigned long flags; |
808 | int tcode, destination, source; | 808 | int tcode, destination, source; |
809 | 809 | ||
810 | destination = HEADER_GET_DESTINATION(p->header[0]); | 810 | destination = HEADER_GET_DESTINATION(p->header[0]); |
811 | source = HEADER_GET_SOURCE(p->header[1]); | 811 | source = HEADER_GET_SOURCE(p->header[1]); |
812 | tcode = HEADER_GET_TCODE(p->header[0]); | 812 | tcode = HEADER_GET_TCODE(p->header[0]); |
813 | if (tcode == TCODE_LOCK_REQUEST) | 813 | if (tcode == TCODE_LOCK_REQUEST) |
814 | tcode = 0x10 + HEADER_GET_EXTENDED_TCODE(p->header[3]); | 814 | tcode = 0x10 + HEADER_GET_EXTENDED_TCODE(p->header[3]); |
815 | 815 | ||
816 | spin_lock_irqsave(&address_handler_lock, flags); | 816 | spin_lock_irqsave(&address_handler_lock, flags); |
817 | handler = lookup_enclosing_address_handler(&address_handler_list, | 817 | handler = lookup_enclosing_address_handler(&address_handler_list, |
818 | offset, request->length); | 818 | offset, request->length); |
819 | spin_unlock_irqrestore(&address_handler_lock, flags); | 819 | spin_unlock_irqrestore(&address_handler_lock, flags); |
820 | 820 | ||
821 | /* | 821 | /* |
822 | * FIXME: lookup the fw_node corresponding to the sender of | 822 | * FIXME: lookup the fw_node corresponding to the sender of |
823 | * this request and pass that to the address handler instead | 823 | * this request and pass that to the address handler instead |
824 | * of the node ID. We may also want to move the address | 824 | * of the node ID. We may also want to move the address |
825 | * allocations to fw_node so we only do this callback if the | 825 | * allocations to fw_node so we only do this callback if the |
826 | * upper layers registered it for this node. | 826 | * upper layers registered it for this node. |
827 | */ | 827 | */ |
828 | 828 | ||
829 | if (handler == NULL) | 829 | if (handler == NULL) |
830 | fw_send_response(card, request, RCODE_ADDRESS_ERROR); | 830 | fw_send_response(card, request, RCODE_ADDRESS_ERROR); |
831 | else | 831 | else |
832 | handler->address_callback(card, request, | 832 | handler->address_callback(card, request, |
833 | tcode, destination, source, | 833 | tcode, destination, source, |
834 | p->generation, offset, | 834 | p->generation, offset, |
835 | request->data, request->length, | 835 | request->data, request->length, |
836 | handler->callback_data); | 836 | handler->callback_data); |
837 | } | 837 | } |
838 | 838 | ||
839 | static void handle_fcp_region_request(struct fw_card *card, | 839 | static void handle_fcp_region_request(struct fw_card *card, |
840 | struct fw_packet *p, | 840 | struct fw_packet *p, |
841 | struct fw_request *request, | 841 | struct fw_request *request, |
842 | unsigned long long offset) | 842 | unsigned long long offset) |
843 | { | 843 | { |
844 | struct fw_address_handler *handler; | 844 | struct fw_address_handler *handler; |
845 | unsigned long flags; | 845 | unsigned long flags; |
846 | int tcode, destination, source; | 846 | int tcode, destination, source; |
847 | 847 | ||
848 | if ((offset != (CSR_REGISTER_BASE | CSR_FCP_COMMAND) && | 848 | if ((offset != (CSR_REGISTER_BASE | CSR_FCP_COMMAND) && |
849 | offset != (CSR_REGISTER_BASE | CSR_FCP_RESPONSE)) || | 849 | offset != (CSR_REGISTER_BASE | CSR_FCP_RESPONSE)) || |
850 | request->length > 0x200) { | 850 | request->length > 0x200) { |
851 | fw_send_response(card, request, RCODE_ADDRESS_ERROR); | 851 | fw_send_response(card, request, RCODE_ADDRESS_ERROR); |
852 | 852 | ||
853 | return; | 853 | return; |
854 | } | 854 | } |
855 | 855 | ||
856 | tcode = HEADER_GET_TCODE(p->header[0]); | 856 | tcode = HEADER_GET_TCODE(p->header[0]); |
857 | destination = HEADER_GET_DESTINATION(p->header[0]); | 857 | destination = HEADER_GET_DESTINATION(p->header[0]); |
858 | source = HEADER_GET_SOURCE(p->header[1]); | 858 | source = HEADER_GET_SOURCE(p->header[1]); |
859 | 859 | ||
860 | if (tcode != TCODE_WRITE_QUADLET_REQUEST && | 860 | if (tcode != TCODE_WRITE_QUADLET_REQUEST && |
861 | tcode != TCODE_WRITE_BLOCK_REQUEST) { | 861 | tcode != TCODE_WRITE_BLOCK_REQUEST) { |
862 | fw_send_response(card, request, RCODE_TYPE_ERROR); | 862 | fw_send_response(card, request, RCODE_TYPE_ERROR); |
863 | 863 | ||
864 | return; | 864 | return; |
865 | } | 865 | } |
866 | 866 | ||
867 | spin_lock_irqsave(&address_handler_lock, flags); | 867 | spin_lock_irqsave(&address_handler_lock, flags); |
868 | list_for_each_entry(handler, &address_handler_list, link) { | 868 | list_for_each_entry(handler, &address_handler_list, link) { |
869 | if (is_enclosing_handler(handler, offset, request->length)) | 869 | if (is_enclosing_handler(handler, offset, request->length)) |
870 | handler->address_callback(card, NULL, tcode, | 870 | handler->address_callback(card, NULL, tcode, |
871 | destination, source, | 871 | destination, source, |
872 | p->generation, offset, | 872 | p->generation, offset, |
873 | request->data, | 873 | request->data, |
874 | request->length, | 874 | request->length, |
875 | handler->callback_data); | 875 | handler->callback_data); |
876 | } | 876 | } |
877 | spin_unlock_irqrestore(&address_handler_lock, flags); | 877 | spin_unlock_irqrestore(&address_handler_lock, flags); |
878 | 878 | ||
879 | fw_send_response(card, request, RCODE_COMPLETE); | 879 | fw_send_response(card, request, RCODE_COMPLETE); |
880 | } | 880 | } |
881 | 881 | ||
882 | void fw_core_handle_request(struct fw_card *card, struct fw_packet *p) | 882 | void fw_core_handle_request(struct fw_card *card, struct fw_packet *p) |
883 | { | 883 | { |
884 | struct fw_request *request; | 884 | struct fw_request *request; |
885 | unsigned long long offset; | 885 | unsigned long long offset; |
886 | 886 | ||
887 | if (p->ack != ACK_PENDING && p->ack != ACK_COMPLETE) | 887 | if (p->ack != ACK_PENDING && p->ack != ACK_COMPLETE) |
888 | return; | 888 | return; |
889 | 889 | ||
890 | if (TCODE_IS_LINK_INTERNAL(HEADER_GET_TCODE(p->header[0]))) { | 890 | if (TCODE_IS_LINK_INTERNAL(HEADER_GET_TCODE(p->header[0]))) { |
891 | fw_cdev_handle_phy_packet(card, p); | 891 | fw_cdev_handle_phy_packet(card, p); |
892 | return; | 892 | return; |
893 | } | 893 | } |
894 | 894 | ||
895 | request = allocate_request(card, p); | 895 | request = allocate_request(card, p); |
896 | if (request == NULL) { | 896 | if (request == NULL) { |
897 | /* FIXME: send statically allocated busy packet. */ | 897 | /* FIXME: send statically allocated busy packet. */ |
898 | return; | 898 | return; |
899 | } | 899 | } |
900 | 900 | ||
901 | offset = ((u64)HEADER_GET_OFFSET_HIGH(p->header[1]) << 32) | | 901 | offset = ((u64)HEADER_GET_OFFSET_HIGH(p->header[1]) << 32) | |
902 | p->header[2]; | 902 | p->header[2]; |
903 | 903 | ||
904 | if (!is_in_fcp_region(offset, request->length)) | 904 | if (!is_in_fcp_region(offset, request->length)) |
905 | handle_exclusive_region_request(card, p, request, offset); | 905 | handle_exclusive_region_request(card, p, request, offset); |
906 | else | 906 | else |
907 | handle_fcp_region_request(card, p, request, offset); | 907 | handle_fcp_region_request(card, p, request, offset); |
908 | 908 | ||
909 | } | 909 | } |
910 | EXPORT_SYMBOL(fw_core_handle_request); | 910 | EXPORT_SYMBOL(fw_core_handle_request); |
911 | 911 | ||
912 | void fw_core_handle_response(struct fw_card *card, struct fw_packet *p) | 912 | void fw_core_handle_response(struct fw_card *card, struct fw_packet *p) |
913 | { | 913 | { |
914 | struct fw_transaction *t; | 914 | struct fw_transaction *t; |
915 | unsigned long flags; | 915 | unsigned long flags; |
916 | u32 *data; | 916 | u32 *data; |
917 | size_t data_length; | 917 | size_t data_length; |
918 | int tcode, tlabel, source, rcode; | 918 | int tcode, tlabel, source, rcode; |
919 | 919 | ||
920 | tcode = HEADER_GET_TCODE(p->header[0]); | 920 | tcode = HEADER_GET_TCODE(p->header[0]); |
921 | tlabel = HEADER_GET_TLABEL(p->header[0]); | 921 | tlabel = HEADER_GET_TLABEL(p->header[0]); |
922 | source = HEADER_GET_SOURCE(p->header[1]); | 922 | source = HEADER_GET_SOURCE(p->header[1]); |
923 | rcode = HEADER_GET_RCODE(p->header[1]); | 923 | rcode = HEADER_GET_RCODE(p->header[1]); |
924 | 924 | ||
925 | spin_lock_irqsave(&card->lock, flags); | 925 | spin_lock_irqsave(&card->lock, flags); |
926 | list_for_each_entry(t, &card->transaction_list, link) { | 926 | list_for_each_entry(t, &card->transaction_list, link) { |
927 | if (t->node_id == source && t->tlabel == tlabel) { | 927 | if (t->node_id == source && t->tlabel == tlabel) { |
928 | if (!del_timer(&t->split_timeout_timer)) { | 928 | if (!del_timer(&t->split_timeout_timer)) { |
929 | spin_unlock_irqrestore(&card->lock, flags); | 929 | spin_unlock_irqrestore(&card->lock, flags); |
930 | goto timed_out; | 930 | goto timed_out; |
931 | } | 931 | } |
932 | list_del_init(&t->link); | 932 | list_del_init(&t->link); |
933 | card->tlabel_mask &= ~(1ULL << t->tlabel); | 933 | card->tlabel_mask &= ~(1ULL << t->tlabel); |
934 | break; | 934 | break; |
935 | } | 935 | } |
936 | } | 936 | } |
937 | spin_unlock_irqrestore(&card->lock, flags); | 937 | spin_unlock_irqrestore(&card->lock, flags); |
938 | 938 | ||
939 | if (&t->link == &card->transaction_list) { | 939 | if (&t->link == &card->transaction_list) { |
940 | timed_out: | 940 | timed_out: |
941 | fw_notify("Unsolicited response (source %x, tlabel %x)\n", | 941 | fw_notify("Unsolicited response (source %x, tlabel %x)\n", |
942 | source, tlabel); | 942 | source, tlabel); |
943 | return; | 943 | return; |
944 | } | 944 | } |
945 | 945 | ||
946 | /* | 946 | /* |
947 | * FIXME: sanity check packet, is length correct, does tcodes | 947 | * FIXME: sanity check packet, is length correct, does tcodes |
948 | * and addresses match. | 948 | * and addresses match. |
949 | */ | 949 | */ |
950 | 950 | ||
951 | switch (tcode) { | 951 | switch (tcode) { |
952 | case TCODE_READ_QUADLET_RESPONSE: | 952 | case TCODE_READ_QUADLET_RESPONSE: |
953 | data = (u32 *) &p->header[3]; | 953 | data = (u32 *) &p->header[3]; |
954 | data_length = 4; | 954 | data_length = 4; |
955 | break; | 955 | break; |
956 | 956 | ||
957 | case TCODE_WRITE_RESPONSE: | 957 | case TCODE_WRITE_RESPONSE: |
958 | data = NULL; | 958 | data = NULL; |
959 | data_length = 0; | 959 | data_length = 0; |
960 | break; | 960 | break; |
961 | 961 | ||
962 | case TCODE_READ_BLOCK_RESPONSE: | 962 | case TCODE_READ_BLOCK_RESPONSE: |
963 | case TCODE_LOCK_RESPONSE: | 963 | case TCODE_LOCK_RESPONSE: |
964 | data = p->payload; | 964 | data = p->payload; |
965 | data_length = HEADER_GET_DATA_LENGTH(p->header[3]); | 965 | data_length = HEADER_GET_DATA_LENGTH(p->header[3]); |
966 | break; | 966 | break; |
967 | 967 | ||
968 | default: | 968 | default: |
969 | /* Should never happen, this is just to shut up gcc. */ | 969 | /* Should never happen, this is just to shut up gcc. */ |
970 | data = NULL; | 970 | data = NULL; |
971 | data_length = 0; | 971 | data_length = 0; |
972 | break; | 972 | break; |
973 | } | 973 | } |
974 | 974 | ||
975 | /* | 975 | /* |
976 | * The response handler may be executed while the request handler | 976 | * The response handler may be executed while the request handler |
977 | * is still pending. Cancel the request handler. | 977 | * is still pending. Cancel the request handler. |
978 | */ | 978 | */ |
979 | card->driver->cancel_packet(card, &t->packet); | 979 | card->driver->cancel_packet(card, &t->packet); |
980 | 980 | ||
981 | t->callback(card, rcode, data, data_length, t->callback_data); | 981 | t->callback(card, rcode, data, data_length, t->callback_data); |
982 | } | 982 | } |
983 | EXPORT_SYMBOL(fw_core_handle_response); | 983 | EXPORT_SYMBOL(fw_core_handle_response); |
984 | 984 | ||
985 | static const struct fw_address_region topology_map_region = | 985 | static const struct fw_address_region topology_map_region = |
986 | { .start = CSR_REGISTER_BASE | CSR_TOPOLOGY_MAP, | 986 | { .start = CSR_REGISTER_BASE | CSR_TOPOLOGY_MAP, |
987 | .end = CSR_REGISTER_BASE | CSR_TOPOLOGY_MAP_END, }; | 987 | .end = CSR_REGISTER_BASE | CSR_TOPOLOGY_MAP_END, }; |
988 | 988 | ||
989 | static void handle_topology_map(struct fw_card *card, struct fw_request *request, | 989 | static void handle_topology_map(struct fw_card *card, struct fw_request *request, |
990 | int tcode, int destination, int source, int generation, | 990 | int tcode, int destination, int source, int generation, |
991 | unsigned long long offset, void *payload, size_t length, | 991 | unsigned long long offset, void *payload, size_t length, |
992 | void *callback_data) | 992 | void *callback_data) |
993 | { | 993 | { |
994 | int start; | 994 | int start; |
995 | 995 | ||
996 | if (!TCODE_IS_READ_REQUEST(tcode)) { | 996 | if (!TCODE_IS_READ_REQUEST(tcode)) { |
997 | fw_send_response(card, request, RCODE_TYPE_ERROR); | 997 | fw_send_response(card, request, RCODE_TYPE_ERROR); |
998 | return; | 998 | return; |
999 | } | 999 | } |
1000 | 1000 | ||
1001 | if ((offset & 3) > 0 || (length & 3) > 0) { | 1001 | if ((offset & 3) > 0 || (length & 3) > 0) { |
1002 | fw_send_response(card, request, RCODE_ADDRESS_ERROR); | 1002 | fw_send_response(card, request, RCODE_ADDRESS_ERROR); |
1003 | return; | 1003 | return; |
1004 | } | 1004 | } |
1005 | 1005 | ||
1006 | start = (offset - topology_map_region.start) / 4; | 1006 | start = (offset - topology_map_region.start) / 4; |
1007 | memcpy(payload, &card->topology_map[start], length); | 1007 | memcpy(payload, &card->topology_map[start], length); |
1008 | 1008 | ||
1009 | fw_send_response(card, request, RCODE_COMPLETE); | 1009 | fw_send_response(card, request, RCODE_COMPLETE); |
1010 | } | 1010 | } |
1011 | 1011 | ||
1012 | static struct fw_address_handler topology_map = { | 1012 | static struct fw_address_handler topology_map = { |
1013 | .length = 0x400, | 1013 | .length = 0x400, |
1014 | .address_callback = handle_topology_map, | 1014 | .address_callback = handle_topology_map, |
1015 | }; | 1015 | }; |
1016 | 1016 | ||
1017 | static const struct fw_address_region registers_region = | 1017 | static const struct fw_address_region registers_region = |
1018 | { .start = CSR_REGISTER_BASE, | 1018 | { .start = CSR_REGISTER_BASE, |
1019 | .end = CSR_REGISTER_BASE | CSR_CONFIG_ROM, }; | 1019 | .end = CSR_REGISTER_BASE | CSR_CONFIG_ROM, }; |
1020 | 1020 | ||
1021 | static void update_split_timeout(struct fw_card *card) | 1021 | static void update_split_timeout(struct fw_card *card) |
1022 | { | 1022 | { |
1023 | unsigned int cycles; | 1023 | unsigned int cycles; |
1024 | 1024 | ||
1025 | cycles = card->split_timeout_hi * 8000 + (card->split_timeout_lo >> 19); | 1025 | cycles = card->split_timeout_hi * 8000 + (card->split_timeout_lo >> 19); |
1026 | 1026 | ||
1027 | cycles = max(cycles, 800u); /* minimum as per the spec */ | 1027 | cycles = max(cycles, 800u); /* minimum as per the spec */ |
1028 | cycles = min(cycles, 3u * 8000u); /* maximum OHCI timeout */ | 1028 | cycles = min(cycles, 3u * 8000u); /* maximum OHCI timeout */ |
1029 | 1029 | ||
1030 | card->split_timeout_cycles = cycles; | 1030 | card->split_timeout_cycles = cycles; |
1031 | card->split_timeout_jiffies = DIV_ROUND_UP(cycles * HZ, 8000); | 1031 | card->split_timeout_jiffies = DIV_ROUND_UP(cycles * HZ, 8000); |
1032 | } | 1032 | } |
1033 | 1033 | ||
1034 | static void handle_registers(struct fw_card *card, struct fw_request *request, | 1034 | static void handle_registers(struct fw_card *card, struct fw_request *request, |
1035 | int tcode, int destination, int source, int generation, | 1035 | int tcode, int destination, int source, int generation, |
1036 | unsigned long long offset, void *payload, size_t length, | 1036 | unsigned long long offset, void *payload, size_t length, |
1037 | void *callback_data) | 1037 | void *callback_data) |
1038 | { | 1038 | { |
1039 | int reg = offset & ~CSR_REGISTER_BASE; | 1039 | int reg = offset & ~CSR_REGISTER_BASE; |
1040 | __be32 *data = payload; | 1040 | __be32 *data = payload; |
1041 | int rcode = RCODE_COMPLETE; | 1041 | int rcode = RCODE_COMPLETE; |
1042 | unsigned long flags; | 1042 | unsigned long flags; |
1043 | 1043 | ||
1044 | switch (reg) { | 1044 | switch (reg) { |
1045 | case CSR_PRIORITY_BUDGET: | 1045 | case CSR_PRIORITY_BUDGET: |
1046 | if (!card->priority_budget_implemented) { | 1046 | if (!card->priority_budget_implemented) { |
1047 | rcode = RCODE_ADDRESS_ERROR; | 1047 | rcode = RCODE_ADDRESS_ERROR; |
1048 | break; | 1048 | break; |
1049 | } | 1049 | } |
1050 | /* else fall through */ | 1050 | /* else fall through */ |
1051 | 1051 | ||
1052 | case CSR_NODE_IDS: | 1052 | case CSR_NODE_IDS: |
1053 | /* | 1053 | /* |
1054 | * per IEEE 1394-2008 8.3.22.3, not IEEE 1394.1-2004 3.2.8 | 1054 | * per IEEE 1394-2008 8.3.22.3, not IEEE 1394.1-2004 3.2.8 |
1055 | * and 9.6, but interoperable with IEEE 1394.1-2004 bridges | 1055 | * and 9.6, but interoperable with IEEE 1394.1-2004 bridges |
1056 | */ | 1056 | */ |
1057 | /* fall through */ | 1057 | /* fall through */ |
1058 | 1058 | ||
1059 | case CSR_STATE_CLEAR: | 1059 | case CSR_STATE_CLEAR: |
1060 | case CSR_STATE_SET: | 1060 | case CSR_STATE_SET: |
1061 | case CSR_CYCLE_TIME: | 1061 | case CSR_CYCLE_TIME: |
1062 | case CSR_BUS_TIME: | 1062 | case CSR_BUS_TIME: |
1063 | case CSR_BUSY_TIMEOUT: | 1063 | case CSR_BUSY_TIMEOUT: |
1064 | if (tcode == TCODE_READ_QUADLET_REQUEST) | 1064 | if (tcode == TCODE_READ_QUADLET_REQUEST) |
1065 | *data = cpu_to_be32(card->driver->read_csr(card, reg)); | 1065 | *data = cpu_to_be32(card->driver->read_csr(card, reg)); |
1066 | else if (tcode == TCODE_WRITE_QUADLET_REQUEST) | 1066 | else if (tcode == TCODE_WRITE_QUADLET_REQUEST) |
1067 | card->driver->write_csr(card, reg, be32_to_cpu(*data)); | 1067 | card->driver->write_csr(card, reg, be32_to_cpu(*data)); |
1068 | else | 1068 | else |
1069 | rcode = RCODE_TYPE_ERROR; | 1069 | rcode = RCODE_TYPE_ERROR; |
1070 | break; | 1070 | break; |
1071 | 1071 | ||
1072 | case CSR_RESET_START: | 1072 | case CSR_RESET_START: |
1073 | if (tcode == TCODE_WRITE_QUADLET_REQUEST) | 1073 | if (tcode == TCODE_WRITE_QUADLET_REQUEST) |
1074 | card->driver->write_csr(card, CSR_STATE_CLEAR, | 1074 | card->driver->write_csr(card, CSR_STATE_CLEAR, |
1075 | CSR_STATE_BIT_ABDICATE); | 1075 | CSR_STATE_BIT_ABDICATE); |
1076 | else | 1076 | else |
1077 | rcode = RCODE_TYPE_ERROR; | 1077 | rcode = RCODE_TYPE_ERROR; |
1078 | break; | 1078 | break; |
1079 | 1079 | ||
1080 | case CSR_SPLIT_TIMEOUT_HI: | 1080 | case CSR_SPLIT_TIMEOUT_HI: |
1081 | if (tcode == TCODE_READ_QUADLET_REQUEST) { | 1081 | if (tcode == TCODE_READ_QUADLET_REQUEST) { |
1082 | *data = cpu_to_be32(card->split_timeout_hi); | 1082 | *data = cpu_to_be32(card->split_timeout_hi); |
1083 | } else if (tcode == TCODE_WRITE_QUADLET_REQUEST) { | 1083 | } else if (tcode == TCODE_WRITE_QUADLET_REQUEST) { |
1084 | spin_lock_irqsave(&card->lock, flags); | 1084 | spin_lock_irqsave(&card->lock, flags); |
1085 | card->split_timeout_hi = be32_to_cpu(*data) & 7; | 1085 | card->split_timeout_hi = be32_to_cpu(*data) & 7; |
1086 | update_split_timeout(card); | 1086 | update_split_timeout(card); |
1087 | spin_unlock_irqrestore(&card->lock, flags); | 1087 | spin_unlock_irqrestore(&card->lock, flags); |
1088 | } else { | 1088 | } else { |
1089 | rcode = RCODE_TYPE_ERROR; | 1089 | rcode = RCODE_TYPE_ERROR; |
1090 | } | 1090 | } |
1091 | break; | 1091 | break; |
1092 | 1092 | ||
1093 | case CSR_SPLIT_TIMEOUT_LO: | 1093 | case CSR_SPLIT_TIMEOUT_LO: |
1094 | if (tcode == TCODE_READ_QUADLET_REQUEST) { | 1094 | if (tcode == TCODE_READ_QUADLET_REQUEST) { |
1095 | *data = cpu_to_be32(card->split_timeout_lo); | 1095 | *data = cpu_to_be32(card->split_timeout_lo); |
1096 | } else if (tcode == TCODE_WRITE_QUADLET_REQUEST) { | 1096 | } else if (tcode == TCODE_WRITE_QUADLET_REQUEST) { |
1097 | spin_lock_irqsave(&card->lock, flags); | 1097 | spin_lock_irqsave(&card->lock, flags); |
1098 | card->split_timeout_lo = | 1098 | card->split_timeout_lo = |
1099 | be32_to_cpu(*data) & 0xfff80000; | 1099 | be32_to_cpu(*data) & 0xfff80000; |
1100 | update_split_timeout(card); | 1100 | update_split_timeout(card); |
1101 | spin_unlock_irqrestore(&card->lock, flags); | 1101 | spin_unlock_irqrestore(&card->lock, flags); |
1102 | } else { | 1102 | } else { |
1103 | rcode = RCODE_TYPE_ERROR; | 1103 | rcode = RCODE_TYPE_ERROR; |
1104 | } | 1104 | } |
1105 | break; | 1105 | break; |
1106 | 1106 | ||
1107 | case CSR_MAINT_UTILITY: | 1107 | case CSR_MAINT_UTILITY: |
1108 | if (tcode == TCODE_READ_QUADLET_REQUEST) | 1108 | if (tcode == TCODE_READ_QUADLET_REQUEST) |
1109 | *data = card->maint_utility_register; | 1109 | *data = card->maint_utility_register; |
1110 | else if (tcode == TCODE_WRITE_QUADLET_REQUEST) | 1110 | else if (tcode == TCODE_WRITE_QUADLET_REQUEST) |
1111 | card->maint_utility_register = *data; | 1111 | card->maint_utility_register = *data; |
1112 | else | 1112 | else |
1113 | rcode = RCODE_TYPE_ERROR; | 1113 | rcode = RCODE_TYPE_ERROR; |
1114 | break; | 1114 | break; |
1115 | 1115 | ||
1116 | case CSR_BROADCAST_CHANNEL: | 1116 | case CSR_BROADCAST_CHANNEL: |
1117 | if (tcode == TCODE_READ_QUADLET_REQUEST) | 1117 | if (tcode == TCODE_READ_QUADLET_REQUEST) |
1118 | *data = cpu_to_be32(card->broadcast_channel); | 1118 | *data = cpu_to_be32(card->broadcast_channel); |
1119 | else if (tcode == TCODE_WRITE_QUADLET_REQUEST) | 1119 | else if (tcode == TCODE_WRITE_QUADLET_REQUEST) |
1120 | card->broadcast_channel = | 1120 | card->broadcast_channel = |
1121 | (be32_to_cpu(*data) & BROADCAST_CHANNEL_VALID) | | 1121 | (be32_to_cpu(*data) & BROADCAST_CHANNEL_VALID) | |
1122 | BROADCAST_CHANNEL_INITIAL; | 1122 | BROADCAST_CHANNEL_INITIAL; |
1123 | else | 1123 | else |
1124 | rcode = RCODE_TYPE_ERROR; | 1124 | rcode = RCODE_TYPE_ERROR; |
1125 | break; | 1125 | break; |
1126 | 1126 | ||
1127 | case CSR_BUS_MANAGER_ID: | 1127 | case CSR_BUS_MANAGER_ID: |
1128 | case CSR_BANDWIDTH_AVAILABLE: | 1128 | case CSR_BANDWIDTH_AVAILABLE: |
1129 | case CSR_CHANNELS_AVAILABLE_HI: | 1129 | case CSR_CHANNELS_AVAILABLE_HI: |
1130 | case CSR_CHANNELS_AVAILABLE_LO: | 1130 | case CSR_CHANNELS_AVAILABLE_LO: |
1131 | /* | 1131 | /* |
1132 | * FIXME: these are handled by the OHCI hardware and | 1132 | * FIXME: these are handled by the OHCI hardware and |
1133 | * the stack never sees these request. If we add | 1133 | * the stack never sees these request. If we add |
1134 | * support for a new type of controller that doesn't | 1134 | * support for a new type of controller that doesn't |
1135 | * handle this in hardware we need to deal with these | 1135 | * handle this in hardware we need to deal with these |
1136 | * transactions. | 1136 | * transactions. |
1137 | */ | 1137 | */ |
1138 | BUG(); | 1138 | BUG(); |
1139 | break; | 1139 | break; |
1140 | 1140 | ||
1141 | default: | 1141 | default: |
1142 | rcode = RCODE_ADDRESS_ERROR; | 1142 | rcode = RCODE_ADDRESS_ERROR; |
1143 | break; | 1143 | break; |
1144 | } | 1144 | } |
1145 | 1145 | ||
1146 | fw_send_response(card, request, rcode); | 1146 | fw_send_response(card, request, rcode); |
1147 | } | 1147 | } |
1148 | 1148 | ||
1149 | static struct fw_address_handler registers = { | 1149 | static struct fw_address_handler registers = { |
1150 | .length = 0x400, | 1150 | .length = 0x400, |
1151 | .address_callback = handle_registers, | 1151 | .address_callback = handle_registers, |
1152 | }; | 1152 | }; |
1153 | 1153 | ||
1154 | MODULE_AUTHOR("Kristian Hoegsberg <krh@bitplanet.net>"); | 1154 | MODULE_AUTHOR("Kristian Hoegsberg <krh@bitplanet.net>"); |
1155 | MODULE_DESCRIPTION("Core IEEE1394 transaction logic"); | 1155 | MODULE_DESCRIPTION("Core IEEE1394 transaction logic"); |
1156 | MODULE_LICENSE("GPL"); | 1156 | MODULE_LICENSE("GPL"); |
1157 | 1157 | ||
1158 | static const u32 vendor_textual_descriptor[] = { | 1158 | static const u32 vendor_textual_descriptor[] = { |
1159 | /* textual descriptor leaf () */ | 1159 | /* textual descriptor leaf () */ |
1160 | 0x00060000, | 1160 | 0x00060000, |
1161 | 0x00000000, | 1161 | 0x00000000, |
1162 | 0x00000000, | 1162 | 0x00000000, |
1163 | 0x4c696e75, /* L i n u */ | 1163 | 0x4c696e75, /* L i n u */ |
1164 | 0x78204669, /* x F i */ | 1164 | 0x78204669, /* x F i */ |
1165 | 0x72657769, /* r e w i */ | 1165 | 0x72657769, /* r e w i */ |
1166 | 0x72650000, /* r e */ | 1166 | 0x72650000, /* r e */ |
1167 | }; | 1167 | }; |
1168 | 1168 | ||
1169 | static const u32 model_textual_descriptor[] = { | 1169 | static const u32 model_textual_descriptor[] = { |
1170 | /* model descriptor leaf () */ | 1170 | /* model descriptor leaf () */ |
1171 | 0x00030000, | 1171 | 0x00030000, |
1172 | 0x00000000, | 1172 | 0x00000000, |
1173 | 0x00000000, | 1173 | 0x00000000, |
1174 | 0x4a756a75, /* J u j u */ | 1174 | 0x4a756a75, /* J u j u */ |
1175 | }; | 1175 | }; |
1176 | 1176 | ||
1177 | static struct fw_descriptor vendor_id_descriptor = { | 1177 | static struct fw_descriptor vendor_id_descriptor = { |
1178 | .length = ARRAY_SIZE(vendor_textual_descriptor), | 1178 | .length = ARRAY_SIZE(vendor_textual_descriptor), |
1179 | .immediate = 0x03d00d1e, | 1179 | .immediate = 0x03d00d1e, |
1180 | .key = 0x81000000, | 1180 | .key = 0x81000000, |
1181 | .data = vendor_textual_descriptor, | 1181 | .data = vendor_textual_descriptor, |
1182 | }; | 1182 | }; |
1183 | 1183 | ||
1184 | static struct fw_descriptor model_id_descriptor = { | 1184 | static struct fw_descriptor model_id_descriptor = { |
1185 | .length = ARRAY_SIZE(model_textual_descriptor), | 1185 | .length = ARRAY_SIZE(model_textual_descriptor), |
1186 | .immediate = 0x17000001, | 1186 | .immediate = 0x17000001, |
1187 | .key = 0x81000000, | 1187 | .key = 0x81000000, |
1188 | .data = model_textual_descriptor, | 1188 | .data = model_textual_descriptor, |
1189 | }; | 1189 | }; |
1190 | 1190 | ||
1191 | static int __init fw_core_init(void) | 1191 | static int __init fw_core_init(void) |
1192 | { | 1192 | { |
1193 | int ret; | 1193 | int ret; |
1194 | 1194 | ||
1195 | ret = bus_register(&fw_bus_type); | 1195 | ret = bus_register(&fw_bus_type); |
1196 | if (ret < 0) | 1196 | if (ret < 0) |
1197 | return ret; | 1197 | return ret; |
1198 | 1198 | ||
1199 | fw_cdev_major = register_chrdev(0, "firewire", &fw_device_ops); | 1199 | fw_cdev_major = register_chrdev(0, "firewire", &fw_device_ops); |
1200 | if (fw_cdev_major < 0) { | 1200 | if (fw_cdev_major < 0) { |
1201 | bus_unregister(&fw_bus_type); | 1201 | bus_unregister(&fw_bus_type); |
1202 | return fw_cdev_major; | 1202 | return fw_cdev_major; |
1203 | } | 1203 | } |
1204 | 1204 | ||
1205 | fw_core_add_address_handler(&topology_map, &topology_map_region); | 1205 | fw_core_add_address_handler(&topology_map, &topology_map_region); |
1206 | fw_core_add_address_handler(®isters, ®isters_region); | 1206 | fw_core_add_address_handler(®isters, ®isters_region); |
1207 | fw_core_add_descriptor(&vendor_id_descriptor); | 1207 | fw_core_add_descriptor(&vendor_id_descriptor); |
1208 | fw_core_add_descriptor(&model_id_descriptor); | 1208 | fw_core_add_descriptor(&model_id_descriptor); |
1209 | 1209 | ||
1210 | return 0; | 1210 | return 0; |
1211 | } | 1211 | } |
1212 | 1212 | ||
1213 | static void __exit fw_core_cleanup(void) | 1213 | static void __exit fw_core_cleanup(void) |
1214 | { | 1214 | { |
1215 | unregister_chrdev(fw_cdev_major, "firewire"); | 1215 | unregister_chrdev(fw_cdev_major, "firewire"); |
1216 | bus_unregister(&fw_bus_type); | 1216 | bus_unregister(&fw_bus_type); |
1217 | idr_destroy(&fw_device_idr); | 1217 | idr_destroy(&fw_device_idr); |
1218 | } | 1218 | } |
1219 | 1219 | ||
1220 | module_init(fw_core_init); | 1220 | module_init(fw_core_init); |
1221 | module_exit(fw_core_cleanup); | 1221 | module_exit(fw_core_cleanup); |
1222 | 1222 |