diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.c')
| -rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.c | 577 | 
1 files changed, 0 insertions, 577 deletions
diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.c b/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.c deleted file mode 100644 index a8bee1e046aa..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.c +++ /dev/null @@ -1,577 +0,0 @@ -/* - * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#include "msgqueue.h" -#include <engine/falcon.h> - -#include <subdev/secboot.h> - - -#define HDR_SIZE sizeof(struct nvkm_msgqueue_hdr) -#define QUEUE_ALIGNMENT 4 -/* max size of the messages we can receive */ -#define MSG_BUF_SIZE 128 - -static int -msg_queue_open(struct nvkm_msgqueue *priv, struct nvkm_msgqueue_queue *queue) -{ -	struct nvkm_falcon *falcon = priv->falcon; - -	mutex_lock(&queue->mutex); - -	queue->position = nvkm_falcon_rd32(falcon, queue->tail_reg); - -	return 0; -} - -static void -msg_queue_close(struct nvkm_msgqueue *priv, struct nvkm_msgqueue_queue *queue, -		bool commit) -{ -	struct nvkm_falcon *falcon = priv->falcon; - -	if (commit) -		nvkm_falcon_wr32(falcon, queue->tail_reg, queue->position); - -	mutex_unlock(&queue->mutex); -} - -static bool -msg_queue_empty(struct nvkm_msgqueue *priv, struct nvkm_msgqueue_queue *queue) -{ -	struct nvkm_falcon *falcon = priv->falcon; -	u32 head, tail; - -	head = nvkm_falcon_rd32(falcon, queue->head_reg); -	tail = nvkm_falcon_rd32(falcon, queue->tail_reg); - -	return head == tail; -} - -static int -msg_queue_pop(struct nvkm_msgqueue *priv, struct nvkm_msgqueue_queue *queue, -	      void *data, u32 size) -{ -	struct nvkm_falcon *falcon = priv->falcon; -	const struct nvkm_subdev *subdev = priv->falcon->owner; -	u32 head, tail, available; - -	head = nvkm_falcon_rd32(falcon, queue->head_reg); -	/* has the buffer looped? */ -	if (head < queue->position) -		queue->position = queue->offset; - -	tail = queue->position; - -	available = head - tail; - -	if (available == 0) { -		nvkm_warn(subdev, "no message data available\n"); -		return 0; -	} - -	if (size > available) { -		nvkm_warn(subdev, "message data smaller than read request\n"); -		size = available; -	} - -	nvkm_falcon_read_dmem(priv->falcon, tail, size, 0, data); -	queue->position += ALIGN(size, QUEUE_ALIGNMENT); - -	return size; -} - -static int -msg_queue_read(struct nvkm_msgqueue *priv, struct nvkm_msgqueue_queue *queue, -	       struct nvkm_msgqueue_hdr *hdr) -{ -	const struct nvkm_subdev *subdev = priv->falcon->owner; -	int err; - -	err = msg_queue_open(priv, queue); -	if (err) { -		nvkm_error(subdev, "fail to open queue %d\n", queue->index); -		return err; -	} - -	if (msg_queue_empty(priv, queue)) { -		err = 0; -		goto close; -	} - -	err = msg_queue_pop(priv, queue, hdr, HDR_SIZE); -	if (err >= 0 && err != HDR_SIZE) -		err = -EINVAL; -	if (err < 0) { -		nvkm_error(subdev, "failed to read message header: %d\n", err); -		goto close; -	} - -	if (hdr->size > MSG_BUF_SIZE) { -		nvkm_error(subdev, "message too big (%d bytes)\n", hdr->size); -		err = -ENOSPC; -		goto close; -	} - -	if (hdr->size > HDR_SIZE) { -		u32 read_size = hdr->size - HDR_SIZE; - -		err = msg_queue_pop(priv, queue, (hdr + 1), read_size); -		if (err >= 0 && err != read_size) -			err = -EINVAL; -		if (err < 0) { -			nvkm_error(subdev, "failed to read message: %d\n", err); -			goto close; -		} -	} - -close: -	msg_queue_close(priv, queue, (err >= 0)); - -	return err; -} - -static bool -cmd_queue_has_room(struct nvkm_msgqueue *priv, struct nvkm_msgqueue_queue *queue, -		   u32 size, bool *rewind) -{ -	struct nvkm_falcon *falcon = priv->falcon; -	u32 head, tail, free; - -	size = ALIGN(size, QUEUE_ALIGNMENT); - -	head = nvkm_falcon_rd32(falcon, queue->head_reg); -	tail = nvkm_falcon_rd32(falcon, queue->tail_reg); - -	if (head >= tail) { -		free = queue->offset + queue->size - head; -		free -= HDR_SIZE; - -		if (size > free) { -			*rewind = true; -			head = queue->offset; -		} -	} - -	if (head < tail) -		free = tail - head - 1; - -	return size <= free; -} - -static int -cmd_queue_push(struct nvkm_msgqueue *priv, struct nvkm_msgqueue_queue *queue, -	       void *data, u32 size) -{ -	nvkm_falcon_load_dmem(priv->falcon, data, queue->position, size, 0); -	queue->position += ALIGN(size, QUEUE_ALIGNMENT); - -	return 0; -} - -/* REWIND unit is always 0x00 */ -#define MSGQUEUE_UNIT_REWIND 0x00 - -static void -cmd_queue_rewind(struct nvkm_msgqueue *priv, struct nvkm_msgqueue_queue *queue) -{ -	const struct nvkm_subdev *subdev = priv->falcon->owner; -	struct nvkm_msgqueue_hdr cmd; -	int err; - -	cmd.unit_id = MSGQUEUE_UNIT_REWIND; -	cmd.size = sizeof(cmd); -	err = cmd_queue_push(priv, queue, &cmd, cmd.size); -	if (err) -		nvkm_error(subdev, "queue %d rewind failed\n", queue->index); -	else -		nvkm_error(subdev, "queue %d rewinded\n", queue->index); - -	queue->position = queue->offset; -} - -static int -cmd_queue_open(struct nvkm_msgqueue *priv, struct nvkm_msgqueue_queue *queue, -	       u32 size) -{ -	struct nvkm_falcon *falcon = priv->falcon; -	const struct nvkm_subdev *subdev = priv->falcon->owner; -	bool rewind = false; - -	mutex_lock(&queue->mutex); - -	if (!cmd_queue_has_room(priv, queue, size, &rewind)) { -		nvkm_error(subdev, "queue full\n"); -		mutex_unlock(&queue->mutex); -		return -EAGAIN; -	} - -	queue->position = nvkm_falcon_rd32(falcon, queue->head_reg); - -	if (rewind) -		cmd_queue_rewind(priv, queue); - -	return 0; -} - -static void -cmd_queue_close(struct nvkm_msgqueue *priv, struct nvkm_msgqueue_queue *queue, -		bool commit) -{ -	struct nvkm_falcon *falcon = priv->falcon; - -	if (commit) -		nvkm_falcon_wr32(falcon, queue->head_reg, queue->position); - -	mutex_unlock(&queue->mutex); -} - -static int -cmd_write(struct nvkm_msgqueue *priv, struct nvkm_msgqueue_hdr *cmd, -	  struct nvkm_msgqueue_queue *queue) -{ -	const struct nvkm_subdev *subdev = priv->falcon->owner; -	static unsigned timeout = 2000; -	unsigned long end_jiffies = jiffies + msecs_to_jiffies(timeout); -	int ret = -EAGAIN; -	bool commit = true; - -	while (ret == -EAGAIN && time_before(jiffies, end_jiffies)) -		ret = cmd_queue_open(priv, queue, cmd->size); -	if (ret) { -		nvkm_error(subdev, "pmu_queue_open_write failed\n"); -		return ret; -	} - -	ret = cmd_queue_push(priv, queue, cmd, cmd->size); -	if (ret) { -		nvkm_error(subdev, "pmu_queue_push failed\n"); -		commit = false; -	} - -	cmd_queue_close(priv, queue, commit); - -	return ret; -} - -static struct nvkm_msgqueue_seq * -msgqueue_seq_acquire(struct nvkm_msgqueue *priv) -{ -	const struct nvkm_subdev *subdev = priv->falcon->owner; -	struct nvkm_msgqueue_seq *seq; -	u32 index; - -	mutex_lock(&priv->seq_lock); - -	index = find_first_zero_bit(priv->seq_tbl, NVKM_MSGQUEUE_NUM_SEQUENCES); - -	if (index >= NVKM_MSGQUEUE_NUM_SEQUENCES) { -		nvkm_error(subdev, "no free sequence available\n"); -		mutex_unlock(&priv->seq_lock); -		return ERR_PTR(-EAGAIN); -	} - -	set_bit(index, priv->seq_tbl); - -	mutex_unlock(&priv->seq_lock); - -	seq = &priv->seq[index]; -	seq->state = SEQ_STATE_PENDING; - -	return seq; -} - -static void -msgqueue_seq_release(struct nvkm_msgqueue *priv, struct nvkm_msgqueue_seq *seq) -{ -	/* no need to acquire seq_lock since clear_bit is atomic */ -	seq->state = SEQ_STATE_FREE; -	seq->callback = NULL; -	seq->completion = NULL; -	clear_bit(seq->id, priv->seq_tbl); -} - -/* specifies that we want to know the command status in the answer message */ -#define CMD_FLAGS_STATUS BIT(0) -/* specifies that we want an interrupt when the answer message is queued */ -#define CMD_FLAGS_INTR BIT(1) - -int -nvkm_msgqueue_post(struct nvkm_msgqueue *priv, enum msgqueue_msg_priority prio, -		   struct nvkm_msgqueue_hdr *cmd, nvkm_msgqueue_callback cb, -		   struct completion *completion, bool wait_init) -{ -	struct nvkm_msgqueue_seq *seq; -	struct nvkm_msgqueue_queue *queue; -	int ret; - -	if (wait_init && !wait_for_completion_timeout(&priv->init_done, -					 msecs_to_jiffies(1000))) -		return -ETIMEDOUT; - -	queue = priv->func->cmd_queue(priv, prio); -	if (IS_ERR(queue)) -		return PTR_ERR(queue); - -	seq = msgqueue_seq_acquire(priv); -	if (IS_ERR(seq)) -		return PTR_ERR(seq); - -	cmd->seq_id = seq->id; -	cmd->ctrl_flags = CMD_FLAGS_STATUS | CMD_FLAGS_INTR; - -	seq->callback = cb; -	seq->state = SEQ_STATE_USED; -	seq->completion = completion; - -	ret = cmd_write(priv, cmd, queue); -	if (ret) { -		seq->state = SEQ_STATE_PENDING; -		msgqueue_seq_release(priv, seq); -	} - -	return ret; -} - -static int -msgqueue_msg_handle(struct nvkm_msgqueue *priv, struct nvkm_msgqueue_hdr *hdr) -{ -	const struct nvkm_subdev *subdev = priv->falcon->owner; -	struct nvkm_msgqueue_seq *seq; - -	seq = &priv->seq[hdr->seq_id]; -	if (seq->state != SEQ_STATE_USED && seq->state != SEQ_STATE_CANCELLED) { -		nvkm_error(subdev, "msg for unknown sequence %d", seq->id); -		return -EINVAL; -	} - -	if (seq->state == SEQ_STATE_USED) { -		if (seq->callback) -			seq->callback(priv, hdr); -	} - -	if (seq->completion) -		complete(seq->completion); - -	msgqueue_seq_release(priv, seq); - -	return 0; -} - -static int -msgqueue_handle_init_msg(struct nvkm_msgqueue *priv, -			 struct nvkm_msgqueue_hdr *hdr) -{ -	struct nvkm_falcon *falcon = priv->falcon; -	const struct nvkm_subdev *subdev = falcon->owner; -	u32 tail; -	u32 tail_reg; -	int ret; - -	/* -	 * Of course the message queue registers vary depending on the falcon -	 * used... -	 */ -	switch (falcon->owner->index) { -	case NVKM_SUBDEV_PMU: -		tail_reg = 0x4cc; -		break; -	case NVKM_ENGINE_SEC2: -		tail_reg = 0xa34; -		break; -	default: -		nvkm_error(subdev, "falcon %s unsupported for msgqueue!\n", -			   nvkm_subdev_name[falcon->owner->index]); -		return -EINVAL; -	} - -	/* -	 * Read the message - queues are not initialized yet so we cannot rely -	 * on msg_queue_read() -	 */ -	tail = nvkm_falcon_rd32(falcon, tail_reg); -	nvkm_falcon_read_dmem(falcon, tail, HDR_SIZE, 0, hdr); - -	if (hdr->size > MSG_BUF_SIZE) { -		nvkm_error(subdev, "message too big (%d bytes)\n", hdr->size); -		return -ENOSPC; -	} - -	nvkm_falcon_read_dmem(falcon, tail + HDR_SIZE, hdr->size - HDR_SIZE, 0, -			      (hdr + 1)); - -	tail += ALIGN(hdr->size, QUEUE_ALIGNMENT); -	nvkm_falcon_wr32(falcon, tail_reg, tail); - -	ret = priv->func->init_func->init_callback(priv, hdr); -	if (ret) -		return ret; - -	return 0; -} - -void -nvkm_msgqueue_process_msgs(struct nvkm_msgqueue *priv, -			   struct nvkm_msgqueue_queue *queue) -{ -	/* -	 * We are invoked from a worker thread, so normally we have plenty of -	 * stack space to work with. -	 */ -	u8 msg_buffer[MSG_BUF_SIZE]; -	struct nvkm_msgqueue_hdr *hdr = (void *)msg_buffer; -	int ret; - -	/* the first message we receive must be the init message */ -	if ((!priv->init_msg_received)) { -		ret = msgqueue_handle_init_msg(priv, hdr); -		if (!ret) -			priv->init_msg_received = true; -	} else { -		while (msg_queue_read(priv, queue, hdr) > 0) -			msgqueue_msg_handle(priv, hdr); -	} -} - -void -nvkm_msgqueue_write_cmdline(struct nvkm_msgqueue *queue, void *buf) -{ -	if (!queue || !queue->func || !queue->func->init_func) -		return; - -	queue->func->init_func->gen_cmdline(queue, buf); -} - -int -nvkm_msgqueue_acr_boot_falcons(struct nvkm_msgqueue *queue, -			       unsigned long falcon_mask) -{ -	unsigned long falcon; - -	if (!queue || !queue->func->acr_func) -		return -ENODEV; - -	/* Does the firmware support booting multiple falcons? */ -	if (queue->func->acr_func->boot_multiple_falcons) -		return queue->func->acr_func->boot_multiple_falcons(queue, -								   falcon_mask); - -	/* Else boot all requested falcons individually */ -	if (!queue->func->acr_func->boot_falcon) -		return -ENODEV; - -	for_each_set_bit(falcon, &falcon_mask, NVKM_SECBOOT_FALCON_END) { -		int ret = queue->func->acr_func->boot_falcon(queue, falcon); - -		if (ret) -			return ret; -	} - -	return 0; -} - -int -nvkm_msgqueue_new(u32 version, struct nvkm_falcon *falcon, -		  const struct nvkm_secboot *sb, struct nvkm_msgqueue **queue) -{ -	const struct nvkm_subdev *subdev = falcon->owner; -	int ret = -EINVAL; - -	switch (version) { -	case 0x0137c63d: -		ret = msgqueue_0137c63d_new(falcon, sb, queue); -		break; -	case 0x0137bca5: -		ret = msgqueue_0137bca5_new(falcon, sb, queue); -		break; -	case 0x0148cdec: -	case 0x015ccf3e: -	case 0x0167d263: -		ret = msgqueue_0148cdec_new(falcon, sb, queue); -		break; -	default: -		nvkm_error(subdev, "unhandled firmware version 0x%08x\n", -			   version); -		break; -	} - -	if (ret == 0) { -		nvkm_debug(subdev, "firmware version: 0x%08x\n", version); -		(*queue)->fw_version = version; -	} - -	return ret; -} - -void -nvkm_msgqueue_del(struct nvkm_msgqueue **queue) -{ -	if (*queue) { -		(*queue)->func->dtor(*queue); -		*queue = NULL; -	} -} - -void -nvkm_msgqueue_recv(struct nvkm_msgqueue *queue) -{ -	if (!queue->func || !queue->func->recv) { -		const struct nvkm_subdev *subdev = queue->falcon->owner; - -		nvkm_warn(subdev, "missing msgqueue recv function\n"); -		return; -	} - -	queue->func->recv(queue); -} - -int -nvkm_msgqueue_reinit(struct nvkm_msgqueue *queue) -{ -	/* firmware not set yet... */ -	if (!queue) -		return 0; - -	queue->init_msg_received = false; -	reinit_completion(&queue->init_done); - -	return 0; -} - -void -nvkm_msgqueue_ctor(const struct nvkm_msgqueue_func *func, -		   struct nvkm_falcon *falcon, -		   struct nvkm_msgqueue *queue) -{ -	int i; - -	queue->func = func; -	queue->falcon = falcon; -	mutex_init(&queue->seq_lock); -	for (i = 0; i < NVKM_MSGQUEUE_NUM_SEQUENCES; i++) -		queue->seq[i].id = i; - -	init_completion(&queue->init_done); - - -}  |