aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firewire
diff options
context:
space:
mode:
authorStefan Richter <stefanr@s5r6.in-berlin.de>2010-07-16 16:25:51 -0400
committerStefan Richter <stefanr@s5r6.in-berlin.de>2010-07-23 07:36:28 -0400
commitbf54e1462b9192fdef7ea9e2bc44fdc16a4b87bc (patch)
tree31ec8e4e13b76d22b7bf9f93ea620e88911fe416 /drivers/firewire
parent850bb6f23b93c04ce1e4509a87fa607dc17d97c1 (diff)
firewire: cdev: add PHY packet reception
Add an FW_CDEV_IOC_RECEIVE_PHY_PACKETS ioctl() and FW_CDEV_EVENT_PHY_PACKET_RECEIVED poll()/read() event for /dev/fw*. This can be used to get information from remote PHYs by remote access PHY packets. This is also the 2nd half of the functionality (the receive part) to support a userspace implementation of a VersaPHY transaction layer. Safety considerations: - PHY packets are generally broadcasts, hence some kind of elevated privileges should be required of a process to be able to listen in on PHY packets. This implementation assumes that a process that is allowed to open the /dev/fw* of a local node does have this privilege. There was an inconclusive discussion about introducing POSIX capabilities as a means to check for user privileges for these kinds of operations. Other limitations: - PHY packet reception may be switched on by ioctl() but cannot be switched off again. It would be trivial to provide an off switch, but this is not worth the code. The client should simply close() the fd then, or just ignore further events. - For sake of simplicity of API and kernel-side implementation, no filter per packet content is provided. Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers/firewire')
-rw-r--r--drivers/firewire/core-card.c1
-rw-r--r--drivers/firewire/core-cdev.c73
-rw-r--r--drivers/firewire/core-transaction.c5
-rw-r--r--drivers/firewire/core.h2
-rw-r--r--drivers/firewire/ohci.c3
5 files changed, 77 insertions, 7 deletions
diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c
index 0c312c4bb4bd..6d1cfae6aad4 100644
--- a/drivers/firewire/core-card.c
+++ b/drivers/firewire/core-card.c
@@ -500,6 +500,7 @@ void fw_card_initialize(struct fw_card *card,
500 kref_init(&card->kref); 500 kref_init(&card->kref);
501 init_completion(&card->done); 501 init_completion(&card->done);
502 INIT_LIST_HEAD(&card->transaction_list); 502 INIT_LIST_HEAD(&card->transaction_list);
503 INIT_LIST_HEAD(&card->phy_receiver_list);
503 spin_lock_init(&card->lock); 504 spin_lock_init(&card->lock);
504 505
505 card->local_node = NULL; 506 card->local_node = NULL;
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c
index f95719926487..0425dd5dfcd3 100644
--- a/drivers/firewire/core-cdev.c
+++ b/drivers/firewire/core-cdev.c
@@ -69,6 +69,9 @@ struct client {
69 struct fw_iso_buffer buffer; 69 struct fw_iso_buffer buffer;
70 unsigned long vm_start; 70 unsigned long vm_start;
71 71
72 struct list_head phy_receiver_link;
73 u64 phy_receiver_closure;
74
72 struct list_head link; 75 struct list_head link;
73 struct kref kref; 76 struct kref kref;
74}; 77};
@@ -201,6 +204,11 @@ struct outbound_phy_packet_event {
201 struct fw_cdev_event_phy_packet phy_packet; 204 struct fw_cdev_event_phy_packet phy_packet;
202}; 205};
203 206
207struct inbound_phy_packet_event {
208 struct event event;
209 struct fw_cdev_event_phy_packet phy_packet;
210};
211
204static inline void __user *u64_to_uptr(__u64 value) 212static inline void __user *u64_to_uptr(__u64 value)
205{ 213{
206 return (void __user *)(unsigned long)value; 214 return (void __user *)(unsigned long)value;
@@ -236,6 +244,7 @@ static int fw_device_op_open(struct inode *inode, struct file *file)
236 idr_init(&client->resource_idr); 244 idr_init(&client->resource_idr);
237 INIT_LIST_HEAD(&client->event_list); 245 INIT_LIST_HEAD(&client->event_list);
238 init_waitqueue_head(&client->wait); 246 init_waitqueue_head(&client->wait);
247 INIT_LIST_HEAD(&client->phy_receiver_link);
239 kref_init(&client->kref); 248 kref_init(&client->kref);
240 249
241 file->private_data = client; 250 file->private_data = client;
@@ -357,7 +366,7 @@ static void queue_bus_reset_event(struct client *client)
357 366
358 e = kzalloc(sizeof(*e), GFP_KERNEL); 367 e = kzalloc(sizeof(*e), GFP_KERNEL);
359 if (e == NULL) { 368 if (e == NULL) {
360 fw_notify("Out of memory when allocating bus reset event\n"); 369 fw_notify("Out of memory when allocating event\n");
361 return; 370 return;
362 } 371 }
363 372
@@ -404,6 +413,7 @@ union ioctl_arg {
404 struct fw_cdev_send_stream_packet send_stream_packet; 413 struct fw_cdev_send_stream_packet send_stream_packet;
405 struct fw_cdev_get_cycle_timer2 get_cycle_timer2; 414 struct fw_cdev_get_cycle_timer2 get_cycle_timer2;
406 struct fw_cdev_send_phy_packet send_phy_packet; 415 struct fw_cdev_send_phy_packet send_phy_packet;
416 struct fw_cdev_receive_phy_packets receive_phy_packets;
407}; 417};
408 418
409static int ioctl_get_info(struct client *client, union ioctl_arg *arg) 419static int ioctl_get_info(struct client *client, union ioctl_arg *arg)
@@ -671,9 +681,10 @@ static void handle_request(struct fw_card *card, struct fw_request *request,
671 681
672 r = kmalloc(sizeof(*r), GFP_ATOMIC); 682 r = kmalloc(sizeof(*r), GFP_ATOMIC);
673 e = kmalloc(sizeof(*e), GFP_ATOMIC); 683 e = kmalloc(sizeof(*e), GFP_ATOMIC);
674 if (r == NULL || e == NULL) 684 if (r == NULL || e == NULL) {
685 fw_notify("Out of memory when allocating event\n");
675 goto failed; 686 goto failed;
676 687 }
677 r->card = card; 688 r->card = card;
678 r->request = request; 689 r->request = request;
679 r->data = payload; 690 r->data = payload;
@@ -902,9 +913,10 @@ static void iso_callback(struct fw_iso_context *context, u32 cycle,
902 struct iso_interrupt_event *e; 913 struct iso_interrupt_event *e;
903 914
904 e = kmalloc(sizeof(*e) + header_length, GFP_ATOMIC); 915 e = kmalloc(sizeof(*e) + header_length, GFP_ATOMIC);
905 if (e == NULL) 916 if (e == NULL) {
917 fw_notify("Out of memory when allocating event\n");
906 return; 918 return;
907 919 }
908 e->interrupt.type = FW_CDEV_EVENT_ISO_INTERRUPT; 920 e->interrupt.type = FW_CDEV_EVENT_ISO_INTERRUPT;
909 e->interrupt.closure = client->iso_closure; 921 e->interrupt.closure = client->iso_closure;
910 e->interrupt.cycle = cycle; 922 e->interrupt.cycle = cycle;
@@ -1447,6 +1459,52 @@ static int ioctl_send_phy_packet(struct client *client, union ioctl_arg *arg)
1447 return 0; 1459 return 0;
1448} 1460}
1449 1461
1462static int ioctl_receive_phy_packets(struct client *client, union ioctl_arg *arg)
1463{
1464 struct fw_cdev_receive_phy_packets *a = &arg->receive_phy_packets;
1465 struct fw_card *card = client->device->card;
1466
1467 /* Access policy: Allow this ioctl only on local nodes' device files. */
1468 if (!client->device->is_local)
1469 return -ENOSYS;
1470
1471 spin_lock_irq(&card->lock);
1472
1473 list_move_tail(&client->phy_receiver_link, &card->phy_receiver_list);
1474 client->phy_receiver_closure = a->closure;
1475
1476 spin_unlock_irq(&card->lock);
1477
1478 return 0;
1479}
1480
1481void fw_cdev_handle_phy_packet(struct fw_card *card, struct fw_packet *p)
1482{
1483 struct client *client;
1484 struct inbound_phy_packet_event *e;
1485 unsigned long flags;
1486
1487 spin_lock_irqsave(&card->lock, flags);
1488
1489 list_for_each_entry(client, &card->phy_receiver_list, phy_receiver_link) {
1490 e = kmalloc(sizeof(*e) + 8, GFP_ATOMIC);
1491 if (e == NULL) {
1492 fw_notify("Out of memory when allocating event\n");
1493 break;
1494 }
1495 e->phy_packet.closure = client->phy_receiver_closure;
1496 e->phy_packet.type = FW_CDEV_EVENT_PHY_PACKET_RECEIVED;
1497 e->phy_packet.rcode = RCODE_COMPLETE;
1498 e->phy_packet.length = 8;
1499 e->phy_packet.data[0] = p->header[1];
1500 e->phy_packet.data[1] = p->header[2];
1501 queue_event(client, &e->event,
1502 &e->phy_packet, sizeof(e->phy_packet) + 8, NULL, 0);
1503 }
1504
1505 spin_unlock_irqrestore(&card->lock, flags);
1506}
1507
1450static int (* const ioctl_handlers[])(struct client *, union ioctl_arg *) = { 1508static int (* const ioctl_handlers[])(struct client *, union ioctl_arg *) = {
1451 [0x00] = ioctl_get_info, 1509 [0x00] = ioctl_get_info,
1452 [0x01] = ioctl_send_request, 1510 [0x01] = ioctl_send_request,
@@ -1470,6 +1528,7 @@ static int (* const ioctl_handlers[])(struct client *, union ioctl_arg *) = {
1470 [0x13] = ioctl_send_stream_packet, 1528 [0x13] = ioctl_send_stream_packet,
1471 [0x14] = ioctl_get_cycle_timer2, 1529 [0x14] = ioctl_get_cycle_timer2,
1472 [0x15] = ioctl_send_phy_packet, 1530 [0x15] = ioctl_send_phy_packet,
1531 [0x16] = ioctl_receive_phy_packets,
1473}; 1532};
1474 1533
1475static int dispatch_ioctl(struct client *client, 1534static int dispatch_ioctl(struct client *client,
@@ -1577,6 +1636,10 @@ static int fw_device_op_release(struct inode *inode, struct file *file)
1577 struct client *client = file->private_data; 1636 struct client *client = file->private_data;
1578 struct event *event, *next_event; 1637 struct event *event, *next_event;
1579 1638
1639 spin_lock_irq(&client->device->card->lock);
1640 list_del(&client->phy_receiver_link);
1641 spin_unlock_irq(&client->device->card->lock);
1642
1580 mutex_lock(&client->device->client_list_mutex); 1643 mutex_lock(&client->device->client_list_mutex);
1581 list_del(&client->link); 1644 list_del(&client->link);
1582 mutex_unlock(&client->device->client_list_mutex); 1645 mutex_unlock(&client->device->client_list_mutex);
diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c
index e2e4dc624fb6..6f225cacbc3d 100644
--- a/drivers/firewire/core-transaction.c
+++ b/drivers/firewire/core-transaction.c
@@ -883,6 +883,11 @@ void fw_core_handle_request(struct fw_card *card, struct fw_packet *p)
883 if (p->ack != ACK_PENDING && p->ack != ACK_COMPLETE) 883 if (p->ack != ACK_PENDING && p->ack != ACK_COMPLETE)
884 return; 884 return;
885 885
886 if (TCODE_IS_LINK_INTERNAL(HEADER_GET_TCODE(p->header[0]))) {
887 fw_cdev_handle_phy_packet(card, p);
888 return;
889 }
890
886 request = allocate_request(card, p); 891 request = allocate_request(card, p);
887 if (request == NULL) { 892 if (request == NULL) {
888 /* FIXME: send statically allocated busy packet. */ 893 /* FIXME: send statically allocated busy packet. */
diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h
index ff6c90922001..3102b6b63438 100644
--- a/drivers/firewire/core.h
+++ b/drivers/firewire/core.h
@@ -128,6 +128,7 @@ extern const struct file_operations fw_device_ops;
128 128
129void fw_device_cdev_update(struct fw_device *device); 129void fw_device_cdev_update(struct fw_device *device);
130void fw_device_cdev_remove(struct fw_device *device); 130void fw_device_cdev_remove(struct fw_device *device);
131void fw_cdev_handle_phy_packet(struct fw_card *card, struct fw_packet *p);
131 132
132 133
133/* -device */ 134/* -device */
@@ -214,6 +215,7 @@ static inline bool is_next_generation(int new_generation, int old_generation)
214 215
215#define TCODE_IS_READ_REQUEST(tcode) (((tcode) & ~1) == 4) 216#define TCODE_IS_READ_REQUEST(tcode) (((tcode) & ~1) == 4)
216#define TCODE_IS_BLOCK_PACKET(tcode) (((tcode) & 1) != 0) 217#define TCODE_IS_BLOCK_PACKET(tcode) (((tcode) & 1) != 0)
218#define TCODE_IS_LINK_INTERNAL(tcode) ((tcode) == 0xe)
217#define TCODE_IS_REQUEST(tcode) (((tcode) & 2) == 0) 219#define TCODE_IS_REQUEST(tcode) (((tcode) & 2) == 0)
218#define TCODE_IS_RESPONSE(tcode) (((tcode) & 2) != 0) 220#define TCODE_IS_RESPONSE(tcode) (((tcode) & 2) != 0)
219#define TCODE_HAS_REQUEST_DATA(tcode) (((tcode) & 12) != 4) 221#define TCODE_HAS_REQUEST_DATA(tcode) (((tcode) & 12) != 4)
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c
index bb6a92bc9e6a..08afccc66333 100644
--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -1759,10 +1759,9 @@ static int ohci_enable(struct fw_card *card,
1759 OHCI1394_HCControl_noByteSwapData); 1759 OHCI1394_HCControl_noByteSwapData);
1760 1760
1761 reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->self_id_bus); 1761 reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->self_id_bus);
1762 reg_write(ohci, OHCI1394_LinkControlClear,
1763 OHCI1394_LinkControl_rcvPhyPkt);
1764 reg_write(ohci, OHCI1394_LinkControlSet, 1762 reg_write(ohci, OHCI1394_LinkControlSet,
1765 OHCI1394_LinkControl_rcvSelfID | 1763 OHCI1394_LinkControl_rcvSelfID |
1764 OHCI1394_LinkControl_rcvPhyPkt |
1766 OHCI1394_LinkControl_cycleTimerEnable | 1765 OHCI1394_LinkControl_cycleTimerEnable |
1767 OHCI1394_LinkControl_cycleMaster); 1766 OHCI1394_LinkControl_cycleMaster);
1768 1767