aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ieee1394/highlevel.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ieee1394/highlevel.c')
-rw-r--r--drivers/ieee1394/highlevel.c445
1 files changed, 202 insertions, 243 deletions
diff --git a/drivers/ieee1394/highlevel.c b/drivers/ieee1394/highlevel.c
index 491e6032bdec..25b22609e793 100644
--- a/drivers/ieee1394/highlevel.c
+++ b/drivers/ieee1394/highlevel.c
@@ -53,7 +53,7 @@ static struct hpsb_address_serve dummy_zero_addr, dummy_max_addr;
53 53
54 54
55static struct hl_host_info *hl_get_hostinfo(struct hpsb_highlevel *hl, 55static struct hl_host_info *hl_get_hostinfo(struct hpsb_highlevel *hl,
56 struct hpsb_host *host) 56 struct hpsb_host *host)
57{ 57{
58 struct hl_host_info *hi = NULL; 58 struct hl_host_info *hi = NULL;
59 59
@@ -68,24 +68,18 @@ static struct hl_host_info *hl_get_hostinfo(struct hpsb_highlevel *hl,
68 } 68 }
69 } 69 }
70 read_unlock(&hl->host_info_lock); 70 read_unlock(&hl->host_info_lock);
71
72 return NULL; 71 return NULL;
73} 72}
74 73
75
76/* Returns a per host/driver data structure that was previously stored by 74/* Returns a per host/driver data structure that was previously stored by
77 * hpsb_create_hostinfo. */ 75 * hpsb_create_hostinfo. */
78void *hpsb_get_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host) 76void *hpsb_get_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host)
79{ 77{
80 struct hl_host_info *hi = hl_get_hostinfo(hl, host); 78 struct hl_host_info *hi = hl_get_hostinfo(hl, host);
81 79
82 if (hi) 80 return hi ? hi->data : NULL;
83 return hi->data;
84
85 return NULL;
86} 81}
87 82
88
89/* If size is zero, then the return here is only valid for error checking */ 83/* If size is zero, then the return here is only valid for error checking */
90void *hpsb_create_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host, 84void *hpsb_create_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
91 size_t data_size) 85 size_t data_size)
@@ -96,8 +90,8 @@ void *hpsb_create_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
96 90
97 hi = hl_get_hostinfo(hl, host); 91 hi = hl_get_hostinfo(hl, host);
98 if (hi) { 92 if (hi) {
99 HPSB_ERR("%s called hpsb_create_hostinfo when hostinfo already exists", 93 HPSB_ERR("%s called hpsb_create_hostinfo when hostinfo already"
100 hl->name); 94 " exists", hl->name);
101 return NULL; 95 return NULL;
102 } 96 }
103 97
@@ -120,7 +114,6 @@ void *hpsb_create_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
120 return data; 114 return data;
121} 115}
122 116
123
124int hpsb_set_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host, 117int hpsb_set_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
125 void *data) 118 void *data)
126{ 119{
@@ -132,16 +125,14 @@ int hpsb_set_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
132 hi->data = data; 125 hi->data = data;
133 return 0; 126 return 0;
134 } else 127 } else
135 HPSB_ERR("%s called hpsb_set_hostinfo when hostinfo already has data", 128 HPSB_ERR("%s called hpsb_set_hostinfo when hostinfo "
136 hl->name); 129 "already has data", hl->name);
137 } else 130 } else
138 HPSB_ERR("%s called hpsb_set_hostinfo when no hostinfo exists", 131 HPSB_ERR("%s called hpsb_set_hostinfo when no hostinfo exists",
139 hl->name); 132 hl->name);
140
141 return -EINVAL; 133 return -EINVAL;
142} 134}
143 135
144
145void hpsb_destroy_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host) 136void hpsb_destroy_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host)
146{ 137{
147 struct hl_host_info *hi; 138 struct hl_host_info *hi;
@@ -154,23 +145,20 @@ void hpsb_destroy_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host)
154 write_unlock_irqrestore(&hl->host_info_lock, flags); 145 write_unlock_irqrestore(&hl->host_info_lock, flags);
155 kfree(hi); 146 kfree(hi);
156 } 147 }
157
158 return; 148 return;
159} 149}
160 150
161 151void hpsb_set_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host,
162void hpsb_set_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host, unsigned long key) 152 unsigned long key)
163{ 153{
164 struct hl_host_info *hi; 154 struct hl_host_info *hi;
165 155
166 hi = hl_get_hostinfo(hl, host); 156 hi = hl_get_hostinfo(hl, host);
167 if (hi) 157 if (hi)
168 hi->key = key; 158 hi->key = key;
169
170 return; 159 return;
171} 160}
172 161
173
174void *hpsb_get_hostinfo_bykey(struct hpsb_highlevel *hl, unsigned long key) 162void *hpsb_get_hostinfo_bykey(struct hpsb_highlevel *hl, unsigned long key)
175{ 163{
176 struct hl_host_info *hi; 164 struct hl_host_info *hi;
@@ -187,46 +175,41 @@ void *hpsb_get_hostinfo_bykey(struct hpsb_highlevel *hl, unsigned long key)
187 } 175 }
188 } 176 }
189 read_unlock(&hl->host_info_lock); 177 read_unlock(&hl->host_info_lock);
190
191 return data; 178 return data;
192} 179}
193 180
194
195static int highlevel_for_each_host_reg(struct hpsb_host *host, void *__data) 181static int highlevel_for_each_host_reg(struct hpsb_host *host, void *__data)
196{ 182{
197 struct hpsb_highlevel *hl = __data; 183 struct hpsb_highlevel *hl = __data;
198 184
199 hl->add_host(host); 185 hl->add_host(host);
200 186
201 if (host->update_config_rom) { 187 if (host->update_config_rom && hpsb_update_config_rom_image(host) < 0)
202 if (hpsb_update_config_rom_image(host) < 0) { 188 HPSB_ERR("Failed to generate Configuration ROM image for host "
203 HPSB_ERR("Failed to generate Configuration ROM image for host " 189 "%s-%d", hl->name, host->id);
204 "%s-%d", hl->name, host->id);
205 }
206 }
207
208 return 0; 190 return 0;
209} 191}
210 192
211void hpsb_register_highlevel(struct hpsb_highlevel *hl) 193void hpsb_register_highlevel(struct hpsb_highlevel *hl)
212{ 194{
213 INIT_LIST_HEAD(&hl->addr_list); 195 unsigned long flags;
196
197 INIT_LIST_HEAD(&hl->addr_list);
214 INIT_LIST_HEAD(&hl->host_info_list); 198 INIT_LIST_HEAD(&hl->host_info_list);
215 199
216 rwlock_init(&hl->host_info_lock); 200 rwlock_init(&hl->host_info_lock);
217 201
218 down_write(&hl_drivers_sem); 202 down_write(&hl_drivers_sem);
219 list_add_tail(&hl->hl_list, &hl_drivers); 203 list_add_tail(&hl->hl_list, &hl_drivers);
220 up_write(&hl_drivers_sem); 204 up_write(&hl_drivers_sem);
221 205
222 write_lock(&hl_irqs_lock); 206 write_lock_irqsave(&hl_irqs_lock, flags);
223 list_add_tail(&hl->irq_list, &hl_irqs); 207 list_add_tail(&hl->irq_list, &hl_irqs);
224 write_unlock(&hl_irqs_lock); 208 write_unlock_irqrestore(&hl_irqs_lock, flags);
225 209
226 if (hl->add_host) 210 if (hl->add_host)
227 nodemgr_for_each_host(hl, highlevel_for_each_host_reg); 211 nodemgr_for_each_host(hl, highlevel_for_each_host_reg);
228 212 return;
229 return;
230} 213}
231 214
232static void __delete_addr(struct hpsb_address_serve *as) 215static void __delete_addr(struct hpsb_address_serve *as)
@@ -236,7 +219,8 @@ static void __delete_addr(struct hpsb_address_serve *as)
236 kfree(as); 219 kfree(as);
237} 220}
238 221
239static void __unregister_host(struct hpsb_highlevel *hl, struct hpsb_host *host, int update_cr) 222static void __unregister_host(struct hpsb_highlevel *hl, struct hpsb_host *host,
223 int update_cr)
240{ 224{
241 unsigned long flags; 225 unsigned long flags;
242 struct list_head *lh, *next; 226 struct list_head *lh, *next;
@@ -251,7 +235,6 @@ static void __unregister_host(struct hpsb_highlevel *hl, struct hpsb_host *host,
251 write_lock_irqsave(&addr_space_lock, flags); 235 write_lock_irqsave(&addr_space_lock, flags);
252 list_for_each_safe (lh, next, &hl->addr_list) { 236 list_for_each_safe (lh, next, &hl->addr_list) {
253 as = list_entry(lh, struct hpsb_address_serve, hl_list); 237 as = list_entry(lh, struct hpsb_address_serve, hl_list);
254
255 if (as->host == host) 238 if (as->host == host)
256 __delete_addr(as); 239 __delete_addr(as);
257 } 240 }
@@ -259,15 +242,12 @@ static void __unregister_host(struct hpsb_highlevel *hl, struct hpsb_host *host,
259 242
260 /* Now update the config-rom to reflect anything removed by the 243 /* Now update the config-rom to reflect anything removed by the
261 * highlevel driver. */ 244 * highlevel driver. */
262 if (update_cr && host->update_config_rom) { 245 if (update_cr && host->update_config_rom &&
263 if (hpsb_update_config_rom_image(host) < 0) { 246 hpsb_update_config_rom_image(host) < 0)
264 HPSB_ERR("Failed to generate Configuration ROM image for host " 247 HPSB_ERR("Failed to generate Configuration ROM image for host "
265 "%s-%d", hl->name, host->id); 248 "%s-%d", hl->name, host->id);
266 }
267 }
268 249
269 /* And finally, remove all the host info associated between these 250 /* Finally remove all the host info associated between these two. */
270 * two. */
271 hpsb_destroy_hostinfo(hl, host); 251 hpsb_destroy_hostinfo(hl, host);
272} 252}
273 253
@@ -276,18 +256,19 @@ static int highlevel_for_each_host_unreg(struct hpsb_host *host, void *__data)
276 struct hpsb_highlevel *hl = __data; 256 struct hpsb_highlevel *hl = __data;
277 257
278 __unregister_host(hl, host, 1); 258 __unregister_host(hl, host, 1);
279
280 return 0; 259 return 0;
281} 260}
282 261
283void hpsb_unregister_highlevel(struct hpsb_highlevel *hl) 262void hpsb_unregister_highlevel(struct hpsb_highlevel *hl)
284{ 263{
285 write_lock(&hl_irqs_lock); 264 unsigned long flags;
265
266 write_lock_irqsave(&hl_irqs_lock, flags);
286 list_del(&hl->irq_list); 267 list_del(&hl->irq_list);
287 write_unlock(&hl_irqs_lock); 268 write_unlock_irqrestore(&hl_irqs_lock, flags);
288 269
289 down_write(&hl_drivers_sem); 270 down_write(&hl_drivers_sem);
290 list_del(&hl->hl_list); 271 list_del(&hl->hl_list);
291 up_write(&hl_drivers_sem); 272 up_write(&hl_drivers_sem);
292 273
293 nodemgr_for_each_host(hl, highlevel_for_each_host_unreg); 274 nodemgr_for_each_host(hl, highlevel_for_each_host_unreg);
@@ -301,7 +282,7 @@ u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl,
301{ 282{
302 struct hpsb_address_serve *as, *a1, *a2; 283 struct hpsb_address_serve *as, *a1, *a2;
303 struct list_head *entry; 284 struct list_head *entry;
304 u64 retval = ~0ULL; 285 u64 retval = CSR1212_INVALID_ADDR_SPACE;
305 unsigned long flags; 286 unsigned long flags;
306 u64 align_mask = ~(alignment - 1); 287 u64 align_mask = ~(alignment - 1);
307 288
@@ -312,14 +293,19 @@ u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl,
312 return retval; 293 return retval;
313 } 294 }
314 295
315 if (start == ~0ULL && end == ~0ULL) { 296 /* default range,
316 start = CSR1212_ALL_SPACE_BASE + 0xffff00000000ULL; /* ohci1394.c limit */ 297 * avoids controller's posted write area (see OHCI 1.1 clause 1.5) */
317 end = CSR1212_ALL_SPACE_END; 298 if (start == CSR1212_INVALID_ADDR_SPACE &&
299 end == CSR1212_INVALID_ADDR_SPACE) {
300 start = host->middle_addr_space;
301 end = CSR1212_ALL_SPACE_END;
318 } 302 }
319 303
320 if (((start|end) & ~align_mask) || (start >= end) || (end > 0x1000000000000ULL)) { 304 if (((start|end) & ~align_mask) || (start >= end) ||
321 HPSB_ERR("%s called with invalid addresses (start = %012Lx end = %012Lx)", 305 (end > CSR1212_ALL_SPACE_END)) {
322 __FUNCTION__, (unsigned long long)start, (unsigned long long)end); 306 HPSB_ERR("%s called with invalid addresses "
307 "(start = %012Lx end = %012Lx)", __FUNCTION__,
308 (unsigned long long)start,(unsigned long long)end);
323 return retval; 309 return retval;
324 } 310 }
325 311
@@ -333,20 +319,21 @@ u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl,
333 as->host = host; 319 as->host = host;
334 320
335 write_lock_irqsave(&addr_space_lock, flags); 321 write_lock_irqsave(&addr_space_lock, flags);
336
337 list_for_each(entry, &host->addr_space) { 322 list_for_each(entry, &host->addr_space) {
338 u64 a1sa, a1ea; 323 u64 a1sa, a1ea;
339 u64 a2sa, a2ea; 324 u64 a2sa, a2ea;
340 325
341 a1 = list_entry(entry, struct hpsb_address_serve, host_list); 326 a1 = list_entry(entry, struct hpsb_address_serve, host_list);
342 a2 = list_entry(entry->next, struct hpsb_address_serve, host_list); 327 a2 = list_entry(entry->next, struct hpsb_address_serve,
328 host_list);
343 329
344 a1sa = a1->start & align_mask; 330 a1sa = a1->start & align_mask;
345 a1ea = (a1->end + alignment -1) & align_mask; 331 a1ea = (a1->end + alignment -1) & align_mask;
346 a2sa = a2->start & align_mask; 332 a2sa = a2->start & align_mask;
347 a2ea = (a2->end + alignment -1) & align_mask; 333 a2ea = (a2->end + alignment -1) & align_mask;
348 334
349 if ((a2sa - a1ea >= size) && (a2sa - start >= size) && (a2sa > start)) { 335 if ((a2sa - a1ea >= size) && (a2sa - start >= size) &&
336 (a2sa > start)) {
350 as->start = max(start, a1ea); 337 as->start = max(start, a1ea);
351 as->end = as->start + size; 338 as->end = as->start + size;
352 list_add(&as->host_list, entry); 339 list_add(&as->host_list, entry);
@@ -355,47 +342,45 @@ u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl,
355 break; 342 break;
356 } 343 }
357 } 344 }
358
359 write_unlock_irqrestore(&addr_space_lock, flags); 345 write_unlock_irqrestore(&addr_space_lock, flags);
360 346
361 if (retval == ~0ULL) { 347 if (retval == CSR1212_INVALID_ADDR_SPACE)
362 kfree(as); 348 kfree(as);
363 }
364
365 return retval; 349 return retval;
366} 350}
367 351
368int hpsb_register_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host, 352int hpsb_register_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
369 struct hpsb_address_ops *ops, u64 start, u64 end) 353 struct hpsb_address_ops *ops, u64 start, u64 end)
370{ 354{
371 struct hpsb_address_serve *as; 355 struct hpsb_address_serve *as;
372 struct list_head *lh; 356 struct list_head *lh;
373 int retval = 0; 357 int retval = 0;
374 unsigned long flags; 358 unsigned long flags;
375 359
376 if (((start|end) & 3) || (start >= end) || (end > 0x1000000000000ULL)) { 360 if (((start|end) & 3) || (start >= end) ||
377 HPSB_ERR("%s called with invalid addresses", __FUNCTION__); 361 (end > CSR1212_ALL_SPACE_END)) {
378 return 0; 362 HPSB_ERR("%s called with invalid addresses", __FUNCTION__);
379 } 363 return 0;
364 }
380 365
381 as = kmalloc(sizeof(*as), GFP_ATOMIC); 366 as = kmalloc(sizeof(*as), GFP_ATOMIC);
382 if (!as) 367 if (!as)
383 return 0; 368 return 0;
384 369
385 INIT_LIST_HEAD(&as->host_list); 370 INIT_LIST_HEAD(&as->host_list);
386 INIT_LIST_HEAD(&as->hl_list); 371 INIT_LIST_HEAD(&as->hl_list);
387 as->op = ops; 372 as->op = ops;
388 as->start = start; 373 as->start = start;
389 as->end = end; 374 as->end = end;
390 as->host = host; 375 as->host = host;
391 376
392 write_lock_irqsave(&addr_space_lock, flags); 377 write_lock_irqsave(&addr_space_lock, flags);
393
394 list_for_each(lh, &host->addr_space) { 378 list_for_each(lh, &host->addr_space) {
395 struct hpsb_address_serve *as_this = 379 struct hpsb_address_serve *as_this =
396 list_entry(lh, struct hpsb_address_serve, host_list); 380 list_entry(lh, struct hpsb_address_serve, host_list);
397 struct hpsb_address_serve *as_next = 381 struct hpsb_address_serve *as_next =
398 list_entry(lh->next, struct hpsb_address_serve, host_list); 382 list_entry(lh->next, struct hpsb_address_serve,
383 host_list);
399 384
400 if (as_this->end > as->start) 385 if (as_this->end > as->start)
401 break; 386 break;
@@ -411,60 +396,51 @@ int hpsb_register_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
411 396
412 if (retval == 0) 397 if (retval == 0)
413 kfree(as); 398 kfree(as);
414 399 return retval;
415 return retval;
416} 400}
417 401
418int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host, 402int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
419 u64 start) 403 u64 start)
420{ 404{
421 int retval = 0; 405 int retval = 0;
422 struct hpsb_address_serve *as; 406 struct hpsb_address_serve *as;
423 struct list_head *lh, *next; 407 struct list_head *lh, *next;
424 unsigned long flags; 408 unsigned long flags;
425
426 write_lock_irqsave(&addr_space_lock, flags);
427 409
410 write_lock_irqsave(&addr_space_lock, flags);
428 list_for_each_safe (lh, next, &hl->addr_list) { 411 list_for_each_safe (lh, next, &hl->addr_list) {
429 as = list_entry(lh, struct hpsb_address_serve, hl_list); 412 as = list_entry(lh, struct hpsb_address_serve, hl_list);
430 if (as->start == start && as->host == host) { 413 if (as->start == start && as->host == host) {
431 __delete_addr(as); 414 __delete_addr(as);
432 retval = 1; 415 retval = 1;
433 break; 416 break;
434 } 417 }
435 } 418 }
436 419 write_unlock_irqrestore(&addr_space_lock, flags);
437 write_unlock_irqrestore(&addr_space_lock, flags); 420 return retval;
438
439 return retval;
440} 421}
441 422
442int hpsb_listen_channel(struct hpsb_highlevel *hl, struct hpsb_host *host, 423int hpsb_listen_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
443 unsigned int channel) 424 unsigned int channel)
444{ 425{
445 if (channel > 63) { 426 if (channel > 63) {
446 HPSB_ERR("%s called with invalid channel", __FUNCTION__); 427 HPSB_ERR("%s called with invalid channel", __FUNCTION__);
447 return -EINVAL; 428 return -EINVAL;
448 } 429 }
449 430 if (host->iso_listen_count[channel]++ == 0)
450 if (host->iso_listen_count[channel]++ == 0) { 431 return host->driver->devctl(host, ISO_LISTEN_CHANNEL, channel);
451 return host->driver->devctl(host, ISO_LISTEN_CHANNEL, channel);
452 }
453
454 return 0; 432 return 0;
455} 433}
456 434
457void hpsb_unlisten_channel(struct hpsb_highlevel *hl, struct hpsb_host *host, 435void hpsb_unlisten_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
458 unsigned int channel) 436 unsigned int channel)
459{ 437{
460 if (channel > 63) { 438 if (channel > 63) {
461 HPSB_ERR("%s called with invalid channel", __FUNCTION__); 439 HPSB_ERR("%s called with invalid channel", __FUNCTION__);
462 return; 440 return;
463 } 441 }
464 442 if (--host->iso_listen_count[channel] == 0)
465 if (--host->iso_listen_count[channel] == 0) { 443 host->driver->devctl(host, ISO_UNLISTEN_CHANNEL, channel);
466 host->driver->devctl(host, ISO_UNLISTEN_CHANNEL, channel);
467 }
468} 444}
469 445
470static void init_hpsb_highlevel(struct hpsb_host *host) 446static void init_hpsb_highlevel(struct hpsb_host *host)
@@ -485,26 +461,24 @@ static void init_hpsb_highlevel(struct hpsb_host *host)
485 461
486void highlevel_add_host(struct hpsb_host *host) 462void highlevel_add_host(struct hpsb_host *host)
487{ 463{
488 struct hpsb_highlevel *hl; 464 struct hpsb_highlevel *hl;
489 465
490 init_hpsb_highlevel(host); 466 init_hpsb_highlevel(host);
491 467
492 down_read(&hl_drivers_sem); 468 down_read(&hl_drivers_sem);
493 list_for_each_entry(hl, &hl_drivers, hl_list) { 469 list_for_each_entry(hl, &hl_drivers, hl_list) {
494 if (hl->add_host) 470 if (hl->add_host)
495 hl->add_host(host); 471 hl->add_host(host);
496 }
497 up_read(&hl_drivers_sem);
498 if (host->update_config_rom) {
499 if (hpsb_update_config_rom_image(host) < 0)
500 HPSB_ERR("Failed to generate Configuration ROM image for "
501 "host %s-%d", hl->name, host->id);
502 } 472 }
473 up_read(&hl_drivers_sem);
474 if (host->update_config_rom && hpsb_update_config_rom_image(host) < 0)
475 HPSB_ERR("Failed to generate Configuration ROM image for host "
476 "%s-%d", hl->name, host->id);
503} 477}
504 478
505void highlevel_remove_host(struct hpsb_host *host) 479void highlevel_remove_host(struct hpsb_host *host)
506{ 480{
507 struct hpsb_highlevel *hl; 481 struct hpsb_highlevel *hl;
508 482
509 down_read(&hl_drivers_sem); 483 down_read(&hl_drivers_sem);
510 list_for_each_entry(hl, &hl_drivers, hl_list) 484 list_for_each_entry(hl, &hl_drivers, hl_list)
@@ -514,184 +488,169 @@ void highlevel_remove_host(struct hpsb_host *host)
514 488
515void highlevel_host_reset(struct hpsb_host *host) 489void highlevel_host_reset(struct hpsb_host *host)
516{ 490{
517 struct hpsb_highlevel *hl; 491 unsigned long flags;
492 struct hpsb_highlevel *hl;
518 493
519 read_lock(&hl_irqs_lock); 494 read_lock_irqsave(&hl_irqs_lock, flags);
520 list_for_each_entry(hl, &hl_irqs, irq_list) { 495 list_for_each_entry(hl, &hl_irqs, irq_list) {
521 if (hl->host_reset) 496 if (hl->host_reset)
522 hl->host_reset(host); 497 hl->host_reset(host);
523 } 498 }
524 read_unlock(&hl_irqs_lock); 499 read_unlock_irqrestore(&hl_irqs_lock, flags);
525} 500}
526 501
527void highlevel_iso_receive(struct hpsb_host *host, void *data, size_t length) 502void highlevel_iso_receive(struct hpsb_host *host, void *data, size_t length)
528{ 503{
529 struct hpsb_highlevel *hl; 504 unsigned long flags;
530 int channel = (((quadlet_t *)data)[0] >> 8) & 0x3f; 505 struct hpsb_highlevel *hl;
506 int channel = (((quadlet_t *)data)[0] >> 8) & 0x3f;
531 507
532 read_lock(&hl_irqs_lock); 508 read_lock_irqsave(&hl_irqs_lock, flags);
533 list_for_each_entry(hl, &hl_irqs, irq_list) { 509 list_for_each_entry(hl, &hl_irqs, irq_list) {
534 if (hl->iso_receive) 510 if (hl->iso_receive)
535 hl->iso_receive(host, channel, data, length); 511 hl->iso_receive(host, channel, data, length);
536 } 512 }
537 read_unlock(&hl_irqs_lock); 513 read_unlock_irqrestore(&hl_irqs_lock, flags);
538} 514}
539 515
540void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction, 516void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction,
541 void *data, size_t length) 517 void *data, size_t length)
542{ 518{
543 struct hpsb_highlevel *hl; 519 unsigned long flags;
544 int cts = ((quadlet_t *)data)[0] >> 4; 520 struct hpsb_highlevel *hl;
521 int cts = ((quadlet_t *)data)[0] >> 4;
545 522
546 read_lock(&hl_irqs_lock); 523 read_lock_irqsave(&hl_irqs_lock, flags);
547 list_for_each_entry(hl, &hl_irqs, irq_list) { 524 list_for_each_entry(hl, &hl_irqs, irq_list) {
548 if (hl->fcp_request) 525 if (hl->fcp_request)
549 hl->fcp_request(host, nodeid, direction, cts, data, 526 hl->fcp_request(host, nodeid, direction, cts, data,
550 length); 527 length);
551 } 528 }
552 read_unlock(&hl_irqs_lock); 529 read_unlock_irqrestore(&hl_irqs_lock, flags);
553} 530}
554 531
555int highlevel_read(struct hpsb_host *host, int nodeid, void *data, 532int highlevel_read(struct hpsb_host *host, int nodeid, void *data, u64 addr,
556 u64 addr, unsigned int length, u16 flags) 533 unsigned int length, u16 flags)
557{ 534{
558 struct hpsb_address_serve *as; 535 struct hpsb_address_serve *as;
559 unsigned int partlength; 536 unsigned int partlength;
560 int rcode = RCODE_ADDRESS_ERROR; 537 int rcode = RCODE_ADDRESS_ERROR;
561
562 read_lock(&addr_space_lock);
563 538
539 read_lock(&addr_space_lock);
564 list_for_each_entry(as, &host->addr_space, host_list) { 540 list_for_each_entry(as, &host->addr_space, host_list) {
565 if (as->start > addr) 541 if (as->start > addr)
566 break; 542 break;
567 543
568 if (as->end > addr) { 544 if (as->end > addr) {
569 partlength = min(as->end - addr, (u64) length); 545 partlength = min(as->end - addr, (u64) length);
570 546
571 if (as->op->read) { 547 if (as->op->read)
572 rcode = as->op->read(host, nodeid, data, 548 rcode = as->op->read(host, nodeid, data,
573 addr, partlength, flags); 549 addr, partlength, flags);
574 } else { 550 else
575 rcode = RCODE_TYPE_ERROR; 551 rcode = RCODE_TYPE_ERROR;
576 }
577 552
578 data += partlength; 553 data += partlength;
579 length -= partlength; 554 length -= partlength;
580 addr += partlength; 555 addr += partlength;
581
582 if ((rcode != RCODE_COMPLETE) || !length) {
583 break;
584 }
585 }
586 }
587
588 read_unlock(&addr_space_lock);
589 556
590 if (length && (rcode == RCODE_COMPLETE)) { 557 if ((rcode != RCODE_COMPLETE) || !length)
591 rcode = RCODE_ADDRESS_ERROR; 558 break;
592 } 559 }
560 }
561 read_unlock(&addr_space_lock);
593 562
594 return rcode; 563 if (length && (rcode == RCODE_COMPLETE))
564 rcode = RCODE_ADDRESS_ERROR;
565 return rcode;
595} 566}
596 567
597int highlevel_write(struct hpsb_host *host, int nodeid, int destid, 568int highlevel_write(struct hpsb_host *host, int nodeid, int destid, void *data,
598 void *data, u64 addr, unsigned int length, u16 flags) 569 u64 addr, unsigned int length, u16 flags)
599{ 570{
600 struct hpsb_address_serve *as; 571 struct hpsb_address_serve *as;
601 unsigned int partlength; 572 unsigned int partlength;
602 int rcode = RCODE_ADDRESS_ERROR; 573 int rcode = RCODE_ADDRESS_ERROR;
603
604 read_lock(&addr_space_lock);
605 574
575 read_lock(&addr_space_lock);
606 list_for_each_entry(as, &host->addr_space, host_list) { 576 list_for_each_entry(as, &host->addr_space, host_list) {
607 if (as->start > addr) 577 if (as->start > addr)
608 break; 578 break;
609 579
610 if (as->end > addr) { 580 if (as->end > addr) {
611 partlength = min(as->end - addr, (u64) length); 581 partlength = min(as->end - addr, (u64) length);
612 582
613 if (as->op->write) { 583 if (as->op->write)
614 rcode = as->op->write(host, nodeid, destid, 584 rcode = as->op->write(host, nodeid, destid,
615 data, addr, partlength, flags); 585 data, addr, partlength,
616 } else { 586 flags);
617 rcode = RCODE_TYPE_ERROR; 587 else
618 } 588 rcode = RCODE_TYPE_ERROR;
619 589
620 data += partlength; 590 data += partlength;
621 length -= partlength; 591 length -= partlength;
622 addr += partlength; 592 addr += partlength;
623
624 if ((rcode != RCODE_COMPLETE) || !length) {
625 break;
626 }
627 }
628 }
629
630 read_unlock(&addr_space_lock);
631 593
632 if (length && (rcode == RCODE_COMPLETE)) { 594 if ((rcode != RCODE_COMPLETE) || !length)
633 rcode = RCODE_ADDRESS_ERROR; 595 break;
634 } 596 }
597 }
598 read_unlock(&addr_space_lock);
635 599
636 return rcode; 600 if (length && (rcode == RCODE_COMPLETE))
601 rcode = RCODE_ADDRESS_ERROR;
602 return rcode;
637} 603}
638 604
639
640int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store, 605int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
641 u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags) 606 u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode,
607 u16 flags)
642{ 608{
643 struct hpsb_address_serve *as; 609 struct hpsb_address_serve *as;
644 int rcode = RCODE_ADDRESS_ERROR; 610 int rcode = RCODE_ADDRESS_ERROR;
645
646 read_lock(&addr_space_lock);
647 611
612 read_lock(&addr_space_lock);
648 list_for_each_entry(as, &host->addr_space, host_list) { 613 list_for_each_entry(as, &host->addr_space, host_list) {
649 if (as->start > addr) 614 if (as->start > addr)
650 break; 615 break;
651 616
652 if (as->end > addr) { 617 if (as->end > addr) {
653 if (as->op->lock) { 618 if (as->op->lock)
654 rcode = as->op->lock(host, nodeid, store, addr, 619 rcode = as->op->lock(host, nodeid, store, addr,
655 data, arg, ext_tcode, flags); 620 data, arg, ext_tcode,
656 } else { 621 flags);
657 rcode = RCODE_TYPE_ERROR; 622 else
658 } 623 rcode = RCODE_TYPE_ERROR;
659 624 break;
660 break; 625 }
661 } 626 }
662 } 627 read_unlock(&addr_space_lock);
663 628 return rcode;
664 read_unlock(&addr_space_lock);
665
666 return rcode;
667} 629}
668 630
669int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store, 631int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
670 u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags) 632 u64 addr, octlet_t data, octlet_t arg, int ext_tcode,
633 u16 flags)
671{ 634{
672 struct hpsb_address_serve *as; 635 struct hpsb_address_serve *as;
673 int rcode = RCODE_ADDRESS_ERROR; 636 int rcode = RCODE_ADDRESS_ERROR;
674 637
675 read_lock(&addr_space_lock); 638 read_lock(&addr_space_lock);
676 639
677 list_for_each_entry(as, &host->addr_space, host_list) { 640 list_for_each_entry(as, &host->addr_space, host_list) {
678 if (as->start > addr) 641 if (as->start > addr)
679 break; 642 break;
680 643
681 if (as->end > addr) { 644 if (as->end > addr) {
682 if (as->op->lock64) { 645 if (as->op->lock64)
683 rcode = as->op->lock64(host, nodeid, store, 646 rcode = as->op->lock64(host, nodeid, store,
684 addr, data, arg, 647 addr, data, arg,
685 ext_tcode, flags); 648 ext_tcode, flags);
686 } else { 649 else
687 rcode = RCODE_TYPE_ERROR; 650 rcode = RCODE_TYPE_ERROR;
688 } 651 break;
689 652 }
690 break; 653 }
691 } 654 read_unlock(&addr_space_lock);
692 } 655 return rcode;
693
694 read_unlock(&addr_space_lock);
695
696 return rcode;
697} 656}