Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 394a77d0 authored by Alexander Usyskin's avatar Alexander Usyskin Committed by Greg Kroah-Hartman
Browse files

mei: drop amthif internal client



AMTHIF has special support in the mei drive, it handles multiplexing
multiple user space connection above single me client connection.
Since there is no additional addressing information there is a strict
requirement on the traffic order on each connection and on the "read
after write" order within the connection. This creates a lot of
complexity mostly because the other client types do not necessarily fall
under the same restriction.    After carefully studying the use of the
AMTHIF client, we came to conclusion that the multiplexing is not really
utilized by any application and we may safely remove that support and
significantly simplify the driver.

Signed-off-by: default avatarAlexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: default avatarTomas Winkler <tomas.winkler@intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 5c4c0106
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -8,7 +8,6 @@ mei-objs += hbm.o
mei-objs += interrupt.o
mei-objs += client.o
mei-objs += main.o
mei-objs += amthif.o
mei-objs += bus.o
mei-objs += bus-fixup.o
mei-$(CONFIG_DEBUG_FS) += debugfs.o

drivers/misc/mei/amthif.c

deleted100644 → 0
+0 −340
Original line number Diff line number Diff line
/*
 *
 * Intel Management Engine Interface (Intel MEI) Linux driver
 * Copyright (c) 2003-2012, Intel Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 */

#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/list.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/uuid.h>
#include <linux/jiffies.h>
#include <linux/uaccess.h>
#include <linux/slab.h>

#include <linux/mei.h>

#include "mei_dev.h"
#include "hbm.h"
#include "client.h"

const uuid_le mei_amthif_guid  = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d,
					 0xac, 0xa8, 0x46, 0xe0,
					 0xff, 0x65, 0x81, 0x4c);

/**
 * mei_amthif_reset_params - initializes mei device iamthif
 *
 * @dev: the device structure
 */
void mei_amthif_reset_params(struct mei_device *dev)
{
	/* reset iamthif parameters. */
	dev->iamthif_canceled = false;
	dev->iamthif_state = MEI_IAMTHIF_IDLE;
	dev->iamthif_stall_timer = 0;
	dev->iamthif_open_count = 0;
}

/**
 * mei_amthif_host_init - mei initialization amthif client.
 *
 * @dev: the device structure
 * @me_cl: me client
 *
 * Return: 0 on success, <0 on failure.
 */
int mei_amthif_host_init(struct mei_device *dev, struct mei_me_client *me_cl)
{
	struct mei_cl *cl = &dev->iamthif_cl;
	int ret;

	mutex_lock(&dev->device_lock);

	if (mei_cl_is_connected(cl)) {
		ret = 0;
		goto out;
	}

	dev->iamthif_state = MEI_IAMTHIF_IDLE;

	mei_cl_init(cl, dev);

	ret = mei_cl_link(cl);
	if (ret < 0) {
		dev_err(dev->dev, "amthif: failed cl_link %d\n", ret);
		goto out;
	}

	ret = mei_cl_connect(cl, me_cl, NULL);

out:
	mutex_unlock(&dev->device_lock);
	return ret;
}

/**
 * mei_amthif_read_start - queue message for sending read credential
 *
 * @cl: host client
 * @fp: file pointer of message recipient
 *
 * Return: 0 on success, <0 on failure.
 */
static int mei_amthif_read_start(struct mei_cl *cl, const struct file *fp)
{
	struct mei_device *dev = cl->dev;
	struct mei_cl_cb *cb;

	cb = mei_cl_enqueue_ctrl_wr_cb(cl, mei_cl_mtu(cl), MEI_FOP_READ, fp);
	if (!cb)
		return -ENOMEM;

	cl->rx_flow_ctrl_creds++;

	dev->iamthif_state = MEI_IAMTHIF_READING;
	cl->fp = cb->fp;

	return 0;
}

/**
 * mei_amthif_run_next_cmd - send next amt command from queue
 *
 * @dev: the device structure
 *
 * Return: 0 on success, <0 on failure.
 */
int mei_amthif_run_next_cmd(struct mei_device *dev)
{
	struct mei_cl *cl = &dev->iamthif_cl;
	struct mei_cl_cb *cb;
	int ret;

	dev->iamthif_canceled = false;

	dev_dbg(dev->dev, "complete amthif cmd_list cb.\n");

	cb = list_first_entry_or_null(&dev->amthif_cmd_list, typeof(*cb), list);
	if (!cb) {
		dev->iamthif_state = MEI_IAMTHIF_IDLE;
		cl->fp = NULL;
		return 0;
	}

	list_del_init(&cb->list);
	dev->iamthif_state = MEI_IAMTHIF_WRITING;
	cl->fp = cb->fp;

	ret = mei_cl_write(cl, cb);
	if (ret < 0)
		return ret;

	if (cb->completed)
		cb->status = mei_amthif_read_start(cl, cb->fp);

	return 0;
}

/**
 * mei_amthif_write - write amthif data to amthif client
 *
 * @cl: host client
 * @cb: mei call back struct
 *
 * Return: 0 on success, <0 on failure.
 */
int mei_amthif_write(struct mei_cl *cl, struct mei_cl_cb *cb)
{

	struct mei_device *dev = cl->dev;

	list_add_tail(&cb->list, &dev->amthif_cmd_list);

	/*
	 * The previous request is still in processing, queue this one.
	 */
	if (dev->iamthif_state != MEI_IAMTHIF_IDLE)
		return 0;

	return mei_amthif_run_next_cmd(dev);
}

/**
 * mei_amthif_poll - the amthif poll function
 *
 * @file: pointer to file structure
 * @wait: pointer to poll_table structure
 *
 * Return: poll mask
 *
 * Locking: called under "dev->device_lock" lock
 */
unsigned int mei_amthif_poll(struct file *file, poll_table *wait)
{
	struct mei_cl *cl = file->private_data;
	struct mei_cl_cb *cb = mei_cl_read_cb(cl, file);
	unsigned int mask = 0;

	poll_wait(file, &cl->rx_wait, wait);
	if (cb)
		mask |= POLLIN | POLLRDNORM;

	return mask;
}

/**
 * mei_amthif_irq_write - write iamthif command in irq thread context.
 *
 * @cl: private data of the file object.
 * @cb: callback block.
 * @cmpl_list: complete list.
 *
 * Return: 0, OK; otherwise, error.
 */
int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
			 struct list_head *cmpl_list)
{
	int ret;

	ret = mei_cl_irq_write(cl, cb, cmpl_list);
	if (ret)
		return ret;

	if (cb->completed)
		cb->status = mei_amthif_read_start(cl, cb->fp);

	return 0;
}

/**
 * mei_amthif_irq_read_msg - read routine after ISR to
 *			handle the read amthif message
 *
 * @cl: mei client
 * @mei_hdr: header of amthif message
 * @cmpl_list: completed callbacks list
 *
 * Return: -ENODEV if cb is NULL 0 otherwise; error message is in cb->status
 */
int mei_amthif_irq_read_msg(struct mei_cl *cl,
			    struct mei_msg_hdr *mei_hdr,
			    struct list_head *cmpl_list)
{
	struct mei_device *dev;
	int ret;

	dev = cl->dev;

	if (dev->iamthif_state != MEI_IAMTHIF_READING) {
		mei_irq_discard_msg(dev, mei_hdr);
		return 0;
	}

	ret = mei_cl_irq_read_msg(cl, mei_hdr, cmpl_list);
	if (ret)
		return ret;

	if (!mei_hdr->msg_complete)
		return 0;

	dev_dbg(dev->dev, "completed amthif read.\n ");
	dev->iamthif_stall_timer = 0;

	return 0;
}

/**
 * mei_amthif_complete - complete amthif callback.
 *
 * @cl: host client
 * @cb: callback block.
 */
void mei_amthif_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
{
	struct mei_device *dev = cl->dev;

	dev_dbg(dev->dev, "completing amthif call back.\n");
	switch (cb->fop_type) {
	case MEI_FOP_WRITE:
		if (!cb->status) {
			dev->iamthif_stall_timer = MEI_IAMTHIF_STALL_TIMER;
			mei_schedule_stall_timer(dev);
			mei_io_cb_free(cb);
			return;
		}
		dev->iamthif_state = MEI_IAMTHIF_IDLE;
		cl->fp = NULL;
		if (!dev->iamthif_canceled) {
			/*
			 * in case of error enqueue the write cb to complete
			 * read list so it can be propagated to the reader
			 */
			list_add_tail(&cb->list, &cl->rd_completed);
			wake_up_interruptible(&cl->rx_wait);
		} else {
			mei_io_cb_free(cb);
		}
		break;
	case MEI_FOP_READ:
		if (!dev->iamthif_canceled) {
			list_add_tail(&cb->list, &cl->rd_completed);
			dev_dbg(dev->dev, "amthif read completed\n");
			wake_up_interruptible(&cl->rx_wait);
		} else {
			mei_io_cb_free(cb);
		}

		dev->iamthif_stall_timer = 0;
		mei_amthif_run_next_cmd(dev);
		break;
	default:
		WARN_ON(1);
	}
}

/**
* mei_amthif_release - the release function
*
*  @dev: device structure
*  @fp: pointer to file structure
*
*  Return: 0 on success, <0 on error
*/
int mei_amthif_release(struct mei_device *dev, struct file *fp)
{
	struct mei_cl *cl = fp->private_data;

	if (dev->iamthif_open_count > 0)
		dev->iamthif_open_count--;

	if (cl->fp == fp && dev->iamthif_state != MEI_IAMTHIF_IDLE) {

		dev_dbg(dev->dev, "amthif canceled iamthif state %d\n",
			dev->iamthif_state);
		dev->iamthif_canceled = true;
	}

	/* Don't clean ctrl_rd_list here, the reads has to be completed */
	mei_io_list_free_fp(&dev->amthif_cmd_list, fp);
	mei_io_list_free_fp(&cl->rd_completed, fp);

	return 0;
}
+0 −6
Original line number Diff line number Diff line
@@ -1076,12 +1076,6 @@ void mei_cl_bus_rescan_work(struct work_struct *work)
{
	struct mei_device *bus =
		container_of(work, struct mei_device, bus_rescan_work);
	struct mei_me_client *me_cl;

	me_cl = mei_me_cl_by_uuid(bus, &mei_amthif_guid);
	if (me_cl)
		mei_amthif_host_init(bus, me_cl);
	mei_me_cl_put(me_cl);

	mei_cl_bus_rescan(bus);
}
+5 −9
Original line number Diff line number Diff line
@@ -428,7 +428,7 @@ static inline void mei_io_list_free_cl(struct list_head *head,
 * @head: io list
 * @fp: file pointer (matching cb file object), may be NULL
 */
void mei_io_list_free_fp(struct list_head *head, const struct file *fp)
static void mei_io_list_free_fp(struct list_head *head, const struct file *fp)
{
	struct mei_cl_cb *cb, *next;

@@ -554,7 +554,7 @@ int mei_cl_flush_queues(struct mei_cl *cl, const struct file *fp)
 * @cl: host client to be initialized
 * @dev: mei device
 */
void mei_cl_init(struct mei_cl *cl, struct mei_device *dev)
static void mei_cl_init(struct mei_cl *cl, struct mei_device *dev)
{
	memset(cl, 0, sizeof(struct mei_cl));
	init_waitqueue_head(&cl->wait);
@@ -600,7 +600,6 @@ struct mei_cl *mei_cl_allocate(struct mei_device *dev)
int mei_cl_link(struct mei_cl *cl)
{
	struct mei_device *dev;
	long open_handle_count;
	int id;

	if (WARN_ON(!cl || !cl->dev))
@@ -614,8 +613,7 @@ int mei_cl_link(struct mei_cl *cl)
		return -EMFILE;
	}

	open_handle_count = dev->open_handle_count + dev->iamthif_open_count;
	if (open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) {
	if (dev->open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) {
		dev_err(dev->dev, "open_handle_count exceeded %d",
			MEI_MAX_OPEN_HANDLE_COUNT);
		return -EMFILE;
@@ -649,8 +647,7 @@ int mei_cl_unlink(struct mei_cl *cl)
	if (!cl)
		return 0;

	/* amthif might not be initialized */
	if (!cl->dev)
	if (WARN_ON(!cl->dev))
		return 0;

	dev = cl->dev;
@@ -763,7 +760,6 @@ static void mei_cl_set_disconnected(struct mei_cl *cl)
	mei_io_list_free_cl(&dev->write_waiting_list, cl);
	mei_io_list_flush_cl(&dev->ctrl_rd_list, cl);
	mei_io_list_flush_cl(&dev->ctrl_wr_list, cl);
	mei_io_list_free_cl(&dev->amthif_cmd_list, cl);
	mei_cl_wake_all(cl);
	cl->rx_flow_ctrl_creds = 0;
	cl->tx_flow_ctrl_creds = 0;
@@ -1478,7 +1474,7 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length, const struct file *fp)
		return  -ENOTTY;
	}

	if (mei_cl_is_fixed_address(cl) || cl == &dev->iamthif_cl)
	if (mei_cl_is_fixed_address(cl))
		return 0;

	/* HW currently supports only one pending read */
+0 −5
Original line number Diff line number Diff line
@@ -83,15 +83,12 @@ static inline u8 mei_me_cl_ver(const struct mei_me_client *me_cl)
 * MEI IO Functions
 */
void mei_io_cb_free(struct mei_cl_cb *priv_cb);
void mei_io_list_free_fp(struct list_head *head, const struct file *fp);

/*
 * MEI Host Client Functions
 */

struct mei_cl *mei_cl_allocate(struct mei_device *dev);
void mei_cl_init(struct mei_cl *cl, struct mei_device *dev);


int mei_cl_link(struct mei_cl *cl);
int mei_cl_unlink(struct mei_cl *cl);
@@ -205,8 +202,6 @@ int mei_cl_connect(struct mei_cl *cl, struct mei_me_client *me_cl,
int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb,
		       struct list_head *cmpl_list);
int mei_cl_read_start(struct mei_cl *cl, size_t length, const struct file *fp);
int mei_cl_irq_read_msg(struct mei_cl *cl, struct mei_msg_hdr *hdr,
			struct list_head *cmpl_list);
int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb);
int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
		     struct list_head *cmpl_list);
Loading