aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ieee1394/ieee1394_transactions.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ieee1394/ieee1394_transactions.c')
-rw-r--r--drivers/ieee1394/ieee1394_transactions.c114
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
33static
34#endif
35spinlock_t hpsb_tlabel_lock = SPIN_LOCK_UNLOCKED;
36
37static DECLARE_WAIT_QUEUE_HEAD(tlabel_wq);
38
34static void fill_async_readquad(struct hpsb_packet *packet, u64 addr) 39static 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 */
123static 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 */
135int hpsb_get_tlabel(struct hpsb_packet *packet) 172int 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 */
177void hpsb_free_tlabel(struct hpsb_packet *packet) 197void 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
196int hpsb_packet_success(struct hpsb_packet *packet) 215int 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
268struct hpsb_packet *hpsb_make_readpacket(struct hpsb_host *host, nodeid_t node, 286struct hpsb_packet *hpsb_make_readpacket(struct hpsb_host *host, nodeid_t node,