aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firewire
diff options
context:
space:
mode:
authorKristian Høgsberg <krh@redhat.com>2007-01-26 00:38:26 -0500
committerStefan Richter <stefanr@s5r6.in-berlin.de>2007-03-09 16:02:47 -0500
commit93c4cceb963ebb133531e5e3f4f6e2da0d222656 (patch)
tree3d53c8720e64a8f02278b0f958251195574d2caa /drivers/firewire
parent746083d86cf5f874741e3ddecf56ea3ed32959c8 (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')
-rw-r--r--drivers/firewire/fw-ohci.c130
-rw-r--r--drivers/firewire/fw-transaction.c14
-rw-r--r--drivers/firewire/fw-transaction.h31
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
548static void
549handle_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
575static void
576handle_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
617static void
618handle_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
544static void 651static void
545at_context_transmit(struct at_context *ctx, struct fw_packet *packet) 652at_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
577static void bus_reset_tasklet(unsigned long data) 675static 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
428static void 428void
429fw_fill_response(struct fw_packet *response, u32 *request_header, 429fw_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}
484EXPORT_SYMBOL(fw_fill_response);
481 485
482static struct fw_request * 486static struct fw_request *
483allocate_request(struct fw_packet *p) 487allocate_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;
227int fw_core_add_address_handler(struct fw_address_handler *handler, 256int fw_core_add_address_handler(struct fw_address_handler *handler,
228 const struct fw_address_region *region); 257 const struct fw_address_region *region);
229void fw_core_remove_address_handler(struct fw_address_handler *handler); 258void fw_core_remove_address_handler(struct fw_address_handler *handler);
259void fw_fill_response(struct fw_packet *response, u32 *request_header,
260 int rcode, void *payload, size_t length);
230void fw_send_response(struct fw_card *card, 261void fw_send_response(struct fw_card *card,
231 struct fw_request *request, int rcode); 262 struct fw_request *request, int rcode);
232 263