aboutsummaryrefslogtreecommitdiffstats
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
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>
-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
-rw-r--r--include/linux/firewire-cdev.h39
-rw-r--r--include/linux/firewire.h3
7 files changed, 111 insertions, 15 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
diff --git a/include/linux/firewire-cdev.h b/include/linux/firewire-cdev.h
index 5bc051b9a013..b87409160794 100644
--- a/include/linux/firewire-cdev.h
+++ b/include/linux/firewire-cdev.h
@@ -35,6 +35,7 @@
35/* available since kernel version 2.6.36 */ 35/* available since kernel version 2.6.36 */
36#define FW_CDEV_EVENT_REQUEST2 0x06 36#define FW_CDEV_EVENT_REQUEST2 0x06
37#define FW_CDEV_EVENT_PHY_PACKET_SENT 0x07 37#define FW_CDEV_EVENT_PHY_PACKET_SENT 0x07
38#define FW_CDEV_EVENT_PHY_PACKET_RECEIVED 0x08
38 39
39/** 40/**
40 * struct fw_cdev_event_common - Common part of all fw_cdev_event_ types 41 * struct fw_cdev_event_common - Common part of all fw_cdev_event_ types
@@ -285,16 +286,24 @@ struct fw_cdev_event_iso_resource {
285}; 286};
286 287
287/** 288/**
288 * struct fw_cdev_event_phy_packet - A PHY packet was transmitted 289 * struct fw_cdev_event_phy_packet - A PHY packet was transmitted or received
289 * @closure: See &fw_cdev_event_common; 290 * @closure: See &fw_cdev_event_common; set by %FW_CDEV_IOC_SEND_PHY_PACKET
290 * set by %FW_CDEV_IOC_SEND_PHY_PACKET ioctl 291 * or %FW_CDEV_IOC_RECEIVE_PHY_PACKETS ioctl
291 * @type: %FW_CDEV_EVENT_PHY_PACKET_SENT 292 * @type: %FW_CDEV_EVENT_PHY_PACKET_SENT or %..._RECEIVED
292 * @rcode: %RCODE_..., indicates success or failure of transmission 293 * @rcode: %RCODE_..., indicates success or failure of transmission
294 * @length: Data length in bytes
295 * @data: Incoming data
296 *
297 * If @type is %FW_CDEV_EVENT_PHY_PACKET_SENT, @length is 0 and @data empty.
298 * If @type is %FW_CDEV_EVENT_PHY_PACKET_RECEIVED, @length is 8 and @data
299 * consists of the two PHY packet quadlets, in host byte order.
293 */ 300 */
294struct fw_cdev_event_phy_packet { 301struct fw_cdev_event_phy_packet {
295 __u64 closure; 302 __u64 closure;
296 __u32 type; 303 __u32 type;
297 __u32 rcode; 304 __u32 rcode;
305 __u32 length;
306 __u32 data[0];
298}; 307};
299 308
300/** 309/**
@@ -308,7 +317,9 @@ struct fw_cdev_event_phy_packet {
308 * @iso_resource: Valid if @common.type == 317 * @iso_resource: Valid if @common.type ==
309 * %FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED or 318 * %FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED or
310 * %FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED 319 * %FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED
311 * @phy_packet: Valid if @common.type == %FW_CDEV_EVENT_PHY_PACKET_SENT 320 * @phy_packet: Valid if @common.type ==
321 * %FW_CDEV_EVENT_PHY_PACKET_SENT or
322 * %FW_CDEV_EVENT_PHY_PACKET_RECEIVED
312 * 323 *
313 * Convenience union for userspace use. Events could be read(2) into an 324 * Convenience union for userspace use. Events could be read(2) into an
314 * appropriately aligned char buffer and then cast to this union for further 325 * appropriately aligned char buffer and then cast to this union for further
@@ -360,6 +371,7 @@ union fw_cdev_event {
360 371
361/* available since kernel version 2.6.36 */ 372/* available since kernel version 2.6.36 */
362#define FW_CDEV_IOC_SEND_PHY_PACKET _IOWR('#', 0x15, struct fw_cdev_send_phy_packet) 373#define FW_CDEV_IOC_SEND_PHY_PACKET _IOWR('#', 0x15, struct fw_cdev_send_phy_packet)
374#define FW_CDEV_IOC_RECEIVE_PHY_PACKETS _IOW('#', 0x16, struct fw_cdev_receive_phy_packets)
363 375
364/* 376/*
365 * ABI version history 377 * ABI version history
@@ -376,9 +388,9 @@ union fw_cdev_event {
376 * - shared use and auto-response for FCP registers 388 * - shared use and auto-response for FCP registers
377 * 3 (2.6.34) - made &fw_cdev_get_cycle_timer reliable 389 * 3 (2.6.34) - made &fw_cdev_get_cycle_timer reliable
378 * - added %FW_CDEV_IOC_GET_CYCLE_TIMER2 390 * - added %FW_CDEV_IOC_GET_CYCLE_TIMER2
379 * 4 (2.6.36) - added %FW_CDEV_EVENT_REQUEST2, %FW_CDEV_EVENT_PHY_PACKET_SENT 391 * 4 (2.6.36) - added %FW_CDEV_EVENT_REQUEST2, %FW_CDEV_EVENT_PHY_PACKET_*
380 * - implemented &fw_cdev_event_bus_reset.bm_node_id 392 * - implemented &fw_cdev_event_bus_reset.bm_node_id
381 * - added %FW_CDEV_IOC_SEND_PHY_PACKET 393 * - added %FW_CDEV_IOC_SEND_PHY_PACKET, _RECEIVE_PHY_PACKETS
382 */ 394 */
383#define FW_CDEV_VERSION 3 /* Meaningless; don't use this macro. */ 395#define FW_CDEV_VERSION 3 /* Meaningless; don't use this macro. */
384 396
@@ -850,4 +862,17 @@ struct fw_cdev_send_phy_packet {
850 __u32 generation; 862 __u32 generation;
851}; 863};
852 864
865/**
866 * struct fw_cdev_receive_phy_packets - start reception of PHY packets
867 * @closure: Passed back to userspace in phy packet events
868 *
869 * This ioctl activates issuing of %FW_CDEV_EVENT_PHY_PACKET_RECEIVED due to
870 * incoming PHY packets from any node on the same bus as the device.
871 *
872 * The ioctl is only permitted on device files which represent a local node.
873 */
874struct fw_cdev_receive_phy_packets {
875 __u64 closure;
876};
877
853#endif /* _LINUX_FIREWIRE_CDEV_H */ 878#endif /* _LINUX_FIREWIRE_CDEV_H */
diff --git a/include/linux/firewire.h b/include/linux/firewire.h
index 0c38b8e97722..d974aa4a24c9 100644
--- a/include/linux/firewire.h
+++ b/include/linux/firewire.h
@@ -111,9 +111,10 @@ struct fw_card {
111 bool beta_repeaters_present; 111 bool beta_repeaters_present;
112 112
113 int index; 113 int index;
114
115 struct list_head link; 114 struct list_head link;
116 115
116 struct list_head phy_receiver_list;
117
117 struct delayed_work br_work; /* bus reset job */ 118 struct delayed_work br_work; /* bus reset job */
118 bool br_short; 119 bool br_short;
119 120