Commit 406fb9eb authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull firewire updates from Takashi Sakamoto:
 "This consist of three parts; UAPI update, OHCI driver update, and
  several bug fixes.

  Firstly, the 1394 OHCI specification defines method to retrieve
  hardware time stamps for asynchronous communication, which was
  previously unavailable in user space. This adds new events to the
  UAPI, allowing applications to retrieve the time when asynchronous
  packet are received and sent. The new events are tested in the
  bleeding edge of libhinawa and look to work well. The new version of
  libhinawa will be released after current merge window is closed:

    https://git.kernel.org/pub/scm/libs/ieee1394/libhinawa.git/

  Secondly, the FireWire stack includes a PCM device driver for 1394
  OHCI hardware, This change modernizes the driver by managed resource
  (devres) framework.

  Lastly, bug fixes for firewire-net and firewire-core"

* tag 'firewire-6.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394: (25 commits)
  firewire: net: fix use after free in fwnet_finish_incoming_packet()
  firewire: core: obsolete usage of GFP_ATOMIC at building node tree
  firewire: ohci: release buffer for AR req/resp contexts when managed resource is released
  firewire: ohci: use devres for content of configuration ROM
  firewire: ohci: use devres for IT, IR, AT/receive, and AT/request contexts
  firewire: ohci: use devres for list of isochronous contexts
  firewire: ohci: use devres for requested IRQ
  firewire: ohci: use devres for misc DMA buffer
  firewire: ohci: use devres for MMIO region mapping
  firewire: ohci: use devres for PCI-related resources
  firewire: ohci: use devres for memory object of ohci structure
  firewire: fix warnings to generate UAPI documentation
  firewire: fix build failure due to missing module license
  firewire: cdev: implement new event relevant to phy packet with time stamp
  firewire: cdev: add new event to notify phy packet with time stamp
  firewire: cdev: code refactoring to dispatch event for phy packet
  firewire: cdev: implement new event to notify response subaction with time stamp
  firewire: cdev: add new event to notify response subaction with time stamp
  firewire: cdev: code refactoring to operate event of response
  firewire: core: implement variations to send request and wait for response with time stamp
  ...
parents f1962207 3ff25675
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
CONFIG_KUNIT=y
CONFIG_PCI=y
CONFIG_FIREWIRE=y
CONFIG_FIREWIRE_KUNIT_UAPI_TEST=y
+16 −0
Original line number Diff line number Diff line
@@ -18,6 +18,22 @@ config FIREWIRE
	  To compile this driver as a module, say M here: the module will be
	  called firewire-core.

config FIREWIRE_KUNIT_UAPI_TEST
	tristate "KUnit tests for layout of structure in UAPI" if !KUNIT_ALL_TESTS
	depends on FIREWIRE && KUNIT
	default KUNIT_ALL_TESTS
	help
	  This builds the KUnit tests whether structures exposed to user
	  space have expected layout.

	  KUnit tests run during boot and output the results to the debug
	  log in TAP format (https://testanything.org/). Only useful for
	  kernel devs running KUnit test harness and are not for inclusion
	  into a production build.

	  For more information on KUnit and unit tests in general, refer
	  to the KUnit documentation in Documentation/dev-tools/kunit/.

config FIREWIRE_OHCI
	tristate "OHCI-1394 controllers"
	depends on PCI && FIREWIRE && MMU
+3 −0
Original line number Diff line number Diff line
@@ -15,3 +15,6 @@ obj-$(CONFIG_FIREWIRE_SBP2) += firewire-sbp2.o
obj-$(CONFIG_FIREWIRE_NET)  += firewire-net.o
obj-$(CONFIG_FIREWIRE_NOSY) += nosy.o
obj-$(CONFIG_PROVIDE_OHCI1394_DMA_INIT) += init_ohci1394_dma.o

firewire-uapi-test-objs += uapi-test.o
obj-$(CONFIG_FIREWIRE_KUNIT_UAPI_TEST) += firewire-uapi-test.o
+188 −64
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@
#define FW_CDEV_VERSION_EVENT_REQUEST2		4
#define FW_CDEV_VERSION_ALLOCATE_REGION_END	4
#define FW_CDEV_VERSION_AUTO_FLUSH_ISO_OVERFLOW	5
#define FW_CDEV_VERSION_EVENT_ASYNC_TSTAMP	6

struct client {
	u32 version;
@@ -169,7 +170,10 @@ struct outbound_transaction_event {
	struct event event;
	struct client *client;
	struct outbound_transaction_resource r;
	struct fw_cdev_event_response response;
	union {
		struct fw_cdev_event_response without_tstamp;
		struct fw_cdev_event_response2 with_tstamp;
	} rsp;
};

struct inbound_transaction_event {
@@ -177,6 +181,7 @@ struct inbound_transaction_event {
	union {
		struct fw_cdev_event_request request;
		struct fw_cdev_event_request2 request2;
		struct fw_cdev_event_request3 with_tstamp;
	} req;
};

@@ -199,12 +204,18 @@ struct outbound_phy_packet_event {
	struct event event;
	struct client *client;
	struct fw_packet p;
	struct fw_cdev_event_phy_packet phy_packet;
	union {
		struct fw_cdev_event_phy_packet without_tstamp;
		struct fw_cdev_event_phy_packet2 with_tstamp;
	} phy_packet;
};

struct inbound_phy_packet_event {
	struct event event;
	struct fw_cdev_event_phy_packet phy_packet;
	union {
		struct fw_cdev_event_phy_packet without_tstamp;
		struct fw_cdev_event_phy_packet2 with_tstamp;
	} phy_packet;
};

#ifdef CONFIG_COMPAT
@@ -534,41 +545,64 @@ static void release_transaction(struct client *client,
{
}

static void complete_transaction(struct fw_card *card, int rcode,
				 void *payload, size_t length, void *data)
static void complete_transaction(struct fw_card *card, int rcode, u32 request_tstamp,
				 u32 response_tstamp, void *payload, size_t length, void *data)
{
	struct outbound_transaction_event *e = data;
	struct fw_cdev_event_response *rsp = &e->response;
	struct client *client = e->client;
	unsigned long flags;

	if (length < rsp->length)
		rsp->length = length;
	if (rcode == RCODE_COMPLETE)
		memcpy(rsp->data, payload, rsp->length);

	spin_lock_irqsave(&client->lock, flags);
	idr_remove(&client->resource_idr, e->r.resource.handle);
	if (client->in_shutdown)
		wake_up(&client->tx_flush_wait);
	spin_unlock_irqrestore(&client->lock, flags);

	rsp->type = FW_CDEV_EVENT_RESPONSE;
	switch (e->rsp.without_tstamp.type) {
	case FW_CDEV_EVENT_RESPONSE:
	{
		struct fw_cdev_event_response *rsp = &e->rsp.without_tstamp;

		if (length < rsp->length)
			rsp->length = length;
		if (rcode == RCODE_COMPLETE)
			memcpy(rsp->data, payload, rsp->length);

		rsp->rcode = rcode;

	/*
	 * In the case that sizeof(*rsp) doesn't align with the position of the
	 * data, and the read is short, preserve an extra copy of the data
	 * to stay compatible with a pre-2.6.27 bug.  Since the bug is harmless
	 * for short reads and some apps depended on it, this is both safe
	 * and prudent for compatibility.
	 */
		// In the case that sizeof(*rsp) doesn't align with the position of the
		// data, and the read is short, preserve an extra copy of the data
		// to stay compatible with a pre-2.6.27 bug.  Since the bug is harmless
		// for short reads and some apps depended on it, this is both safe
		// and prudent for compatibility.
		if (rsp->length <= sizeof(*rsp) - offsetof(typeof(*rsp), data))
		queue_event(client, &e->event, rsp, sizeof(*rsp),
			    rsp->data, rsp->length);
			queue_event(client, &e->event, rsp, sizeof(*rsp), rsp->data, rsp->length);
		else
		queue_event(client, &e->event, rsp, sizeof(*rsp) + rsp->length,
			    NULL, 0);
			queue_event(client, &e->event, rsp, sizeof(*rsp) + rsp->length, NULL, 0);

		break;
	}
	case FW_CDEV_EVENT_RESPONSE2:
	{
		struct fw_cdev_event_response2 *rsp = &e->rsp.with_tstamp;

		if (length < rsp->length)
			rsp->length = length;
		if (rcode == RCODE_COMPLETE)
			memcpy(rsp->data, payload, rsp->length);

		rsp->rcode = rcode;
		rsp->request_tstamp = request_tstamp;
		rsp->response_tstamp = response_tstamp;

		queue_event(client, &e->event, rsp, sizeof(*rsp) + rsp->length, NULL, 0);

		break;
	default:
		WARN_ON(1);
		break;
	}
	}

	/* Drop the idr's reference */
	client_put(client);
@@ -579,6 +613,7 @@ static int init_request(struct client *client,
			int destination_id, int speed)
{
	struct outbound_transaction_event *e;
	void *payload;
	int ret;

	if (request->tcode != TCODE_STREAM_DATA &&
@@ -592,14 +627,25 @@ static int init_request(struct client *client,
	e = kmalloc(sizeof(*e) + request->length, GFP_KERNEL);
	if (e == NULL)
		return -ENOMEM;

	e->client = client;
	e->response.length = request->length;
	e->response.closure = request->closure;

	if (request->data &&
	    copy_from_user(e->response.data,
			   u64_to_uptr(request->data), request->length)) {
	if (client->version < FW_CDEV_VERSION_EVENT_ASYNC_TSTAMP) {
		struct fw_cdev_event_response *rsp = &e->rsp.without_tstamp;

		rsp->type = FW_CDEV_EVENT_RESPONSE;
		rsp->length = request->length;
		rsp->closure = request->closure;
		payload = rsp->data;
	} else {
		struct fw_cdev_event_response2 *rsp = &e->rsp.with_tstamp;

		rsp->type = FW_CDEV_EVENT_RESPONSE2;
		rsp->length = request->length;
		rsp->closure = request->closure;
		payload = rsp->data;
	}

	if (request->data && copy_from_user(payload, u64_to_uptr(request->data), request->length)) {
		ret = -EFAULT;
		goto failed;
	}
@@ -609,10 +655,9 @@ static int init_request(struct client *client,
	if (ret < 0)
		goto failed;

	fw_send_request(client->device->card, &e->r.transaction,
			request->tcode, destination_id, request->generation,
			speed, request->offset, e->response.data,
			request->length, complete_transaction, e);
	fw_send_request_with_tstamp(client->device->card, &e->r.transaction, request->tcode,
				    destination_id, request->generation, speed, request->offset,
				    payload, request->length, complete_transaction, e);
	return 0;

 failed:
@@ -708,7 +753,7 @@ static void handle_request(struct fw_card *card, struct fw_request *request,
		req->handle	= r->resource.handle;
		req->closure	= handler->closure;
		event_size0	= sizeof(*req);
	} else {
	} else if (handler->client->version < FW_CDEV_VERSION_EVENT_ASYNC_TSTAMP) {
		struct fw_cdev_event_request2 *req = &e->req.request2;

		req->type	= FW_CDEV_EVENT_REQUEST2;
@@ -722,6 +767,21 @@ static void handle_request(struct fw_card *card, struct fw_request *request,
		req->handle	= r->resource.handle;
		req->closure	= handler->closure;
		event_size0	= sizeof(*req);
	} else {
		struct fw_cdev_event_request3 *req = &e->req.with_tstamp;

		req->type	= FW_CDEV_EVENT_REQUEST3;
		req->tcode	= tcode;
		req->offset	= offset;
		req->source_node_id = source;
		req->destination_node_id = destination;
		req->card	= card->index;
		req->generation	= generation;
		req->length	= length;
		req->handle	= r->resource.handle;
		req->closure	= handler->closure;
		req->tstamp	= fw_request_get_timestamp(request);
		event_size0	= sizeof(*req);
	}

	queue_event(handler->client, &e->event,
@@ -1495,26 +1555,61 @@ static void outbound_phy_packet_callback(struct fw_packet *packet,
{
	struct outbound_phy_packet_event *e =
		container_of(packet, struct outbound_phy_packet_event, p);
	struct client *e_client;
	struct client *e_client = e->client;
	u32 rcode;

	switch (status) {
	/* expected: */
	case ACK_COMPLETE:	e->phy_packet.rcode = RCODE_COMPLETE;	break;
	/* should never happen with PHY packets: */
	case ACK_PENDING:	e->phy_packet.rcode = RCODE_COMPLETE;	break;
	// expected:
	case ACK_COMPLETE:
		rcode = RCODE_COMPLETE;
		break;
	// should never happen with PHY packets:
	case ACK_PENDING:
		rcode = RCODE_COMPLETE;
		break;
	case ACK_BUSY_X:
	case ACK_BUSY_A:
	case ACK_BUSY_B:	e->phy_packet.rcode = RCODE_BUSY;	break;
	case ACK_DATA_ERROR:	e->phy_packet.rcode = RCODE_DATA_ERROR;	break;
	case ACK_TYPE_ERROR:	e->phy_packet.rcode = RCODE_TYPE_ERROR;	break;
	/* stale generation; cancelled; on certain controllers: no ack */
	default:		e->phy_packet.rcode = status;		break;
	case ACK_BUSY_B:
		rcode = RCODE_BUSY;
		break;
	case ACK_DATA_ERROR:
		rcode = RCODE_DATA_ERROR;
		break;
	case ACK_TYPE_ERROR:
		rcode = RCODE_TYPE_ERROR;
		break;
	// stale generation; cancelled; on certain controllers: no ack
	default:
		rcode = status;
		break;
	}

	switch (e->phy_packet.without_tstamp.type) {
	case FW_CDEV_EVENT_PHY_PACKET_SENT:
	{
		struct fw_cdev_event_phy_packet *pp = &e->phy_packet.without_tstamp;

		pp->rcode = rcode;
		pp->data[0] = packet->timestamp;
		queue_event(e->client, &e->event, &e->phy_packet, sizeof(*pp) + pp->length,
			    NULL, 0);
		break;
	}
	case FW_CDEV_EVENT_PHY_PACKET_SENT2:
	{
		struct fw_cdev_event_phy_packet2 *pp = &e->phy_packet.with_tstamp;

		pp->rcode = rcode;
		pp->tstamp = packet->timestamp;
		queue_event(e->client, &e->event, &e->phy_packet, sizeof(*pp) + pp->length,
			    NULL, 0);
		break;
	}
	default:
		WARN_ON(1);
		break;
	}
	e->phy_packet.data[0] = packet->timestamp;

	e_client = e->client;
	queue_event(e->client, &e->event, &e->phy_packet,
		    sizeof(e->phy_packet) + e->phy_packet.length, NULL, 0);
	client_put(e_client);
}

@@ -1528,7 +1623,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) + 4, GFP_KERNEL);
	e = kzalloc(sizeof(*e) + sizeof(a->data), GFP_KERNEL);
	if (e == NULL)
		return -ENOMEM;

@@ -1541,10 +1636,24 @@ static int ioctl_send_phy_packet(struct client *client, union ioctl_arg *arg)
	e->p.header[2]		= a->data[1];
	e->p.header_length	= 12;
	e->p.callback		= outbound_phy_packet_callback;
	e->phy_packet.closure	= a->closure;
	e->phy_packet.type	= FW_CDEV_EVENT_PHY_PACKET_SENT;

	if (client->version < FW_CDEV_VERSION_EVENT_ASYNC_TSTAMP) {
		struct fw_cdev_event_phy_packet *pp = &e->phy_packet.without_tstamp;

		pp->closure = a->closure;
		pp->type = FW_CDEV_EVENT_PHY_PACKET_SENT;
		if (is_ping_packet(a->data))
			e->phy_packet.length = 4;
			pp->length = 4;
	} else {
		struct fw_cdev_event_phy_packet2 *pp = &e->phy_packet.with_tstamp;

		pp->closure = a->closure;
		pp->type = FW_CDEV_EVENT_PHY_PACKET_SENT2;
		// Keep the data field so that application can match the response event to the
		// request.
		pp->length = sizeof(a->data);
		memcpy(pp->data, a->data, sizeof(a->data));
	}

	card->driver->send_request(card, &e->p);

@@ -1583,14 +1692,29 @@ void fw_cdev_handle_phy_packet(struct fw_card *card, struct fw_packet *p)
		if (e == NULL)
			break;

		e->phy_packet.closure	= client->phy_receiver_closure;
		e->phy_packet.type	= FW_CDEV_EVENT_PHY_PACKET_RECEIVED;
		e->phy_packet.rcode	= RCODE_COMPLETE;
		e->phy_packet.length	= 8;
		e->phy_packet.data[0]	= p->header[1];
		e->phy_packet.data[1]	= p->header[2];
		queue_event(client, &e->event,
			    &e->phy_packet, sizeof(e->phy_packet) + 8, NULL, 0);
		if (client->version < FW_CDEV_VERSION_EVENT_ASYNC_TSTAMP) {
			struct fw_cdev_event_phy_packet *pp = &e->phy_packet.without_tstamp;

			pp->closure = client->phy_receiver_closure;
			pp->type = FW_CDEV_EVENT_PHY_PACKET_RECEIVED;
			pp->rcode = RCODE_COMPLETE;
			pp->length = 8;
			pp->data[0] = p->header[1];
			pp->data[1] = p->header[2];
			queue_event(client, &e->event, &e->phy_packet, sizeof(*pp) + 8, NULL, 0);
		} else {
			struct fw_cdev_event_phy_packet2 *pp = &e->phy_packet.with_tstamp;

			pp = &e->phy_packet.with_tstamp;
			pp->closure = client->phy_receiver_closure;
			pp->type = FW_CDEV_EVENT_PHY_PACKET_RECEIVED2;
			pp->rcode = RCODE_COMPLETE;
			pp->length = 8;
			pp->tstamp = p->timestamp;
			pp->data[0] = p->header[1];
			pp->data[1] = p->header[2];
			queue_event(client, &e->event, &e->phy_packet, sizeof(*pp) + 8, NULL, 0);
		}
	}

	spin_unlock_irqrestore(&card->lock, flags);
+1 −1
Original line number Diff line number Diff line
@@ -1211,7 +1211,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
		 * without actually having a link.
		 */
 create:
		device = kzalloc(sizeof(*device), GFP_ATOMIC);
		device = kzalloc(sizeof(*device), GFP_KERNEL);
		if (device == NULL)
			break;

Loading