diff options
Diffstat (limited to 'drivers/ieee1394/ieee1394_transactions.c')
-rw-r--r-- | drivers/ieee1394/ieee1394_transactions.c | 108 |
1 files changed, 63 insertions, 45 deletions
diff --git a/drivers/ieee1394/ieee1394_transactions.c b/drivers/ieee1394/ieee1394_transactions.c index 751960037e27..0833fc9f50c4 100644 --- a/drivers/ieee1394/ieee1394_transactions.c +++ b/drivers/ieee1394/ieee1394_transactions.c | |||
@@ -9,10 +9,9 @@ | |||
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 | ||
17 | #include <asm/bug.h> | 16 | #include <asm/bug.h> |
18 | #include <asm/errno.h> | 17 | #include <asm/errno.h> |
@@ -21,8 +20,6 @@ | |||
21 | #include "ieee1394_types.h" | 20 | #include "ieee1394_types.h" |
22 | #include "hosts.h" | 21 | #include "hosts.h" |
23 | #include "ieee1394_core.h" | 22 | #include "ieee1394_core.h" |
24 | #include "highlevel.h" | ||
25 | #include "nodemgr.h" | ||
26 | #include "ieee1394_transactions.h" | 23 | #include "ieee1394_transactions.h" |
27 | 24 | ||
28 | #define PREP_ASYNC_HEAD_ADDRESS(tc) \ | 25 | #define PREP_ASYNC_HEAD_ADDRESS(tc) \ |
@@ -32,6 +29,13 @@ | |||
32 | packet->header[1] = (packet->host->node_id << 16) | (addr >> 32); \ | 29 | packet->header[1] = (packet->host->node_id << 16) | (addr >> 32); \ |
33 | packet->header[2] = addr & 0xffffffff | 30 | packet->header[2] = addr & 0xffffffff |
34 | 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 | |||
35 | static void fill_async_readquad(struct hpsb_packet *packet, u64 addr) | 39 | static void fill_async_readquad(struct hpsb_packet *packet, u64 addr) |
36 | { | 40 | { |
37 | PREP_ASYNC_HEAD_ADDRESS(TCODE_READQ); | 41 | PREP_ASYNC_HEAD_ADDRESS(TCODE_READQ); |
@@ -115,9 +119,41 @@ static void fill_async_stream_packet(struct hpsb_packet *packet, int length, | |||
115 | packet->tcode = TCODE_ISO_DATA; | 119 | packet->tcode = TCODE_ISO_DATA; |
116 | } | 120 | } |
117 | 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 | |||
118 | /** | 154 | /** |
119 | * hpsb_get_tlabel - allocate a transaction label | 155 | * hpsb_get_tlabel - allocate a transaction label |
120 | * @packet: the packet who's tlabel/tpool we set | 156 | * @packet: the packet whose tlabel and tl_pool we set |
121 | * | 157 | * |
122 | * Every asynchronous transaction on the 1394 bus needs a transaction | 158 | * Every asynchronous transaction on the 1394 bus needs a transaction |
123 | * 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 |
@@ -131,42 +167,25 @@ static void fill_async_stream_packet(struct hpsb_packet *packet, int length, | |||
131 | * 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 |
132 | * 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 |
133 | * 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 |
134 | * tlabel. | 170 | * tlabel or a signal is received. |
135 | */ | 171 | */ |
136 | int hpsb_get_tlabel(struct hpsb_packet *packet) | 172 | int hpsb_get_tlabel(struct hpsb_packet *packet) |
137 | { | 173 | { |
138 | unsigned long flags; | 174 | if (irqs_disabled() || in_atomic()) |
139 | struct hpsb_tlabel_pool *tp; | 175 | return hpsb_get_tlabel_atomic(packet); |
140 | int n = NODEID_TO_NODE(packet->node_id); | 176 | |
141 | 177 | /* NB: The macro wait_event_interruptible() is called with a condition | |
142 | if (unlikely(n == ALL_NODES)) | 178 | * argument with side effect. This is only possible because the side |
143 | return 0; | 179 | * effect does not occur until the condition became true, and |
144 | tp = &packet->host->tpool[n]; | 180 | * wait_event_interruptible() won't evaluate the condition again after |
145 | 181 | * that. */ | |
146 | if (irqs_disabled() || in_atomic()) { | 182 | return wait_event_interruptible(tlabel_wq, |
147 | if (down_trylock(&tp->count)) | 183 | !hpsb_get_tlabel_atomic(packet)); |
148 | return 1; | ||
149 | } else { | ||
150 | down(&tp->count); | ||
151 | } | ||
152 | |||
153 | spin_lock_irqsave(&tp->lock, flags); | ||
154 | |||
155 | packet->tlabel = find_next_zero_bit(tp->pool, 64, tp->next); | ||
156 | if (packet->tlabel > 63) | ||
157 | packet->tlabel = find_first_zero_bit(tp->pool, 64); | ||
158 | tp->next = (packet->tlabel + 1) % 64; | ||
159 | /* Should _never_ happen */ | ||
160 | BUG_ON(test_and_set_bit(packet->tlabel, tp->pool)); | ||
161 | tp->allocations++; | ||
162 | spin_unlock_irqrestore(&tp->lock, flags); | ||
163 | |||
164 | return 0; | ||
165 | } | 184 | } |
166 | 185 | ||
167 | /** | 186 | /** |
168 | * hpsb_free_tlabel - free an allocated transaction label | 187 | * hpsb_free_tlabel - free an allocated transaction label |
169 | * @packet: packet whos tlabel/tpool needs to be cleared | 188 | * @packet: packet whose tlabel and tl_pool needs to be cleared |
170 | * | 189 | * |
171 | * Frees the transaction label allocated with hpsb_get_tlabel(). The | 190 | * Frees the transaction label allocated with hpsb_get_tlabel(). The |
172 | * 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 |
@@ -177,21 +196,20 @@ int hpsb_get_tlabel(struct hpsb_packet *packet) | |||
177 | */ | 196 | */ |
178 | void hpsb_free_tlabel(struct hpsb_packet *packet) | 197 | void hpsb_free_tlabel(struct hpsb_packet *packet) |
179 | { | 198 | { |
180 | unsigned long flags; | 199 | unsigned long flags, *tp; |
181 | struct hpsb_tlabel_pool *tp; | 200 | int tlabel, n = NODEID_TO_NODE(packet->node_id); |
182 | int n = NODEID_TO_NODE(packet->node_id); | ||
183 | 201 | ||
184 | if (unlikely(n == ALL_NODES)) | 202 | if (unlikely(n == ALL_NODES)) |
185 | return; | 203 | return; |
186 | tp = &packet->host->tpool[n]; | 204 | tp = packet->host->tl_pool[n].map; |
187 | 205 | tlabel = packet->tlabel; | |
188 | BUG_ON(packet->tlabel > 63 || packet->tlabel < 0); | 206 | BUG_ON(tlabel > 63 || tlabel < 0); |
189 | 207 | ||
190 | spin_lock_irqsave(&tp->lock, flags); | 208 | spin_lock_irqsave(&hpsb_tlabel_lock, flags); |
191 | BUG_ON(!test_and_clear_bit(packet->tlabel, tp->pool)); | 209 | BUG_ON(!__test_and_clear_bit(tlabel, tp)); |
192 | spin_unlock_irqrestore(&tp->lock, flags); | 210 | spin_unlock_irqrestore(&hpsb_tlabel_lock, flags); |
193 | 211 | ||
194 | up(&tp->count); | 212 | wake_up_interruptible(&tlabel_wq); |
195 | } | 213 | } |
196 | 214 | ||
197 | int hpsb_packet_success(struct hpsb_packet *packet) | 215 | int hpsb_packet_success(struct hpsb_packet *packet) |