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 | |
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>
-rw-r--r-- | drivers/firewire/fw-ohci.c | 130 | ||||
-rw-r--r-- | drivers/firewire/fw-transaction.c | 14 | ||||
-rw-r--r-- | drivers/firewire/fw-transaction.h | 31 |
3 files changed, 154 insertions, 21 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) |
diff --git a/drivers/firewire/fw-transaction.c b/drivers/firewire/fw-transaction.c index a116ffa9bf45..780ed2b44983 100644 --- a/drivers/firewire/fw-transaction.c +++ b/drivers/firewire/fw-transaction.c | |||
@@ -425,7 +425,7 @@ free_response_callback(struct fw_packet *packet, | |||
425 | kfree(request); | 425 | kfree(request); |
426 | } | 426 | } |
427 | 427 | ||
428 | static void | 428 | void |
429 | fw_fill_response(struct fw_packet *response, u32 *request_header, | 429 | fw_fill_response(struct fw_packet *response, u32 *request_header, |
430 | int rcode, void *payload, size_t length) | 430 | int rcode, void *payload, size_t length) |
431 | { | 431 | { |
@@ -457,7 +457,10 @@ fw_fill_response(struct fw_packet *response, u32 *request_header, | |||
457 | case TCODE_READ_QUADLET_REQUEST: | 457 | case TCODE_READ_QUADLET_REQUEST: |
458 | response->header[0] |= | 458 | response->header[0] |= |
459 | header_tcode(TCODE_READ_QUADLET_RESPONSE); | 459 | header_tcode(TCODE_READ_QUADLET_RESPONSE); |
460 | response->header[3] = *(u32 *)payload; | 460 | if (payload != NULL) |
461 | response->header[3] = *(u32 *)payload; | ||
462 | else | ||
463 | response->header[3] = 0; | ||
461 | response->header_length = 16; | 464 | response->header_length = 16; |
462 | response->payload_length = 0; | 465 | response->payload_length = 0; |
463 | break; | 466 | break; |
@@ -478,6 +481,7 @@ fw_fill_response(struct fw_packet *response, u32 *request_header, | |||
478 | return; | 481 | return; |
479 | } | 482 | } |
480 | } | 483 | } |
484 | EXPORT_SYMBOL(fw_fill_response); | ||
481 | 485 | ||
482 | static struct fw_request * | 486 | static struct fw_request * |
483 | allocate_request(struct fw_packet *p) | 487 | allocate_request(struct fw_packet *p) |
@@ -529,9 +533,9 @@ allocate_request(struct fw_packet *p) | |||
529 | request->response.generation = p->generation; | 533 | request->response.generation = p->generation; |
530 | request->response.callback = free_response_callback; | 534 | request->response.callback = free_response_callback; |
531 | request->ack = p->ack; | 535 | request->ack = p->ack; |
532 | request->length = p->payload_length; | 536 | request->length = length; |
533 | if (data) | 537 | if (data) |
534 | memcpy(request->data, p->payload, p->payload_length); | 538 | memcpy(request->data, p->payload, length); |
535 | 539 | ||
536 | memcpy(request->request_header, p->header, sizeof p->header); | 540 | memcpy(request->request_header, p->header, sizeof p->header); |
537 | 541 | ||
@@ -656,7 +660,7 @@ fw_core_handle_response(struct fw_card *card, struct fw_packet *p) | |||
656 | 660 | ||
657 | case TCODE_READ_BLOCK_RESPONSE: | 661 | case TCODE_READ_BLOCK_RESPONSE: |
658 | case TCODE_LOCK_RESPONSE: | 662 | case TCODE_LOCK_RESPONSE: |
659 | data = &p->header[4]; | 663 | data = p->payload; |
660 | data_length = header_get_data_length(p->header[3]); | 664 | data_length = header_get_data_length(p->header[3]); |
661 | break; | 665 | break; |
662 | 666 | ||
diff --git a/drivers/firewire/fw-transaction.h b/drivers/firewire/fw-transaction.h index 903235b142f2..fb46ef78a323 100644 --- a/drivers/firewire/fw-transaction.h +++ b/drivers/firewire/fw-transaction.h | |||
@@ -40,6 +40,7 @@ | |||
40 | #define TCODE_STREAM_DATA 10 | 40 | #define TCODE_STREAM_DATA 10 |
41 | #define TCODE_LOCK_RESPONSE 11 | 41 | #define TCODE_LOCK_RESPONSE 11 |
42 | 42 | ||
43 | #define TCODE_IS_READ_REQUEST(tcode) (((tcode) & ~1) == 4) | ||
43 | #define TCODE_IS_BLOCK_PACKET(tcode) (((tcode) & 1) != 0) | 44 | #define TCODE_IS_BLOCK_PACKET(tcode) (((tcode) & 1) != 0) |
44 | #define TCODE_IS_REQUEST(tcode) (((tcode) & 2) == 0) | 45 | #define TCODE_IS_REQUEST(tcode) (((tcode) & 2) == 0) |
45 | #define TCODE_IS_RESPONSE(tcode) (((tcode) & 2) != 0) | 46 | #define TCODE_IS_RESPONSE(tcode) (((tcode) & 2) != 0) |
@@ -103,6 +104,34 @@ | |||
103 | #define PHY_PACKET_LINK_ON 0x1 | 104 | #define PHY_PACKET_LINK_ON 0x1 |
104 | #define PHY_PACKET_SELF_ID 0x2 | 105 | #define PHY_PACKET_SELF_ID 0x2 |
105 | 106 | ||
107 | #define CSR_REGISTER_BASE 0xfffff0000000ULL | ||
108 | |||
109 | /* register offsets relative to CSR_REGISTER_BASE */ | ||
110 | #define CSR_STATE_CLEAR 0x0 | ||
111 | #define CSR_STATE_SET 0x4 | ||
112 | #define CSR_NODE_IDS 0x8 | ||
113 | #define CSR_RESET_START 0xc | ||
114 | #define CSR_SPLIT_TIMEOUT_HI 0x18 | ||
115 | #define CSR_SPLIT_TIMEOUT_LO 0x1c | ||
116 | #define CSR_CYCLE_TIME 0x200 | ||
117 | #define CSR_BUS_TIME 0x204 | ||
118 | #define CSR_BUSY_TIMEOUT 0x210 | ||
119 | #define CSR_BUS_MANAGER_ID 0x21c | ||
120 | #define CSR_BANDWIDTH_AVAILABLE 0x220 | ||
121 | #define CSR_CHANNELS_AVAILABLE 0x224 | ||
122 | #define CSR_CHANNELS_AVAILABLE_HI 0x224 | ||
123 | #define CSR_CHANNELS_AVAILABLE_LO 0x228 | ||
124 | #define CSR_BROADCAST_CHANNEL 0x234 | ||
125 | #define CSR_CONFIG_ROM 0x400 | ||
126 | #define CSR_CONFIG_ROM_END 0x800 | ||
127 | #define CSR_FCP_COMMAND 0xB00 | ||
128 | #define CSR_FCP_RESPONSE 0xD00 | ||
129 | #define CSR_FCP_END 0xF00 | ||
130 | #define CSR_TOPOLOGY_MAP 0x1000 | ||
131 | #define CSR_TOPOLOGY_MAP_END 0x1400 | ||
132 | #define CSR_SPEED_MAP 0x2000 | ||
133 | #define CSR_SPEED_MAP_END 0x3000 | ||
134 | |||
106 | #define fw_notify(s, args...) printk(KERN_NOTICE KBUILD_MODNAME ": " s, ## args) | 135 | #define fw_notify(s, args...) printk(KERN_NOTICE KBUILD_MODNAME ": " s, ## args) |
107 | #define fw_error(s, args...) printk(KERN_ERR KBUILD_MODNAME ": " s, ## args) | 136 | #define fw_error(s, args...) printk(KERN_ERR KBUILD_MODNAME ": " s, ## args) |
108 | #define fw_debug(s, args...) printk(KERN_DEBUG KBUILD_MODNAME ": " s, ## args) | 137 | #define fw_debug(s, args...) printk(KERN_DEBUG KBUILD_MODNAME ": " s, ## args) |
@@ -227,6 +256,8 @@ extern const struct fw_address_region fw_unit_space_region; | |||
227 | int fw_core_add_address_handler(struct fw_address_handler *handler, | 256 | int fw_core_add_address_handler(struct fw_address_handler *handler, |
228 | const struct fw_address_region *region); | 257 | const struct fw_address_region *region); |
229 | void fw_core_remove_address_handler(struct fw_address_handler *handler); | 258 | void fw_core_remove_address_handler(struct fw_address_handler *handler); |
259 | void fw_fill_response(struct fw_packet *response, u32 *request_header, | ||
260 | int rcode, void *payload, size_t length); | ||
230 | void fw_send_response(struct fw_card *card, | 261 | void fw_send_response(struct fw_card *card, |
231 | struct fw_request *request, int rcode); | 262 | struct fw_request *request, int rcode); |
232 | 263 | ||