diff options
Diffstat (limited to 'drivers/firewire/fw-transaction.c')
-rw-r--r-- | drivers/firewire/fw-transaction.c | 79 |
1 files changed, 30 insertions, 49 deletions
diff --git a/drivers/firewire/fw-transaction.c b/drivers/firewire/fw-transaction.c index 40db80752272..e5d1a0b64fcf 100644 --- a/drivers/firewire/fw-transaction.c +++ b/drivers/firewire/fw-transaction.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/kernel.h> | 22 | #include <linux/kernel.h> |
23 | #include <linux/kref.h> | 23 | #include <linux/kref.h> |
24 | #include <linux/module.h> | 24 | #include <linux/module.h> |
25 | #include <linux/mutex.h> | ||
25 | #include <linux/init.h> | 26 | #include <linux/init.h> |
26 | #include <linux/interrupt.h> | 27 | #include <linux/interrupt.h> |
27 | #include <linux/pci.h> | 28 | #include <linux/pci.h> |
@@ -151,7 +152,7 @@ transmit_complete_callback(struct fw_packet *packet, | |||
151 | 152 | ||
152 | static void | 153 | static void |
153 | fw_fill_request(struct fw_packet *packet, int tcode, int tlabel, | 154 | fw_fill_request(struct fw_packet *packet, int tcode, int tlabel, |
154 | int node_id, int source_id, int generation, int speed, | 155 | int destination_id, int source_id, int generation, int speed, |
155 | unsigned long long offset, void *payload, size_t length) | 156 | unsigned long long offset, void *payload, size_t length) |
156 | { | 157 | { |
157 | int ext_tcode; | 158 | int ext_tcode; |
@@ -166,7 +167,7 @@ fw_fill_request(struct fw_packet *packet, int tcode, int tlabel, | |||
166 | HEADER_RETRY(RETRY_X) | | 167 | HEADER_RETRY(RETRY_X) | |
167 | HEADER_TLABEL(tlabel) | | 168 | HEADER_TLABEL(tlabel) | |
168 | HEADER_TCODE(tcode) | | 169 | HEADER_TCODE(tcode) | |
169 | HEADER_DESTINATION(node_id); | 170 | HEADER_DESTINATION(destination_id); |
170 | packet->header[1] = | 171 | packet->header[1] = |
171 | HEADER_OFFSET_HIGH(offset >> 32) | HEADER_SOURCE(source_id); | 172 | HEADER_OFFSET_HIGH(offset >> 32) | HEADER_SOURCE(source_id); |
172 | packet->header[2] = | 173 | packet->header[2] = |
@@ -252,7 +253,7 @@ fw_send_request(struct fw_card *card, struct fw_transaction *t, | |||
252 | fw_transaction_callback_t callback, void *callback_data) | 253 | fw_transaction_callback_t callback, void *callback_data) |
253 | { | 254 | { |
254 | unsigned long flags; | 255 | unsigned long flags; |
255 | int tlabel, source; | 256 | int tlabel; |
256 | 257 | ||
257 | /* | 258 | /* |
258 | * Bump the flush timer up 100ms first of all so we | 259 | * Bump the flush timer up 100ms first of all so we |
@@ -268,7 +269,6 @@ fw_send_request(struct fw_card *card, struct fw_transaction *t, | |||
268 | 269 | ||
269 | spin_lock_irqsave(&card->lock, flags); | 270 | spin_lock_irqsave(&card->lock, flags); |
270 | 271 | ||
271 | source = card->node_id; | ||
272 | tlabel = card->current_tlabel; | 272 | tlabel = card->current_tlabel; |
273 | if (card->tlabel_mask & (1 << tlabel)) { | 273 | if (card->tlabel_mask & (1 << tlabel)) { |
274 | spin_unlock_irqrestore(&card->lock, flags); | 274 | spin_unlock_irqrestore(&card->lock, flags); |
@@ -279,77 +279,58 @@ fw_send_request(struct fw_card *card, struct fw_transaction *t, | |||
279 | card->current_tlabel = (card->current_tlabel + 1) & 0x1f; | 279 | card->current_tlabel = (card->current_tlabel + 1) & 0x1f; |
280 | card->tlabel_mask |= (1 << tlabel); | 280 | card->tlabel_mask |= (1 << tlabel); |
281 | 281 | ||
282 | list_add_tail(&t->link, &card->transaction_list); | ||
283 | |||
284 | spin_unlock_irqrestore(&card->lock, flags); | ||
285 | |||
286 | /* Initialize rest of transaction, fill out packet and send it. */ | ||
287 | t->node_id = node_id; | 282 | t->node_id = node_id; |
288 | t->tlabel = tlabel; | 283 | t->tlabel = tlabel; |
289 | t->callback = callback; | 284 | t->callback = callback; |
290 | t->callback_data = callback_data; | 285 | t->callback_data = callback_data; |
291 | 286 | ||
292 | fw_fill_request(&t->packet, tcode, t->tlabel, | 287 | fw_fill_request(&t->packet, tcode, t->tlabel, node_id, card->node_id, |
293 | node_id, source, generation, | 288 | generation, speed, offset, payload, length); |
294 | speed, offset, payload, length); | ||
295 | t->packet.callback = transmit_complete_callback; | 289 | t->packet.callback = transmit_complete_callback; |
296 | 290 | ||
291 | list_add_tail(&t->link, &card->transaction_list); | ||
292 | |||
293 | spin_unlock_irqrestore(&card->lock, flags); | ||
294 | |||
297 | card->driver->send_request(card, &t->packet); | 295 | card->driver->send_request(card, &t->packet); |
298 | } | 296 | } |
299 | EXPORT_SYMBOL(fw_send_request); | 297 | EXPORT_SYMBOL(fw_send_request); |
300 | 298 | ||
301 | struct fw_phy_packet { | 299 | static DEFINE_MUTEX(phy_config_mutex); |
302 | struct fw_packet packet; | 300 | static DECLARE_COMPLETION(phy_config_done); |
303 | struct completion done; | ||
304 | struct kref kref; | ||
305 | }; | ||
306 | |||
307 | static void phy_packet_release(struct kref *kref) | ||
308 | { | ||
309 | struct fw_phy_packet *p = | ||
310 | container_of(kref, struct fw_phy_packet, kref); | ||
311 | kfree(p); | ||
312 | } | ||
313 | 301 | ||
314 | static void transmit_phy_packet_callback(struct fw_packet *packet, | 302 | static void transmit_phy_packet_callback(struct fw_packet *packet, |
315 | struct fw_card *card, int status) | 303 | struct fw_card *card, int status) |
316 | { | 304 | { |
317 | struct fw_phy_packet *p = | 305 | complete(&phy_config_done); |
318 | container_of(packet, struct fw_phy_packet, packet); | ||
319 | |||
320 | complete(&p->done); | ||
321 | kref_put(&p->kref, phy_packet_release); | ||
322 | } | 306 | } |
323 | 307 | ||
308 | static struct fw_packet phy_config_packet = { | ||
309 | .header_length = 8, | ||
310 | .payload_length = 0, | ||
311 | .speed = SCODE_100, | ||
312 | .callback = transmit_phy_packet_callback, | ||
313 | }; | ||
314 | |||
324 | void fw_send_phy_config(struct fw_card *card, | 315 | void fw_send_phy_config(struct fw_card *card, |
325 | int node_id, int generation, int gap_count) | 316 | int node_id, int generation, int gap_count) |
326 | { | 317 | { |
327 | struct fw_phy_packet *p; | ||
328 | long timeout = DIV_ROUND_UP(HZ, 10); | 318 | long timeout = DIV_ROUND_UP(HZ, 10); |
329 | u32 data = PHY_IDENTIFIER(PHY_PACKET_CONFIG) | | 319 | u32 data = PHY_IDENTIFIER(PHY_PACKET_CONFIG) | |
330 | PHY_CONFIG_ROOT_ID(node_id) | | 320 | PHY_CONFIG_ROOT_ID(node_id) | |
331 | PHY_CONFIG_GAP_COUNT(gap_count); | 321 | PHY_CONFIG_GAP_COUNT(gap_count); |
332 | 322 | ||
333 | p = kmalloc(sizeof(*p), GFP_KERNEL); | 323 | mutex_lock(&phy_config_mutex); |
334 | if (p == NULL) | 324 | |
335 | return; | 325 | phy_config_packet.header[0] = data; |
326 | phy_config_packet.header[1] = ~data; | ||
327 | phy_config_packet.generation = generation; | ||
328 | INIT_COMPLETION(phy_config_done); | ||
329 | |||
330 | card->driver->send_request(card, &phy_config_packet); | ||
331 | wait_for_completion_timeout(&phy_config_done, timeout); | ||
336 | 332 | ||
337 | p->packet.header[0] = data; | 333 | mutex_unlock(&phy_config_mutex); |
338 | p->packet.header[1] = ~data; | ||
339 | p->packet.header_length = 8; | ||
340 | p->packet.payload_length = 0; | ||
341 | p->packet.speed = SCODE_100; | ||
342 | p->packet.generation = generation; | ||
343 | p->packet.callback = transmit_phy_packet_callback; | ||
344 | init_completion(&p->done); | ||
345 | kref_set(&p->kref, 2); | ||
346 | |||
347 | card->driver->send_request(card, &p->packet); | ||
348 | timeout = wait_for_completion_timeout(&p->done, timeout); | ||
349 | kref_put(&p->kref, phy_packet_release); | ||
350 | |||
351 | /* will leak p if the callback is never executed */ | ||
352 | WARN_ON(timeout == 0); | ||
353 | } | 334 | } |
354 | 335 | ||
355 | void fw_flush_transactions(struct fw_card *card) | 336 | void fw_flush_transactions(struct fw_card *card) |