firewire: cdev: add PHY pinging
authorStefan Richter <stefanr@s5r6.in-berlin.de>
Sun, 18 Jul 2010 11:00:50 +0000 (13:00 +0200)
committerStefan Richter <stefanr@s5r6.in-berlin.de>
Fri, 23 Jul 2010 11:36:28 +0000 (13:36 +0200)
This extends the FW_CDEV_IOC_SEND_PHY_PACKET ioctl() for /dev/fw* to be
useful for ping time measurements.  One application for it would be gap
count optimization in userspace that is based on ping times rather than
hop count.  (The latter is implemented in firewire-core itself but is
not applicable to beta PHYs that act as repeater.)

Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
drivers/firewire/core-cdev.c
drivers/firewire/core.h
drivers/firewire/ohci.c
include/linux/firewire-cdev.h

index 0425dd5dfcd39bade92337071f78f9e9731bf7a9..31863cf8b6c4ec5d4fe4ca32802c16e487e0ef60 100644 (file)
@@ -1423,9 +1423,10 @@ static void outbound_phy_packet_callback(struct fw_packet *packet,
        /* stale generation; cancelled; on certain controllers: no ack */
        default:                e->phy_packet.rcode = status;           break;
        }
+       e->phy_packet.data[0] = packet->timestamp;
 
-       queue_event(e->client, &e->event,
-                   &e->phy_packet, sizeof(e->phy_packet), NULL, 0);
+       queue_event(e->client, &e->event, &e->phy_packet,
+                   sizeof(e->phy_packet) + e->phy_packet.length, NULL, 0);
        client_put(e->client);
 }
 
@@ -1439,7 +1440,7 @@ static int ioctl_send_phy_packet(struct client *client, union ioctl_arg *arg)
        if (!client->device->is_local)
                return -ENOSYS;
 
-       e = kzalloc(sizeof(*e), GFP_KERNEL);
+       e = kzalloc(sizeof(*e) + 4, GFP_KERNEL);
        if (e == NULL)
                return -ENOMEM;
 
@@ -1453,6 +1454,8 @@ static int ioctl_send_phy_packet(struct client *client, union ioctl_arg *arg)
        e->p.callback           = outbound_phy_packet_callback;
        e->phy_packet.closure   = a->closure;
        e->phy_packet.type      = FW_CDEV_EVENT_PHY_PACKET_SENT;
+       if (is_ping_packet(a->data))
+                       e->phy_packet.length = 4;
 
        card->driver->send_request(card, &e->p);
 
index 3102b6b63438890fe6984eba19cfdbf677df7b92..28621e44b111f86022ee955226e4968aabd71fa6 100644 (file)
@@ -234,4 +234,9 @@ void fw_fill_response(struct fw_packet *response, u32 *request_header,
 void fw_send_phy_config(struct fw_card *card,
                        int node_id, int generation, int gap_count);
 
+static inline bool is_ping_packet(u32 *data)
+{
+       return (data[0] & 0xc0ffffff) == 0 && ~data[0] == data[1];
+}
+
 #endif /* _FIREWIRE_CORE_H */
index 08afccc66333c877e17882858137a3e025defad1..5f6bb2c53808d49fb11c974f62f6184f25201ec5 100644 (file)
@@ -1068,6 +1068,9 @@ static int at_context_queue_packet(struct context *ctx,
                header[1] = cpu_to_le32(packet->header[0]);
                header[2] = cpu_to_le32(packet->header[1]);
                d[0].req_count = cpu_to_le16(12);
+
+               if (is_ping_packet(packet->header))
+                       d[0].control |= cpu_to_le16(DESCRIPTOR_PING);
                break;
 
        case 4:
index b8740916079441af54e30764a8037d07f3fcef26..da0fec7e8dc0a3a05010f3a5c63d061cb3ba8e58 100644 (file)
@@ -294,7 +294,10 @@ struct fw_cdev_event_iso_resource {
  * @length:    Data length in bytes
  * @data:      Incoming data
  *
- * If @type is %FW_CDEV_EVENT_PHY_PACKET_SENT, @length is 0 and @data empty.
+ * If @type is %FW_CDEV_EVENT_PHY_PACKET_SENT, @length is 0 and @data empty,
+ * except in case of a ping packet:  Then, @length is 4, and @data[0] is the
+ * ping time in 49.152MHz clocks if @rcode is %RCODE_COMPLETE.
+ *
  * If @type is %FW_CDEV_EVENT_PHY_PACKET_RECEIVED, @length is 8 and @data
  * consists of the two PHY packet quadlets, in host byte order.
  */