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) |
