diff options
author | Clemens Ladisch <clemens@ladisch.de> | 2010-06-10 02:26:28 -0400 |
---|---|---|
committer | Clemens Ladisch <clemens@ladisch.de> | 2010-06-10 02:26:28 -0400 |
commit | 8e4b50f94e8c1435a3e0ece42b7f97bc857d0145 (patch) | |
tree | aad5b85a0bf67b5a7bbd80e1dad2d2a2d9b85470 /drivers/firewire | |
parent | 446eba0d6896787b2f02f7a665838d32aa7b9d3f (diff) |
firewire: core: add CSR SPLIT_TIMEOUT support
Implement the SPLIT_TIMEOUT registers. Besides being required by the
spec, this is desirable for some IIDC devices and necessary for many
audio devices to be able to increase the timeout from userspace.
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Diffstat (limited to 'drivers/firewire')
-rw-r--r-- | drivers/firewire/core-card.c | 4 | ||||
-rw-r--r-- | drivers/firewire/core-transaction.c | 76 |
2 files changed, 69 insertions, 11 deletions
diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c index 901435cdd5c2..d0f15c2f1e1d 100644 --- a/drivers/firewire/core-card.c +++ b/drivers/firewire/core-card.c | |||
@@ -428,6 +428,10 @@ void fw_card_initialize(struct fw_card *card, | |||
428 | card->device = device; | 428 | card->device = device; |
429 | card->current_tlabel = 0; | 429 | card->current_tlabel = 0; |
430 | card->tlabel_mask = 0; | 430 | card->tlabel_mask = 0; |
431 | card->split_timeout_hi = 0; | ||
432 | card->split_timeout_lo = 800 << 19; | ||
433 | card->split_timeout_cycles = 800; | ||
434 | card->split_timeout_jiffies = DIV_ROUND_UP(HZ, 10); | ||
431 | card->color = 0; | 435 | card->color = 0; |
432 | card->broadcast_channel = BROADCAST_CHANNEL_INITIAL; | 436 | card->broadcast_channel = BROADCAST_CHANNEL_INITIAL; |
433 | 437 | ||
diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index 0034229dfd14..9a7d3ec23f2b 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c | |||
@@ -339,7 +339,8 @@ void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode, | |||
339 | setup_timer(&t->split_timeout_timer, | 339 | setup_timer(&t->split_timeout_timer, |
340 | split_transaction_timeout_callback, (unsigned long)t); | 340 | split_transaction_timeout_callback, (unsigned long)t); |
341 | /* FIXME: start this timer later, relative to t->timestamp */ | 341 | /* FIXME: start this timer later, relative to t->timestamp */ |
342 | mod_timer(&t->split_timeout_timer, jiffies + DIV_ROUND_UP(HZ, 10)); | 342 | mod_timer(&t->split_timeout_timer, |
343 | jiffies + card->split_timeout_jiffies); | ||
343 | t->callback = callback; | 344 | t->callback = callback; |
344 | t->callback_data = callback_data; | 345 | t->callback_data = callback_data; |
345 | 346 | ||
@@ -673,11 +674,28 @@ void fw_fill_response(struct fw_packet *response, u32 *request_header, | |||
673 | } | 674 | } |
674 | EXPORT_SYMBOL(fw_fill_response); | 675 | EXPORT_SYMBOL(fw_fill_response); |
675 | 676 | ||
676 | static struct fw_request *allocate_request(struct fw_packet *p) | 677 | static u32 compute_split_timeout_timestamp(struct fw_card *card, |
678 | u32 request_timestamp) | ||
679 | { | ||
680 | unsigned int cycles; | ||
681 | u32 timestamp; | ||
682 | |||
683 | cycles = card->split_timeout_cycles; | ||
684 | cycles += request_timestamp & 0x1fff; | ||
685 | |||
686 | timestamp = request_timestamp & ~0x1fff; | ||
687 | timestamp += (cycles / 8000) << 13; | ||
688 | timestamp |= cycles % 8000; | ||
689 | |||
690 | return timestamp; | ||
691 | } | ||
692 | |||
693 | static struct fw_request *allocate_request(struct fw_card *card, | ||
694 | struct fw_packet *p) | ||
677 | { | 695 | { |
678 | struct fw_request *request; | 696 | struct fw_request *request; |
679 | u32 *data, length; | 697 | u32 *data, length; |
680 | int request_tcode, t; | 698 | int request_tcode; |
681 | 699 | ||
682 | request_tcode = HEADER_GET_TCODE(p->header[0]); | 700 | request_tcode = HEADER_GET_TCODE(p->header[0]); |
683 | switch (request_tcode) { | 701 | switch (request_tcode) { |
@@ -712,14 +730,9 @@ static struct fw_request *allocate_request(struct fw_packet *p) | |||
712 | if (request == NULL) | 730 | if (request == NULL) |
713 | return NULL; | 731 | return NULL; |
714 | 732 | ||
715 | t = (p->timestamp & 0x1fff) + 4000; | ||
716 | if (t >= 8000) | ||
717 | t = (p->timestamp & ~0x1fff) + 0x2000 + t - 8000; | ||
718 | else | ||
719 | t = (p->timestamp & ~0x1fff) + t; | ||
720 | |||
721 | request->response.speed = p->speed; | 733 | request->response.speed = p->speed; |
722 | request->response.timestamp = t; | 734 | request->response.timestamp = |
735 | compute_split_timeout_timestamp(card, p->timestamp); | ||
723 | request->response.generation = p->generation; | 736 | request->response.generation = p->generation; |
724 | request->response.ack = 0; | 737 | request->response.ack = 0; |
725 | request->response.callback = free_response_callback; | 738 | request->response.callback = free_response_callback; |
@@ -845,7 +858,7 @@ void fw_core_handle_request(struct fw_card *card, struct fw_packet *p) | |||
845 | if (p->ack != ACK_PENDING && p->ack != ACK_COMPLETE) | 858 | if (p->ack != ACK_PENDING && p->ack != ACK_COMPLETE) |
846 | return; | 859 | return; |
847 | 860 | ||
848 | request = allocate_request(p); | 861 | request = allocate_request(card, p); |
849 | if (request == NULL) { | 862 | if (request == NULL) { |
850 | /* FIXME: send statically allocated busy packet. */ | 863 | /* FIXME: send statically allocated busy packet. */ |
851 | return; | 864 | return; |
@@ -993,6 +1006,19 @@ static u32 read_state_register(struct fw_card *card) | |||
993 | return 0; | 1006 | return 0; |
994 | } | 1007 | } |
995 | 1008 | ||
1009 | static void update_split_timeout(struct fw_card *card) | ||
1010 | { | ||
1011 | unsigned int cycles; | ||
1012 | |||
1013 | cycles = card->split_timeout_hi * 8000 + (card->split_timeout_lo >> 19); | ||
1014 | |||
1015 | cycles = max(cycles, 800u); /* minimum as per the spec */ | ||
1016 | cycles = min(cycles, 3u * 8000u); /* maximum OHCI timeout */ | ||
1017 | |||
1018 | card->split_timeout_cycles = cycles; | ||
1019 | card->split_timeout_jiffies = DIV_ROUND_UP(cycles * HZ, 8000); | ||
1020 | } | ||
1021 | |||
996 | static void handle_registers(struct fw_card *card, struct fw_request *request, | 1022 | static void handle_registers(struct fw_card *card, struct fw_request *request, |
997 | int tcode, int destination, int source, int generation, | 1023 | int tcode, int destination, int source, int generation, |
998 | int speed, unsigned long long offset, | 1024 | int speed, unsigned long long offset, |
@@ -1001,6 +1027,7 @@ static void handle_registers(struct fw_card *card, struct fw_request *request, | |||
1001 | int reg = offset & ~CSR_REGISTER_BASE; | 1027 | int reg = offset & ~CSR_REGISTER_BASE; |
1002 | __be32 *data = payload; | 1028 | __be32 *data = payload; |
1003 | int rcode = RCODE_COMPLETE; | 1029 | int rcode = RCODE_COMPLETE; |
1030 | unsigned long flags; | ||
1004 | 1031 | ||
1005 | switch (reg) { | 1032 | switch (reg) { |
1006 | case CSR_STATE_CLEAR: | 1033 | case CSR_STATE_CLEAR: |
@@ -1039,6 +1066,33 @@ static void handle_registers(struct fw_card *card, struct fw_request *request, | |||
1039 | rcode = RCODE_TYPE_ERROR; | 1066 | rcode = RCODE_TYPE_ERROR; |
1040 | break; | 1067 | break; |
1041 | 1068 | ||
1069 | case CSR_SPLIT_TIMEOUT_HI: | ||
1070 | if (tcode == TCODE_READ_QUADLET_REQUEST) { | ||
1071 | *data = cpu_to_be32(card->split_timeout_hi); | ||
1072 | } else if (tcode == TCODE_WRITE_QUADLET_REQUEST) { | ||
1073 | spin_lock_irqsave(&card->lock, flags); | ||
1074 | card->split_timeout_hi = be32_to_cpu(*data) & 7; | ||
1075 | update_split_timeout(card); | ||
1076 | spin_unlock_irqrestore(&card->lock, flags); | ||
1077 | } else { | ||
1078 | rcode = RCODE_TYPE_ERROR; | ||
1079 | } | ||
1080 | break; | ||
1081 | |||
1082 | case CSR_SPLIT_TIMEOUT_LO: | ||
1083 | if (tcode == TCODE_READ_QUADLET_REQUEST) { | ||
1084 | *data = cpu_to_be32(card->split_timeout_lo); | ||
1085 | } else if (tcode == TCODE_WRITE_QUADLET_REQUEST) { | ||
1086 | spin_lock_irqsave(&card->lock, flags); | ||
1087 | card->split_timeout_lo = | ||
1088 | be32_to_cpu(*data) & 0xfff80000; | ||
1089 | update_split_timeout(card); | ||
1090 | spin_unlock_irqrestore(&card->lock, flags); | ||
1091 | } else { | ||
1092 | rcode = RCODE_TYPE_ERROR; | ||
1093 | } | ||
1094 | break; | ||
1095 | |||
1042 | case CSR_CYCLE_TIME: | 1096 | case CSR_CYCLE_TIME: |
1043 | if (TCODE_IS_READ_REQUEST(tcode) && length == 4) | 1097 | if (TCODE_IS_READ_REQUEST(tcode) && length == 4) |
1044 | *data = cpu_to_be32(card->driver-> | 1098 | *data = cpu_to_be32(card->driver-> |