diff options
author | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2010-07-22 05:56:38 -0400 |
---|---|---|
committer | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2010-07-27 05:04:11 -0400 |
commit | fd8c8d46ca9402c15383d2cf0bc3ee7740de3b62 (patch) | |
tree | 66a33db3ea837f2fb6c66e077a9b5fae7009c3ba /drivers/firewire/nosy.c | |
parent | c89db7b8bc88d8288dcfbe7a885b950d2560d564 (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>
Diffstat (limited to 'drivers/firewire/nosy.c')
-rw-r--r-- | drivers/firewire/nosy.c | 74 |
1 files changed, 26 insertions, 48 deletions
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 | ||
52 | static char driver_name[] = KBUILD_MODNAME; | 52 | static char driver_name[] = KBUILD_MODNAME; |
53 | 53 | ||
54 | struct 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 */ |
69 | struct pcl { | 55 | struct 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 | ||
82 | struct packet { | 68 | struct 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 | ||
429 | struct 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 | |||
437 | static void | 415 | static void |
438 | packet_irq_handler(struct pcilynx *lynx) | 416 | packet_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: */ |