aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Richter <stefanr@s5r6.in-berlin.de>2010-07-22 05:56:38 -0400
committerStefan Richter <stefanr@s5r6.in-berlin.de>2010-07-27 05:04:11 -0400
commitfd8c8d46ca9402c15383d2cf0bc3ee7740de3b62 (patch)
tree66a33db3ea837f2fb6c66e077a9b5fae7009c3ba
parentc89db7b8bc88d8288dcfbe7a885b950d2560d564 (diff)
firewire: nosy: endianess fixes and annotations
1.) The DMA programs (struct pcl) are PCI-endian = little endian data (except for the 3rd quadlet in a PCL which the controller does not touch). Annotate them as such. Fix all accesses of the PCL to work with big endian CPUs also. Not actually tested, I only have a little endian PC to test with. This includes replacement of a bitfield struct pcl_status by open-coded shift and mask operations. 2.) The two __attribute__ ((packed)) at struct pcl are not really required since it consists of u32/__le32 only, i.e. there will be no padding with or without the attribute. 3.) The received IEEE 1394 data are byteswapped by the controller from IEEE 1394 endian = big endian to PCI endian = little endian because the PCL_BIGENDIAN control bit is set. Therefore annotate the DMA buffer as a __le32 array. Fix the one access of the DMA buffer (the check of the transaction code of link packets) to work with big endian CPUs. Also fix the two accesses of the client bounce buffer (the reading of packet length). 4.) Add a comment to the userspace ABI header that all of the data gets out as little endian data, except for the timestamp which is CPU endian. (We could make it little endian too, but why? Vice versa, an ioctl could be added to dump packet data in big endian byte order...) Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
-rw-r--r--drivers/firewire/nosy-user.h6
-rw-r--r--drivers/firewire/nosy.c74
2 files changed, 29 insertions, 51 deletions
diff --git a/drivers/firewire/nosy-user.h b/drivers/firewire/nosy-user.h
index ebef97f4ecf9..e48aa6200c72 100644
--- a/drivers/firewire/nosy-user.h
+++ b/drivers/firewire/nosy-user.h
@@ -17,9 +17,9 @@ struct nosy_stats {
17/* 17/*
18 * Format of packets returned from the kernel driver: 18 * Format of packets returned from the kernel driver:
19 * 19 *
20 * quadlet with timestamp (microseconds) 20 * quadlet with timestamp (microseconds, CPU endian)
21 * quadlet padded packet data... 21 * quadlet-padded packet data... (little endian)
22 * quadlet with ack 22 * quadlet with ack (little endian)
23 */ 23 */
24 24
25#endif /* __nosy_user_h */ 25#endif /* __nosy_user_h */
diff --git a/drivers/firewire/nosy.c b/drivers/firewire/nosy.c
index b8dcaa28e1ad..225e64956823 100644
--- a/drivers/firewire/nosy.c
+++ b/drivers/firewire/nosy.c
@@ -51,33 +51,19 @@
51 51
52static char driver_name[] = KBUILD_MODNAME; 52static char driver_name[] = KBUILD_MODNAME;
53 53
54struct pcl_status {
55 unsigned int transfer_count : 13;
56 unsigned int reserved0 : 1;
57 unsigned int ack_type : 1;
58 unsigned int ack : 4;
59 unsigned int rcv_speed : 2;
60 unsigned int rcv_dma_channel : 6;
61 unsigned int packet_complete : 1;
62 unsigned int packet_error : 1;
63 unsigned int master_error : 1;
64 unsigned int iso_mode : 1;
65 unsigned int self_id : 1;
66};
67
68/* this is the physical layout of a PCL, its size is 128 bytes */ 54/* this is the physical layout of a PCL, its size is 128 bytes */
69struct pcl { 55struct pcl {
70 u32 next; 56 __le32 next;
71 u32 async_error_next; 57 __le32 async_error_next;
72 u32 user_data; 58 u32 user_data;
73 struct pcl_status pcl_status; 59 __le32 pcl_status;
74 u32 remaining_transfer_count; 60 __le32 remaining_transfer_count;
75 u32 next_data_buffer; 61 __le32 next_data_buffer;
76 struct { 62 struct {
77 u32 control; 63 __le32 control;
78 u32 pointer; 64 __le32 pointer;
79 } buffer[13] __attribute__ ((packed)); 65 } buffer[13];
80} __attribute__ ((packed)); 66};
81 67
82struct packet { 68struct packet {
83 unsigned int length; 69 unsigned int length;
@@ -98,7 +84,7 @@ struct pcilynx {
98 __iomem char *registers; 84 __iomem char *registers;
99 85
100 struct pcl *rcv_start_pcl, *rcv_pcl; 86 struct pcl *rcv_start_pcl, *rcv_pcl;
101 u32 *rcv_buffer; 87 __le32 *rcv_buffer;
102 88
103 dma_addr_t rcv_start_pcl_bus, rcv_pcl_bus, rcv_buffer_bus; 89 dma_addr_t rcv_start_pcl_bus, rcv_pcl_bus, rcv_buffer_bus;
104 90
@@ -426,35 +412,26 @@ static const struct file_operations nosy_ops = {
426 412
427#define PHY_PACKET_SIZE 12 /* 1 payload, 1 inverse, 1 ack = 3 quadlets */ 413#define PHY_PACKET_SIZE 12 /* 1 payload, 1 inverse, 1 ack = 3 quadlets */
428 414
429struct link_packet {
430 unsigned int priority : 4;
431 unsigned int tcode : 4;
432 unsigned int rt : 2;
433 unsigned int tlabel : 6;
434 unsigned int destination : 16;
435};
436
437static void 415static void
438packet_irq_handler(struct pcilynx *lynx) 416packet_irq_handler(struct pcilynx *lynx)
439{ 417{
440 struct client *client; 418 struct client *client;
441 u32 tcode_mask; 419 u32 tcode_mask, tcode;
442 size_t length; 420 size_t length;
443 struct link_packet *packet;
444 struct timeval tv; 421 struct timeval tv;
445 422
446 /* FIXME: Also report rcv_speed. */ 423 /* FIXME: Also report rcv_speed. */
447 424
448 length = lynx->rcv_pcl->pcl_status.transfer_count; 425 length = __le32_to_cpu(lynx->rcv_pcl->pcl_status) & 0x00001fff;
449 packet = (struct link_packet *) &lynx->rcv_buffer[1]; 426 tcode = __le32_to_cpu(lynx->rcv_buffer[1]) >> 4 & 0xf;
450 427
451 do_gettimeofday(&tv); 428 do_gettimeofday(&tv);
452 lynx->rcv_buffer[0] = tv.tv_usec; 429 lynx->rcv_buffer[0] = (__force __le32)tv.tv_usec;
453 430
454 if (length == PHY_PACKET_SIZE) 431 if (length == PHY_PACKET_SIZE)
455 tcode_mask = 1 << TCODE_PHY_PACKET; 432 tcode_mask = 1 << TCODE_PHY_PACKET;
456 else 433 else
457 tcode_mask = 1 << packet->tcode; 434 tcode_mask = 1 << tcode;
458 435
459 spin_lock(&lynx->client_list_lock); 436 spin_lock(&lynx->client_list_lock);
460 437
@@ -602,21 +579,22 @@ add_card(struct pci_dev *dev, const struct pci_device_id *unused)
602 ret = -ENOMEM; 579 ret = -ENOMEM;
603 goto fail_deallocate; 580 goto fail_deallocate;
604 } 581 }
605 lynx->rcv_start_pcl->next = lynx->rcv_pcl_bus; 582 lynx->rcv_start_pcl->next = cpu_to_le32(lynx->rcv_pcl_bus);
606 lynx->rcv_pcl->next = PCL_NEXT_INVALID; 583 lynx->rcv_pcl->next = cpu_to_le32(PCL_NEXT_INVALID);
607 lynx->rcv_pcl->async_error_next = PCL_NEXT_INVALID; 584 lynx->rcv_pcl->async_error_next = cpu_to_le32(PCL_NEXT_INVALID);
608 585
609 lynx->rcv_pcl->buffer[0].control = 586 lynx->rcv_pcl->buffer[0].control =
610 PCL_CMD_RCV | PCL_BIGENDIAN | 2044; 587 cpu_to_le32(PCL_CMD_RCV | PCL_BIGENDIAN | 2044);
611 lynx->rcv_pcl->buffer[0].pointer = lynx->rcv_buffer_bus + 4; 588 lynx->rcv_pcl->buffer[0].pointer =
589 cpu_to_le32(lynx->rcv_buffer_bus + 4);
612 p = lynx->rcv_buffer_bus + 2048; 590 p = lynx->rcv_buffer_bus + 2048;
613 end = lynx->rcv_buffer_bus + RCV_BUFFER_SIZE; 591 end = lynx->rcv_buffer_bus + RCV_BUFFER_SIZE;
614 for (i = 1; p < end; i++, p += 2048) { 592 for (i = 1; p < end; i++, p += 2048) {
615 lynx->rcv_pcl->buffer[i].control = 593 lynx->rcv_pcl->buffer[i].control =
616 PCL_CMD_RCV | PCL_BIGENDIAN | 2048; 594 cpu_to_le32(PCL_CMD_RCV | PCL_BIGENDIAN | 2048);
617 lynx->rcv_pcl->buffer[i].pointer = p; 595 lynx->rcv_pcl->buffer[i].pointer = cpu_to_le32(p);
618 } 596 }
619 lynx->rcv_pcl->buffer[i - 1].control |= PCL_LAST_BUFF; 597 lynx->rcv_pcl->buffer[i - 1].control |= cpu_to_le32(PCL_LAST_BUFF);
620 598
621 reg_set_bits(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET); 599 reg_set_bits(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET);
622 /* Fix buggy cards with autoboot pin not tied low: */ 600 /* Fix buggy cards with autoboot pin not tied low: */