diff options
author | Kristian Høgsberg <krh@redhat.com> | 2007-01-26 00:38:26 -0500 |
---|---|---|
committer | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2007-03-09 16:02:47 -0500 |
commit | 93c4cceb963ebb133531e5e3f4f6e2da0d222656 (patch) | |
tree | 3d53c8720e64a8f02278b0f958251195574d2caa /drivers/firewire/fw-ohci.c | |
parent | 746083d86cf5f874741e3ddecf56ea3ed32959c8 (diff) |
firewire: Handle access to CSR resources on local node.
Signed-off-by: Kristian Høgsberg <krh@redhat.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers/firewire/fw-ohci.c')
-rw-r--r-- | drivers/firewire/fw-ohci.c | 130 |
1 files changed, 114 insertions, 16 deletions
diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c index 5156329a8655..ac6c018de0dc 100644 --- a/drivers/firewire/fw-ohci.c +++ b/drivers/firewire/fw-ohci.c | |||
@@ -540,38 +540,136 @@ at_context_init(struct at_context *ctx, struct fw_ohci *ohci, u32 control_set) | |||
540 | } | 540 | } |
541 | 541 | ||
542 | #define header_get_destination(q) (((q) >> 16) & 0xffff) | 542 | #define header_get_destination(q) (((q) >> 16) & 0xffff) |
543 | #define header_get_tcode(q) (((q) >> 4) & 0x0f) | ||
544 | #define header_get_offset_high(q) (((q) >> 0) & 0xffff) | ||
545 | #define header_get_data_length(q) (((q) >> 16) & 0xffff) | ||
546 | #define header_get_extended_tcode(q) (((q) >> 0) & 0xffff) | ||
547 | |||
548 | static void | ||
549 | handle_local_rom(struct fw_ohci *ohci, struct fw_packet *packet, u32 csr) | ||
550 | { | ||
551 | struct fw_packet response; | ||
552 | int tcode, length, i; | ||
553 | |||
554 | tcode = header_get_tcode(packet->header[0]); | ||
555 | if (TCODE_IS_BLOCK_PACKET(tcode)) | ||
556 | length = header_get_data_length(packet->header[3]); | ||
557 | else | ||
558 | length = 4; | ||
559 | |||
560 | i = csr - CSR_CONFIG_ROM; | ||
561 | if (i + length > CONFIG_ROM_SIZE) { | ||
562 | fw_fill_response(&response, packet->header, | ||
563 | RCODE_ADDRESS_ERROR, NULL, 0); | ||
564 | } else if (!TCODE_IS_READ_REQUEST(tcode)) { | ||
565 | fw_fill_response(&response, packet->header, | ||
566 | RCODE_TYPE_ERROR, NULL, 0); | ||
567 | } else { | ||
568 | fw_fill_response(&response, packet->header, RCODE_COMPLETE, | ||
569 | (void *) ohci->config_rom + i, length); | ||
570 | } | ||
571 | |||
572 | fw_core_handle_response(&ohci->card, &response); | ||
573 | } | ||
574 | |||
575 | static void | ||
576 | handle_local_lock(struct fw_ohci *ohci, struct fw_packet *packet, u32 csr) | ||
577 | { | ||
578 | struct fw_packet response; | ||
579 | int tcode, length, ext_tcode, sel; | ||
580 | __be32 *payload, lock_old; | ||
581 | u32 lock_arg, lock_data; | ||
582 | |||
583 | tcode = header_get_tcode(packet->header[0]); | ||
584 | length = header_get_data_length(packet->header[3]); | ||
585 | payload = packet->payload; | ||
586 | ext_tcode = header_get_extended_tcode(packet->header[3]); | ||
587 | |||
588 | if (tcode == TCODE_LOCK_REQUEST && | ||
589 | ext_tcode == EXTCODE_COMPARE_SWAP && length == 8) { | ||
590 | lock_arg = be32_to_cpu(payload[0]); | ||
591 | lock_data = be32_to_cpu(payload[1]); | ||
592 | } else if (tcode == TCODE_READ_QUADLET_REQUEST) { | ||
593 | lock_arg = 0; | ||
594 | lock_data = 0; | ||
595 | } else { | ||
596 | fw_fill_response(&response, packet->header, | ||
597 | RCODE_TYPE_ERROR, NULL, 0); | ||
598 | goto out; | ||
599 | } | ||
600 | |||
601 | sel = (csr - CSR_BUS_MANAGER_ID) / 4; | ||
602 | reg_write(ohci, OHCI1394_CSRData, lock_data); | ||
603 | reg_write(ohci, OHCI1394_CSRCompareData, lock_arg); | ||
604 | reg_write(ohci, OHCI1394_CSRControl, sel); | ||
605 | |||
606 | if (reg_read(ohci, OHCI1394_CSRControl) & 0x80000000) | ||
607 | lock_old = cpu_to_be32(reg_read(ohci, OHCI1394_CSRData)); | ||
608 | else | ||
609 | fw_notify("swap not done yet\n"); | ||
610 | |||
611 | fw_fill_response(&response, packet->header, | ||
612 | RCODE_COMPLETE, &lock_old, sizeof lock_old); | ||
613 | out: | ||
614 | fw_core_handle_response(&ohci->card, &response); | ||
615 | } | ||
616 | |||
617 | static void | ||
618 | handle_local_request(struct at_context *ctx, struct fw_packet *packet) | ||
619 | { | ||
620 | u64 offset; | ||
621 | u32 csr; | ||
622 | |||
623 | packet->ack = ACK_PENDING; | ||
624 | packet->callback(packet, &ctx->ohci->card, packet->ack); | ||
625 | |||
626 | offset = | ||
627 | ((unsigned long long) | ||
628 | header_get_offset_high(packet->header[1]) << 32) | | ||
629 | packet->header[2]; | ||
630 | csr = offset - CSR_REGISTER_BASE; | ||
631 | |||
632 | /* Handle config rom reads. */ | ||
633 | if (csr >= CSR_CONFIG_ROM && csr < CSR_CONFIG_ROM_END) | ||
634 | handle_local_rom(ctx->ohci, packet, csr); | ||
635 | else switch (csr) { | ||
636 | case CSR_BUS_MANAGER_ID: | ||
637 | case CSR_BANDWIDTH_AVAILABLE: | ||
638 | case CSR_CHANNELS_AVAILABLE_HI: | ||
639 | case CSR_CHANNELS_AVAILABLE_LO: | ||
640 | handle_local_lock(ctx->ohci, packet, csr); | ||
641 | break; | ||
642 | default: | ||
643 | if (ctx == &ctx->ohci->at_request_ctx) | ||
644 | fw_core_handle_request(&ctx->ohci->card, packet); | ||
645 | else | ||
646 | fw_core_handle_response(&ctx->ohci->card, packet); | ||
647 | break; | ||
648 | } | ||
649 | } | ||
543 | 650 | ||
544 | static void | 651 | static void |
545 | at_context_transmit(struct at_context *ctx, struct fw_packet *packet) | 652 | at_context_transmit(struct at_context *ctx, struct fw_packet *packet) |
546 | { | 653 | { |
547 | LIST_HEAD(list); | 654 | LIST_HEAD(list); |
548 | unsigned long flags; | 655 | unsigned long flags; |
549 | int local; | ||
550 | 656 | ||
551 | spin_lock_irqsave(&ctx->ohci->lock, flags); | 657 | spin_lock_irqsave(&ctx->ohci->lock, flags); |
552 | 658 | ||
553 | if (header_get_destination(packet->header[0]) == ctx->ohci->node_id && | 659 | if (header_get_destination(packet->header[0]) == ctx->ohci->node_id && |
554 | ctx->ohci->generation == packet->generation) { | 660 | ctx->ohci->generation == packet->generation) { |
555 | local = 1; | 661 | spin_unlock_irqrestore(&ctx->ohci->lock, flags); |
556 | } else { | 662 | handle_local_request(ctx, packet); |
557 | list_add_tail(&packet->link, &ctx->list); | 663 | return; |
558 | if (ctx->list.next == &packet->link) | ||
559 | at_context_setup_packet(ctx, &list); | ||
560 | local = 0; | ||
561 | } | 664 | } |
562 | 665 | ||
666 | list_add_tail(&packet->link, &ctx->list); | ||
667 | if (ctx->list.next == &packet->link) | ||
668 | at_context_setup_packet(ctx, &list); | ||
669 | |||
563 | spin_unlock_irqrestore(&ctx->ohci->lock, flags); | 670 | spin_unlock_irqrestore(&ctx->ohci->lock, flags); |
564 | 671 | ||
565 | do_packet_callbacks(ctx->ohci, &list); | 672 | do_packet_callbacks(ctx->ohci, &list); |
566 | |||
567 | if (local) { | ||
568 | packet->ack = ACK_PENDING; | ||
569 | packet->callback(packet, &ctx->ohci->card, packet->ack); | ||
570 | if (ctx == &ctx->ohci->at_request_ctx) | ||
571 | fw_core_handle_request(&ctx->ohci->card, packet); | ||
572 | else | ||
573 | fw_core_handle_response(&ctx->ohci->card, packet); | ||
574 | } | ||
575 | } | 673 | } |
576 | 674 | ||
577 | static void bus_reset_tasklet(unsigned long data) | 675 | static void bus_reset_tasklet(unsigned long data) |