diff options
Diffstat (limited to 'drivers/ieee1394/ieee1394_transactions.c')
| -rw-r--r-- | drivers/ieee1394/ieee1394_transactions.c | 114 |
1 files changed, 66 insertions, 48 deletions
diff --git a/drivers/ieee1394/ieee1394_transactions.c b/drivers/ieee1394/ieee1394_transactions.c index a114b91d606d..0833fc9f50c4 100644 --- a/drivers/ieee1394/ieee1394_transactions.c +++ b/drivers/ieee1394/ieee1394_transactions.c | |||
| @@ -9,19 +9,17 @@ | |||
| 9 | * directory of the kernel sources for details. | 9 | * directory of the kernel sources for details. |
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | #include <linux/sched.h> | ||
| 13 | #include <linux/bitops.h> | 12 | #include <linux/bitops.h> |
| 14 | #include <linux/smp_lock.h> | 13 | #include <linux/spinlock.h> |
| 15 | #include <linux/interrupt.h> | 14 | #include <linux/wait.h> |
| 16 | 15 | ||
| 16 | #include <asm/bug.h> | ||
| 17 | #include <asm/errno.h> | 17 | #include <asm/errno.h> |
| 18 | 18 | ||
| 19 | #include "ieee1394.h" | 19 | #include "ieee1394.h" |
| 20 | #include "ieee1394_types.h" | 20 | #include "ieee1394_types.h" |
| 21 | #include "hosts.h" | 21 | #include "hosts.h" |
| 22 | #include "ieee1394_core.h" | 22 | #include "ieee1394_core.h" |
| 23 | #include "highlevel.h" | ||
| 24 | #include "nodemgr.h" | ||
| 25 | #include "ieee1394_transactions.h" | 23 | #include "ieee1394_transactions.h" |
| 26 | 24 | ||
| 27 | #define PREP_ASYNC_HEAD_ADDRESS(tc) \ | 25 | #define PREP_ASYNC_HEAD_ADDRESS(tc) \ |
| @@ -31,6 +29,13 @@ | |||
| 31 | packet->header[1] = (packet->host->node_id << 16) | (addr >> 32); \ | 29 | packet->header[1] = (packet->host->node_id << 16) | (addr >> 32); \ |
| 32 | packet->header[2] = addr & 0xffffffff | 30 | packet->header[2] = addr & 0xffffffff |
| 33 | 31 | ||
| 32 | #ifndef HPSB_DEBUG_TLABELS | ||
| 33 | static | ||
| 34 | #endif | ||
| 35 | spinlock_t hpsb_tlabel_lock = SPIN_LOCK_UNLOCKED; | ||
| 36 | |||
| 37 | static DECLARE_WAIT_QUEUE_HEAD(tlabel_wq); | ||
| 38 | |||
| 34 | static void fill_async_readquad(struct hpsb_packet *packet, u64 addr) | 39 | static void fill_async_readquad(struct hpsb_packet *packet, u64 addr) |
| 35 | { | 40 | { |
| 36 | PREP_ASYNC_HEAD_ADDRESS(TCODE_READQ); | 41 | PREP_ASYNC_HEAD_ADDRESS(TCODE_READQ); |
| @@ -114,9 +119,41 @@ static void fill_async_stream_packet(struct hpsb_packet *packet, int length, | |||
| 114 | packet->tcode = TCODE_ISO_DATA; | 119 | packet->tcode = TCODE_ISO_DATA; |
| 115 | } | 120 | } |
| 116 | 121 | ||
| 122 | /* same as hpsb_get_tlabel, except that it returns immediately */ | ||
| 123 | static int hpsb_get_tlabel_atomic(struct hpsb_packet *packet) | ||
| 124 | { | ||
| 125 | unsigned long flags, *tp; | ||
| 126 | u8 *next; | ||
| 127 | int tlabel, n = NODEID_TO_NODE(packet->node_id); | ||
| 128 | |||
| 129 | /* Broadcast transactions are complete once the request has been sent. | ||
| 130 | * Use the same transaction label for all broadcast transactions. */ | ||
| 131 | if (unlikely(n == ALL_NODES)) { | ||
| 132 | packet->tlabel = 0; | ||
| 133 | return 0; | ||
| 134 | } | ||
| 135 | tp = packet->host->tl_pool[n].map; | ||
| 136 | next = &packet->host->next_tl[n]; | ||
| 137 | |||
| 138 | spin_lock_irqsave(&hpsb_tlabel_lock, flags); | ||
| 139 | tlabel = find_next_zero_bit(tp, 64, *next); | ||
| 140 | if (tlabel > 63) | ||
| 141 | tlabel = find_first_zero_bit(tp, 64); | ||
| 142 | if (tlabel > 63) { | ||
| 143 | spin_unlock_irqrestore(&hpsb_tlabel_lock, flags); | ||
| 144 | return -EAGAIN; | ||
| 145 | } | ||
| 146 | __set_bit(tlabel, tp); | ||
| 147 | *next = (tlabel + 1) & 63; | ||
| 148 | spin_unlock_irqrestore(&hpsb_tlabel_lock, flags); | ||
| 149 | |||
| 150 | packet->tlabel = tlabel; | ||
| 151 | return 0; | ||
| 152 | } | ||
| 153 | |||
| 117 | /** | 154 | /** |
| 118 | * hpsb_get_tlabel - allocate a transaction label | 155 | * hpsb_get_tlabel - allocate a transaction label |
| 119 | * @packet: the packet who's tlabel/tpool we set | 156 | * @packet: the packet whose tlabel and tl_pool we set |
| 120 | * | 157 | * |
| 121 | * Every asynchronous transaction on the 1394 bus needs a transaction | 158 | * Every asynchronous transaction on the 1394 bus needs a transaction |
| 122 | * label to match the response to the request. This label has to be | 159 | * label to match the response to the request. This label has to be |
| @@ -130,42 +167,25 @@ static void fill_async_stream_packet(struct hpsb_packet *packet, int length, | |||
| 130 | * Return value: Zero on success, otherwise non-zero. A non-zero return | 167 | * Return value: Zero on success, otherwise non-zero. A non-zero return |
| 131 | * generally means there are no available tlabels. If this is called out | 168 | * generally means there are no available tlabels. If this is called out |
| 132 | * of interrupt or atomic context, then it will sleep until can return a | 169 | * of interrupt or atomic context, then it will sleep until can return a |
| 133 | * tlabel. | 170 | * tlabel or a signal is received. |
| 134 | */ | 171 | */ |
| 135 | int hpsb_get_tlabel(struct hpsb_packet *packet) | 172 | int hpsb_get_tlabel(struct hpsb_packet *packet) |
| 136 | { | 173 | { |
| 137 | unsigned long flags; | 174 | if (irqs_disabled() || in_atomic()) |
| 138 | struct hpsb_tlabel_pool *tp; | 175 | return hpsb_get_tlabel_atomic(packet); |
| 139 | int n = NODEID_TO_NODE(packet->node_id); | 176 | |
| 140 | 177 | /* NB: The macro wait_event_interruptible() is called with a condition | |
| 141 | if (unlikely(n == ALL_NODES)) | 178 | * argument with side effect. This is only possible because the side |
| 142 | return 0; | 179 | * effect does not occur until the condition became true, and |
| 143 | tp = &packet->host->tpool[n]; | 180 | * wait_event_interruptible() won't evaluate the condition again after |
| 144 | 181 | * that. */ | |
| 145 | if (irqs_disabled() || in_atomic()) { | 182 | return wait_event_interruptible(tlabel_wq, |
| 146 | if (down_trylock(&tp->count)) | 183 | !hpsb_get_tlabel_atomic(packet)); |
| 147 | return 1; | ||
| 148 | } else { | ||
| 149 | down(&tp->count); | ||
| 150 | } | ||
| 151 | |||
| 152 | spin_lock_irqsave(&tp->lock, flags); | ||
| 153 | |||
| 154 | packet->tlabel = find_next_zero_bit(tp->pool, 64, tp->next); | ||
| 155 | if (packet->tlabel > 63) | ||
| 156 | packet->tlabel = find_first_zero_bit(tp->pool, 64); | ||
| 157 | tp->next = (packet->tlabel + 1) % 64; | ||
| 158 | /* Should _never_ happen */ | ||
| 159 | BUG_ON(test_and_set_bit(packet->tlabel, tp->pool)); | ||
| 160 | tp->allocations++; | ||
| 161 | spin_unlock_irqrestore(&tp->lock, flags); | ||
| 162 | |||
| 163 | return 0; | ||
| 164 | } | 184 | } |
| 165 | 185 | ||
| 166 | /** | 186 | /** |
| 167 | * hpsb_free_tlabel - free an allocated transaction label | 187 | * hpsb_free_tlabel - free an allocated transaction label |
| 168 | * @packet: packet whos tlabel/tpool needs to be cleared | 188 | * @packet: packet whose tlabel and tl_pool needs to be cleared |
| 169 | * | 189 | * |
| 170 | * Frees the transaction label allocated with hpsb_get_tlabel(). The | 190 | * Frees the transaction label allocated with hpsb_get_tlabel(). The |
| 171 | * tlabel has to be freed after the transaction is complete (i.e. response | 191 | * tlabel has to be freed after the transaction is complete (i.e. response |
| @@ -176,21 +196,20 @@ int hpsb_get_tlabel(struct hpsb_packet *packet) | |||
| 176 | */ | 196 | */ |
| 177 | void hpsb_free_tlabel(struct hpsb_packet *packet) | 197 | void hpsb_free_tlabel(struct hpsb_packet *packet) |
| 178 | { | 198 | { |
| 179 | unsigned long flags; | 199 | unsigned long flags, *tp; |
| 180 | struct hpsb_tlabel_pool *tp; | 200 | int tlabel, n = NODEID_TO_NODE(packet->node_id); |
| 181 | int n = NODEID_TO_NODE(packet->node_id); | ||
| 182 | 201 | ||
| 183 | if (unlikely(n == ALL_NODES)) | 202 | if (unlikely(n == ALL_NODES)) |
| 184 | return; | 203 | return; |
| 185 | tp = &packet->host->tpool[n]; | 204 | tp = packet->host->tl_pool[n].map; |
| 205 | tlabel = packet->tlabel; | ||
| 206 | BUG_ON(tlabel > 63 || tlabel < 0); | ||
| 186 | 207 | ||
| 187 | BUG_ON(packet->tlabel > 63 || packet->tlabel < 0); | 208 | spin_lock_irqsave(&hpsb_tlabel_lock, flags); |
| 209 | BUG_ON(!__test_and_clear_bit(tlabel, tp)); | ||
| 210 | spin_unlock_irqrestore(&hpsb_tlabel_lock, flags); | ||
| 188 | 211 | ||
| 189 | spin_lock_irqsave(&tp->lock, flags); | 212 | wake_up_interruptible(&tlabel_wq); |
| 190 | BUG_ON(!test_and_clear_bit(packet->tlabel, tp->pool)); | ||
| 191 | spin_unlock_irqrestore(&tp->lock, flags); | ||
| 192 | |||
| 193 | up(&tp->count); | ||
| 194 | } | 213 | } |
| 195 | 214 | ||
| 196 | int hpsb_packet_success(struct hpsb_packet *packet) | 215 | int hpsb_packet_success(struct hpsb_packet *packet) |
| @@ -214,7 +233,7 @@ int hpsb_packet_success(struct hpsb_packet *packet) | |||
| 214 | packet->node_id); | 233 | packet->node_id); |
| 215 | return -EAGAIN; | 234 | return -EAGAIN; |
| 216 | } | 235 | } |
| 217 | HPSB_PANIC("reached unreachable code 1 in %s", __FUNCTION__); | 236 | BUG(); |
| 218 | 237 | ||
| 219 | case ACK_BUSY_X: | 238 | case ACK_BUSY_X: |
| 220 | case ACK_BUSY_A: | 239 | case ACK_BUSY_A: |
| @@ -261,8 +280,7 @@ int hpsb_packet_success(struct hpsb_packet *packet) | |||
| 261 | packet->ack_code, packet->node_id, packet->tcode); | 280 | packet->ack_code, packet->node_id, packet->tcode); |
| 262 | return -EAGAIN; | 281 | return -EAGAIN; |
| 263 | } | 282 | } |
| 264 | 283 | BUG(); | |
| 265 | HPSB_PANIC("reached unreachable code 2 in %s", __FUNCTION__); | ||
| 266 | } | 284 | } |
| 267 | 285 | ||
| 268 | struct hpsb_packet *hpsb_make_readpacket(struct hpsb_host *host, nodeid_t node, | 286 | struct hpsb_packet *hpsb_make_readpacket(struct hpsb_host *host, nodeid_t node, |
