staging/mei: PCI device and char driver support.
contains module entries and PCI driver and char device
definitions (using file_operations, pci_driver struts).
The HW interface is exposed on PCI interface.
PCI:
The MEI HW resources are memory map 32 bit registers
(Host and ME Status Registers and Data Registers)
and interrupt (shared, with Intel GFX on some chipsets
and USB2 controller on others).
The device is part of the chipsets and cannot be hotplugged.
The MEI device present is determined by BIOS configuration.
Probe:
The driver starts the init MEI flow, that is explained
in the patch "MEI driver init flow" [06/10],
then schedules a timer that handles
timeouts and watchdog heartbeats.
Remove:
The driver closes all connections and stops the watchdog.
The driver expose char device that supports:
open, release, write, read, ioctl, poll.
Open:
Upon open the driver allocates HOST data structure
on behalf of application which will resides in the file's
private data and assign a host ID number which
will identify messages between driver client instance
and MEI client.
The driver also checks readiness of the device. The number
of simultaneously opened instances is limited to 253.
(255 - (amthi + watchdog))
Release:
In release the driver sends a Disconnect Command to
ME feature and clean all the data structs.
IOCTL:
MEI adds new IOCTL: (IOCTL_MEI_CONNECT_CLIENT)
The IOCTL links the current file descriptor to ME feature.
This is done by sending MEI Bus command: 'hbm_client_connect_request'
to the ME and waiting for an answer :'hbm_client_connect_response'.
Upon answer reception the driver updates its and HOST data
structures in file structure to indicate that the file
descriptor is associated to ME feature.
Each ME feature is represented by UUID which is given as
an input parameter to the IOCTL, upon success connect command the
IOCTL will return the ME feature properties.
ME can reject CONNECT commands due to several reasons,
most common are:
Invalid UUID ME or feature does not exists in ME.
No More Connection allowed to this is feature,
usually only one connection is allowed.
Write:
Upon write, the driver splits the user data into several MEI
messages up to 512 bytes each and sends it to the HW.
If the user wants to write data to AMTHI ME feature then the
drivers routes the messages through AMTHI queues.
Read:
In read the driver checks is a connection exists to
current file descriptor and then wait until a data is available.
Message might be received (by interrupt from ME) in multiple chunks.
Only complete message is released to the application.
Poll:
Nothing special here. Waiting for see if we have
data available for reading.
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Itzhak Tzeel-Krupp <itzhak.tzeel-krupp@intel.com>
Signed-off-by: Oren Weil <oren.jer.weil@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2011-05-15 18:43:41 +08:00
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Intel Management Engine Interface (Intel MEI) Linux driver
|
2012-02-10 01:25:53 +08:00
|
|
|
* Copyright (c) 2003-2012, Intel Corporation.
|
staging/mei: PCI device and char driver support.
contains module entries and PCI driver and char device
definitions (using file_operations, pci_driver struts).
The HW interface is exposed on PCI interface.
PCI:
The MEI HW resources are memory map 32 bit registers
(Host and ME Status Registers and Data Registers)
and interrupt (shared, with Intel GFX on some chipsets
and USB2 controller on others).
The device is part of the chipsets and cannot be hotplugged.
The MEI device present is determined by BIOS configuration.
Probe:
The driver starts the init MEI flow, that is explained
in the patch "MEI driver init flow" [06/10],
then schedules a timer that handles
timeouts and watchdog heartbeats.
Remove:
The driver closes all connections and stops the watchdog.
The driver expose char device that supports:
open, release, write, read, ioctl, poll.
Open:
Upon open the driver allocates HOST data structure
on behalf of application which will resides in the file's
private data and assign a host ID number which
will identify messages between driver client instance
and MEI client.
The driver also checks readiness of the device. The number
of simultaneously opened instances is limited to 253.
(255 - (amthi + watchdog))
Release:
In release the driver sends a Disconnect Command to
ME feature and clean all the data structs.
IOCTL:
MEI adds new IOCTL: (IOCTL_MEI_CONNECT_CLIENT)
The IOCTL links the current file descriptor to ME feature.
This is done by sending MEI Bus command: 'hbm_client_connect_request'
to the ME and waiting for an answer :'hbm_client_connect_response'.
Upon answer reception the driver updates its and HOST data
structures in file structure to indicate that the file
descriptor is associated to ME feature.
Each ME feature is represented by UUID which is given as
an input parameter to the IOCTL, upon success connect command the
IOCTL will return the ME feature properties.
ME can reject CONNECT commands due to several reasons,
most common are:
Invalid UUID ME or feature does not exists in ME.
No More Connection allowed to this is feature,
usually only one connection is allowed.
Write:
Upon write, the driver splits the user data into several MEI
messages up to 512 bytes each and sends it to the HW.
If the user wants to write data to AMTHI ME feature then the
drivers routes the messages through AMTHI queues.
Read:
In read the driver checks is a connection exists to
current file descriptor and then wait until a data is available.
Message might be received (by interrupt from ME) in multiple chunks.
Only complete message is released to the application.
Poll:
Nothing special here. Waiting for see if we have
data available for reading.
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Itzhak Tzeel-Krupp <itzhak.tzeel-krupp@intel.com>
Signed-off-by: Oren Weil <oren.jer.weil@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2011-05-15 18:43:41 +08:00
|
|
|
*
|
|
|
|
* 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/pci.h>
|
|
|
|
#include <linux/sched.h>
|
2013-01-09 05:07:13 +08:00
|
|
|
#include <linux/wait.h>
|
|
|
|
#include <linux/delay.h>
|
2014-03-19 04:52:04 +08:00
|
|
|
#include <linux/pm_runtime.h>
|
staging/mei: PCI device and char driver support.
contains module entries and PCI driver and char device
definitions (using file_operations, pci_driver struts).
The HW interface is exposed on PCI interface.
PCI:
The MEI HW resources are memory map 32 bit registers
(Host and ME Status Registers and Data Registers)
and interrupt (shared, with Intel GFX on some chipsets
and USB2 controller on others).
The device is part of the chipsets and cannot be hotplugged.
The MEI device present is determined by BIOS configuration.
Probe:
The driver starts the init MEI flow, that is explained
in the patch "MEI driver init flow" [06/10],
then schedules a timer that handles
timeouts and watchdog heartbeats.
Remove:
The driver closes all connections and stops the watchdog.
The driver expose char device that supports:
open, release, write, read, ioctl, poll.
Open:
Upon open the driver allocates HOST data structure
on behalf of application which will resides in the file's
private data and assign a host ID number which
will identify messages between driver client instance
and MEI client.
The driver also checks readiness of the device. The number
of simultaneously opened instances is limited to 253.
(255 - (amthi + watchdog))
Release:
In release the driver sends a Disconnect Command to
ME feature and clean all the data structs.
IOCTL:
MEI adds new IOCTL: (IOCTL_MEI_CONNECT_CLIENT)
The IOCTL links the current file descriptor to ME feature.
This is done by sending MEI Bus command: 'hbm_client_connect_request'
to the ME and waiting for an answer :'hbm_client_connect_response'.
Upon answer reception the driver updates its and HOST data
structures in file structure to indicate that the file
descriptor is associated to ME feature.
Each ME feature is represented by UUID which is given as
an input parameter to the IOCTL, upon success connect command the
IOCTL will return the ME feature properties.
ME can reject CONNECT commands due to several reasons,
most common are:
Invalid UUID ME or feature does not exists in ME.
No More Connection allowed to this is feature,
usually only one connection is allowed.
Write:
Upon write, the driver splits the user data into several MEI
messages up to 512 bytes each and sends it to the HW.
If the user wants to write data to AMTHI ME feature then the
drivers routes the messages through AMTHI queues.
Read:
In read the driver checks is a connection exists to
current file descriptor and then wait until a data is available.
Message might be received (by interrupt from ME) in multiple chunks.
Only complete message is released to the application.
Poll:
Nothing special here. Waiting for see if we have
data available for reading.
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Itzhak Tzeel-Krupp <itzhak.tzeel-krupp@intel.com>
Signed-off-by: Oren Weil <oren.jer.weil@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2011-05-15 18:43:41 +08:00
|
|
|
|
2012-05-09 21:38:59 +08:00
|
|
|
#include <linux/mei.h>
|
2012-12-26 01:06:03 +08:00
|
|
|
|
|
|
|
#include "mei_dev.h"
|
2013-01-09 05:07:12 +08:00
|
|
|
#include "hbm.h"
|
2013-01-09 05:07:14 +08:00
|
|
|
#include "client.h"
|
|
|
|
|
|
|
|
/**
|
|
|
|
* mei_me_cl_by_uuid - locate index of me client
|
|
|
|
*
|
|
|
|
* @dev: mei device
|
2014-02-17 21:13:22 +08:00
|
|
|
*
|
|
|
|
* Locking: called under "dev->device_lock" lock
|
|
|
|
*
|
2013-01-09 05:07:14 +08:00
|
|
|
* returns me client index or -ENOENT if not found
|
|
|
|
*/
|
|
|
|
int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *uuid)
|
|
|
|
{
|
2014-02-17 21:13:22 +08:00
|
|
|
int i;
|
2013-01-09 05:07:14 +08:00
|
|
|
|
|
|
|
for (i = 0; i < dev->me_clients_num; ++i)
|
|
|
|
if (uuid_le_cmp(*uuid,
|
2014-02-17 21:13:22 +08:00
|
|
|
dev->me_clients[i].props.protocol_name) == 0)
|
|
|
|
return i;
|
2013-01-09 05:07:14 +08:00
|
|
|
|
2014-02-17 21:13:22 +08:00
|
|
|
return -ENOENT;
|
2013-01-09 05:07:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* mei_me_cl_by_id return index to me_clients for client_id
|
|
|
|
*
|
|
|
|
* @dev: the device structure
|
|
|
|
* @client_id: me client id
|
|
|
|
*
|
|
|
|
* Locking: called under "dev->device_lock" lock
|
|
|
|
*
|
|
|
|
* returns index on success, -ENOENT on failure.
|
|
|
|
*/
|
|
|
|
|
|
|
|
int mei_me_cl_by_id(struct mei_device *dev, u8 client_id)
|
|
|
|
{
|
|
|
|
int i;
|
2014-02-17 21:13:22 +08:00
|
|
|
|
2013-01-09 05:07:14 +08:00
|
|
|
for (i = 0; i < dev->me_clients_num; i++)
|
|
|
|
if (dev->me_clients[i].client_id == client_id)
|
2014-02-17 21:13:22 +08:00
|
|
|
return i;
|
2013-01-09 05:07:14 +08:00
|
|
|
|
2014-02-17 21:13:22 +08:00
|
|
|
return -ENOENT;
|
2013-01-09 05:07:14 +08:00
|
|
|
}
|
staging/mei: PCI device and char driver support.
contains module entries and PCI driver and char device
definitions (using file_operations, pci_driver struts).
The HW interface is exposed on PCI interface.
PCI:
The MEI HW resources are memory map 32 bit registers
(Host and ME Status Registers and Data Registers)
and interrupt (shared, with Intel GFX on some chipsets
and USB2 controller on others).
The device is part of the chipsets and cannot be hotplugged.
The MEI device present is determined by BIOS configuration.
Probe:
The driver starts the init MEI flow, that is explained
in the patch "MEI driver init flow" [06/10],
then schedules a timer that handles
timeouts and watchdog heartbeats.
Remove:
The driver closes all connections and stops the watchdog.
The driver expose char device that supports:
open, release, write, read, ioctl, poll.
Open:
Upon open the driver allocates HOST data structure
on behalf of application which will resides in the file's
private data and assign a host ID number which
will identify messages between driver client instance
and MEI client.
The driver also checks readiness of the device. The number
of simultaneously opened instances is limited to 253.
(255 - (amthi + watchdog))
Release:
In release the driver sends a Disconnect Command to
ME feature and clean all the data structs.
IOCTL:
MEI adds new IOCTL: (IOCTL_MEI_CONNECT_CLIENT)
The IOCTL links the current file descriptor to ME feature.
This is done by sending MEI Bus command: 'hbm_client_connect_request'
to the ME and waiting for an answer :'hbm_client_connect_response'.
Upon answer reception the driver updates its and HOST data
structures in file structure to indicate that the file
descriptor is associated to ME feature.
Each ME feature is represented by UUID which is given as
an input parameter to the IOCTL, upon success connect command the
IOCTL will return the ME feature properties.
ME can reject CONNECT commands due to several reasons,
most common are:
Invalid UUID ME or feature does not exists in ME.
No More Connection allowed to this is feature,
usually only one connection is allowed.
Write:
Upon write, the driver splits the user data into several MEI
messages up to 512 bytes each and sends it to the HW.
If the user wants to write data to AMTHI ME feature then the
drivers routes the messages through AMTHI queues.
Read:
In read the driver checks is a connection exists to
current file descriptor and then wait until a data is available.
Message might be received (by interrupt from ME) in multiple chunks.
Only complete message is released to the application.
Poll:
Nothing special here. Waiting for see if we have
data available for reading.
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Itzhak Tzeel-Krupp <itzhak.tzeel-krupp@intel.com>
Signed-off-by: Oren Weil <oren.jer.weil@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2011-05-15 18:43:41 +08:00
|
|
|
|
2013-01-09 05:07:13 +08:00
|
|
|
|
|
|
|
/**
|
2014-03-10 21:10:40 +08:00
|
|
|
* mei_cl_cmp_id - tells if the clients are the same
|
2013-01-09 05:07:13 +08:00
|
|
|
*
|
2014-03-10 21:10:40 +08:00
|
|
|
* @cl1: host client 1
|
|
|
|
* @cl2: host client 2
|
|
|
|
*
|
|
|
|
* returns true - if the clients has same host and me ids
|
|
|
|
* false - otherwise
|
|
|
|
*/
|
|
|
|
static inline bool mei_cl_cmp_id(const struct mei_cl *cl1,
|
|
|
|
const struct mei_cl *cl2)
|
|
|
|
{
|
|
|
|
return cl1 && cl2 &&
|
|
|
|
(cl1->host_client_id == cl2->host_client_id) &&
|
|
|
|
(cl1->me_client_id == cl2->me_client_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* mei_io_list_flush - removes cbs belonging to cl.
|
|
|
|
*
|
|
|
|
* @list: an instance of our list structure
|
|
|
|
* @cl: host client, can be NULL for flushing the whole list
|
|
|
|
* @free: whether to free the cbs
|
2013-01-09 05:07:13 +08:00
|
|
|
*/
|
2014-03-10 21:10:40 +08:00
|
|
|
static void __mei_io_list_flush(struct mei_cl_cb *list,
|
|
|
|
struct mei_cl *cl, bool free)
|
2013-01-09 05:07:13 +08:00
|
|
|
{
|
|
|
|
struct mei_cl_cb *cb;
|
|
|
|
struct mei_cl_cb *next;
|
|
|
|
|
2014-03-10 21:10:40 +08:00
|
|
|
/* enable removing everything if no cl is specified */
|
2013-01-09 05:07:13 +08:00
|
|
|
list_for_each_entry_safe(cb, next, &list->list, list) {
|
2014-03-10 21:10:40 +08:00
|
|
|
if (!cl || (cb->cl && mei_cl_cmp_id(cl, cb->cl))) {
|
2013-01-09 05:07:13 +08:00
|
|
|
list_del(&cb->list);
|
2014-03-10 21:10:40 +08:00
|
|
|
if (free)
|
|
|
|
mei_io_cb_free(cb);
|
|
|
|
}
|
2013-01-09 05:07:13 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-10 21:10:40 +08:00
|
|
|
/**
|
|
|
|
* mei_io_list_flush - removes list entry belonging to cl.
|
|
|
|
*
|
|
|
|
* @list: An instance of our list structure
|
|
|
|
* @cl: host client
|
|
|
|
*/
|
|
|
|
static inline void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl)
|
|
|
|
{
|
|
|
|
__mei_io_list_flush(list, cl, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* mei_io_list_free - removes cb belonging to cl and free them
|
|
|
|
*
|
|
|
|
* @list: An instance of our list structure
|
|
|
|
* @cl: host client
|
|
|
|
*/
|
|
|
|
static inline void mei_io_list_free(struct mei_cl_cb *list, struct mei_cl *cl)
|
|
|
|
{
|
|
|
|
__mei_io_list_flush(list, cl, true);
|
|
|
|
}
|
|
|
|
|
2012-10-09 22:50:20 +08:00
|
|
|
/**
|
|
|
|
* mei_io_cb_free - free mei_cb_private related memory
|
|
|
|
*
|
|
|
|
* @cb: mei callback struct
|
|
|
|
*/
|
|
|
|
void mei_io_cb_free(struct mei_cl_cb *cb)
|
|
|
|
{
|
|
|
|
if (cb == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
kfree(cb->request_buffer.data);
|
|
|
|
kfree(cb->response_buffer.data);
|
|
|
|
kfree(cb);
|
|
|
|
}
|
2013-01-09 05:07:13 +08:00
|
|
|
|
2012-10-11 22:35:08 +08:00
|
|
|
/**
|
|
|
|
* mei_io_cb_init - allocate and initialize io callback
|
|
|
|
*
|
|
|
|
* @cl - mei client
|
2013-04-05 00:05:05 +08:00
|
|
|
* @fp: pointer to file structure
|
2012-10-11 22:35:08 +08:00
|
|
|
*
|
|
|
|
* returns mei_cl_cb pointer or NULL;
|
|
|
|
*/
|
|
|
|
struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp)
|
|
|
|
{
|
|
|
|
struct mei_cl_cb *cb;
|
|
|
|
|
|
|
|
cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL);
|
|
|
|
if (!cb)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
mei_io_list_init(cb);
|
|
|
|
|
|
|
|
cb->file_object = fp;
|
2012-11-11 23:37:59 +08:00
|
|
|
cb->cl = cl;
|
2012-10-11 22:35:08 +08:00
|
|
|
cb->buf_idx = 0;
|
|
|
|
return cb;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* mei_io_cb_alloc_req_buf - allocate request buffer
|
|
|
|
*
|
2013-04-05 00:05:05 +08:00
|
|
|
* @cb: io callback structure
|
|
|
|
* @length: size of the buffer
|
2012-10-11 22:35:08 +08:00
|
|
|
*
|
|
|
|
* returns 0 on success
|
|
|
|
* -EINVAL if cb is NULL
|
|
|
|
* -ENOMEM if allocation failed
|
|
|
|
*/
|
|
|
|
int mei_io_cb_alloc_req_buf(struct mei_cl_cb *cb, size_t length)
|
|
|
|
{
|
|
|
|
if (!cb)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (length == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
cb->request_buffer.data = kmalloc(length, GFP_KERNEL);
|
|
|
|
if (!cb->request_buffer.data)
|
|
|
|
return -ENOMEM;
|
|
|
|
cb->request_buffer.size = length;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/**
|
2014-01-09 04:31:46 +08:00
|
|
|
* mei_io_cb_alloc_resp_buf - allocate response buffer
|
2012-10-11 22:35:08 +08:00
|
|
|
*
|
2013-04-05 00:05:05 +08:00
|
|
|
* @cb: io callback structure
|
|
|
|
* @length: size of the buffer
|
2012-10-11 22:35:08 +08:00
|
|
|
*
|
|
|
|
* returns 0 on success
|
|
|
|
* -EINVAL if cb is NULL
|
|
|
|
* -ENOMEM if allocation failed
|
|
|
|
*/
|
|
|
|
int mei_io_cb_alloc_resp_buf(struct mei_cl_cb *cb, size_t length)
|
|
|
|
{
|
|
|
|
if (!cb)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (length == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
cb->response_buffer.data = kmalloc(length, GFP_KERNEL);
|
|
|
|
if (!cb->response_buffer.data)
|
|
|
|
return -ENOMEM;
|
|
|
|
cb->response_buffer.size = length;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-10-09 22:50:20 +08:00
|
|
|
|
2013-01-09 05:07:13 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* mei_cl_flush_queues - flushes queue lists belonging to cl.
|
|
|
|
*
|
|
|
|
* @cl: host client
|
|
|
|
*/
|
|
|
|
int mei_cl_flush_queues(struct mei_cl *cl)
|
|
|
|
{
|
2013-09-15 23:11:07 +08:00
|
|
|
struct mei_device *dev;
|
|
|
|
|
2013-01-09 05:07:14 +08:00
|
|
|
if (WARN_ON(!cl || !cl->dev))
|
2013-01-09 05:07:13 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2013-09-15 23:11:07 +08:00
|
|
|
dev = cl->dev;
|
|
|
|
|
|
|
|
cl_dbg(dev, cl, "remove list entry belonging to cl\n");
|
2013-01-09 05:07:13 +08:00
|
|
|
mei_io_list_flush(&cl->dev->read_list, cl);
|
2014-03-10 21:10:40 +08:00
|
|
|
mei_io_list_free(&cl->dev->write_list, cl);
|
|
|
|
mei_io_list_free(&cl->dev->write_waiting_list, cl);
|
2013-01-09 05:07:13 +08:00
|
|
|
mei_io_list_flush(&cl->dev->ctrl_wr_list, cl);
|
|
|
|
mei_io_list_flush(&cl->dev->ctrl_rd_list, cl);
|
|
|
|
mei_io_list_flush(&cl->dev->amthif_cmd_list, cl);
|
|
|
|
mei_io_list_flush(&cl->dev->amthif_rd_complete_list, cl);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
staging/mei: PCI device and char driver support.
contains module entries and PCI driver and char device
definitions (using file_operations, pci_driver struts).
The HW interface is exposed on PCI interface.
PCI:
The MEI HW resources are memory map 32 bit registers
(Host and ME Status Registers and Data Registers)
and interrupt (shared, with Intel GFX on some chipsets
and USB2 controller on others).
The device is part of the chipsets and cannot be hotplugged.
The MEI device present is determined by BIOS configuration.
Probe:
The driver starts the init MEI flow, that is explained
in the patch "MEI driver init flow" [06/10],
then schedules a timer that handles
timeouts and watchdog heartbeats.
Remove:
The driver closes all connections and stops the watchdog.
The driver expose char device that supports:
open, release, write, read, ioctl, poll.
Open:
Upon open the driver allocates HOST data structure
on behalf of application which will resides in the file's
private data and assign a host ID number which
will identify messages between driver client instance
and MEI client.
The driver also checks readiness of the device. The number
of simultaneously opened instances is limited to 253.
(255 - (amthi + watchdog))
Release:
In release the driver sends a Disconnect Command to
ME feature and clean all the data structs.
IOCTL:
MEI adds new IOCTL: (IOCTL_MEI_CONNECT_CLIENT)
The IOCTL links the current file descriptor to ME feature.
This is done by sending MEI Bus command: 'hbm_client_connect_request'
to the ME and waiting for an answer :'hbm_client_connect_response'.
Upon answer reception the driver updates its and HOST data
structures in file structure to indicate that the file
descriptor is associated to ME feature.
Each ME feature is represented by UUID which is given as
an input parameter to the IOCTL, upon success connect command the
IOCTL will return the ME feature properties.
ME can reject CONNECT commands due to several reasons,
most common are:
Invalid UUID ME or feature does not exists in ME.
No More Connection allowed to this is feature,
usually only one connection is allowed.
Write:
Upon write, the driver splits the user data into several MEI
messages up to 512 bytes each and sends it to the HW.
If the user wants to write data to AMTHI ME feature then the
drivers routes the messages through AMTHI queues.
Read:
In read the driver checks is a connection exists to
current file descriptor and then wait until a data is available.
Message might be received (by interrupt from ME) in multiple chunks.
Only complete message is released to the application.
Poll:
Nothing special here. Waiting for see if we have
data available for reading.
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Itzhak Tzeel-Krupp <itzhak.tzeel-krupp@intel.com>
Signed-off-by: Oren Weil <oren.jer.weil@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2011-05-15 18:43:41 +08:00
|
|
|
|
2013-01-09 05:07:13 +08:00
|
|
|
/**
|
2014-01-09 04:31:46 +08:00
|
|
|
* mei_cl_init - initializes cl.
|
2013-01-09 05:07:13 +08:00
|
|
|
*
|
|
|
|
* @cl: host client to be initialized
|
|
|
|
* @dev: mei device
|
|
|
|
*/
|
|
|
|
void mei_cl_init(struct mei_cl *cl, struct mei_device *dev)
|
|
|
|
{
|
|
|
|
memset(cl, 0, sizeof(struct mei_cl));
|
|
|
|
init_waitqueue_head(&cl->wait);
|
|
|
|
init_waitqueue_head(&cl->rx_wait);
|
|
|
|
init_waitqueue_head(&cl->tx_wait);
|
|
|
|
INIT_LIST_HEAD(&cl->link);
|
2013-03-27 23:29:56 +08:00
|
|
|
INIT_LIST_HEAD(&cl->device_link);
|
2013-01-09 05:07:13 +08:00
|
|
|
cl->reading_state = MEI_IDLE;
|
|
|
|
cl->writing_state = MEI_IDLE;
|
|
|
|
cl->dev = dev;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* mei_cl_allocate - allocates cl structure and sets it up.
|
|
|
|
*
|
|
|
|
* @dev: mei device
|
|
|
|
* returns The allocated file or NULL on failure
|
|
|
|
*/
|
|
|
|
struct mei_cl *mei_cl_allocate(struct mei_device *dev)
|
|
|
|
{
|
|
|
|
struct mei_cl *cl;
|
|
|
|
|
|
|
|
cl = kmalloc(sizeof(struct mei_cl), GFP_KERNEL);
|
|
|
|
if (!cl)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
mei_cl_init(cl, dev);
|
|
|
|
|
|
|
|
return cl;
|
|
|
|
}
|
|
|
|
|
2013-01-09 05:07:14 +08:00
|
|
|
/**
|
|
|
|
* mei_cl_find_read_cb - find this cl's callback in the read list
|
|
|
|
*
|
2013-04-05 00:05:05 +08:00
|
|
|
* @cl: host client
|
|
|
|
*
|
2013-01-09 05:07:14 +08:00
|
|
|
* returns cb on success, NULL on error
|
|
|
|
*/
|
|
|
|
struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl)
|
|
|
|
{
|
|
|
|
struct mei_device *dev = cl->dev;
|
2014-02-17 21:13:25 +08:00
|
|
|
struct mei_cl_cb *cb;
|
2013-01-09 05:07:14 +08:00
|
|
|
|
2014-02-17 21:13:25 +08:00
|
|
|
list_for_each_entry(cb, &dev->read_list.list, list)
|
2013-01-09 05:07:14 +08:00
|
|
|
if (mei_cl_cmp_id(cl, cb->cl))
|
|
|
|
return cb;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-01-09 04:31:46 +08:00
|
|
|
/** mei_cl_link: allocate host id in the host map
|
2013-01-09 05:07:13 +08:00
|
|
|
*
|
2013-01-09 05:07:22 +08:00
|
|
|
* @cl - host client
|
2014-01-09 04:31:46 +08:00
|
|
|
* @id - fixed host id or -1 for generic one
|
2013-04-05 00:05:05 +08:00
|
|
|
*
|
2013-01-09 05:07:22 +08:00
|
|
|
* returns 0 on success
|
2013-01-09 05:07:13 +08:00
|
|
|
* -EINVAL on incorrect values
|
|
|
|
* -ENONET if client not found
|
|
|
|
*/
|
2013-01-09 05:07:22 +08:00
|
|
|
int mei_cl_link(struct mei_cl *cl, int id)
|
2013-01-09 05:07:13 +08:00
|
|
|
{
|
2013-01-09 05:07:14 +08:00
|
|
|
struct mei_device *dev;
|
2013-09-17 04:44:47 +08:00
|
|
|
long open_handle_count;
|
2013-01-09 05:07:13 +08:00
|
|
|
|
2013-01-09 05:07:22 +08:00
|
|
|
if (WARN_ON(!cl || !cl->dev))
|
2013-01-09 05:07:13 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2013-01-09 05:07:14 +08:00
|
|
|
dev = cl->dev;
|
|
|
|
|
2014-01-09 04:31:46 +08:00
|
|
|
/* If Id is not assigned get one*/
|
2013-01-09 05:07:22 +08:00
|
|
|
if (id == MEI_HOST_CLIENT_ID_ANY)
|
|
|
|
id = find_first_zero_bit(dev->host_clients_map,
|
|
|
|
MEI_CLIENTS_MAX);
|
2013-01-09 05:07:13 +08:00
|
|
|
|
2013-01-09 05:07:22 +08:00
|
|
|
if (id >= MEI_CLIENTS_MAX) {
|
2014-01-09 04:31:46 +08:00
|
|
|
dev_err(&dev->pdev->dev, "id exceeded %d", MEI_CLIENTS_MAX);
|
2013-09-17 04:44:46 +08:00
|
|
|
return -EMFILE;
|
|
|
|
}
|
|
|
|
|
2013-09-17 04:44:47 +08:00
|
|
|
open_handle_count = dev->open_handle_count + dev->iamthif_open_count;
|
|
|
|
if (open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) {
|
2014-01-09 04:31:46 +08:00
|
|
|
dev_err(&dev->pdev->dev, "open_handle_count exceeded %d",
|
2013-09-17 04:44:46 +08:00
|
|
|
MEI_MAX_OPEN_HANDLE_COUNT);
|
|
|
|
return -EMFILE;
|
2013-01-09 05:07:13 +08:00
|
|
|
}
|
|
|
|
|
2013-01-09 05:07:22 +08:00
|
|
|
dev->open_handle_count++;
|
|
|
|
|
|
|
|
cl->host_client_id = id;
|
|
|
|
list_add_tail(&cl->link, &dev->file_list);
|
|
|
|
|
|
|
|
set_bit(id, dev->host_clients_map);
|
|
|
|
|
|
|
|
cl->state = MEI_FILE_INITIALIZING;
|
|
|
|
|
2013-09-15 23:11:07 +08:00
|
|
|
cl_dbg(dev, cl, "link cl\n");
|
2013-01-09 05:07:22 +08:00
|
|
|
return 0;
|
2013-01-09 05:07:13 +08:00
|
|
|
}
|
2013-01-09 05:07:22 +08:00
|
|
|
|
2013-01-09 05:07:13 +08:00
|
|
|
/**
|
2013-01-09 05:07:14 +08:00
|
|
|
* mei_cl_unlink - remove me_cl from the list
|
2013-01-09 05:07:13 +08:00
|
|
|
*
|
2013-04-05 00:05:05 +08:00
|
|
|
* @cl: host client
|
2013-01-09 05:07:13 +08:00
|
|
|
*/
|
2013-01-09 05:07:14 +08:00
|
|
|
int mei_cl_unlink(struct mei_cl *cl)
|
2013-01-09 05:07:13 +08:00
|
|
|
{
|
2013-01-09 05:07:14 +08:00
|
|
|
struct mei_device *dev;
|
|
|
|
|
2013-01-09 05:07:22 +08:00
|
|
|
/* don't shout on error exit path */
|
|
|
|
if (!cl)
|
|
|
|
return 0;
|
|
|
|
|
2013-01-10 23:32:14 +08:00
|
|
|
/* wd and amthif might not be initialized */
|
|
|
|
if (!cl->dev)
|
|
|
|
return 0;
|
2013-01-09 05:07:14 +08:00
|
|
|
|
|
|
|
dev = cl->dev;
|
|
|
|
|
2013-09-17 04:44:45 +08:00
|
|
|
cl_dbg(dev, cl, "unlink client");
|
|
|
|
|
2013-09-17 04:44:47 +08:00
|
|
|
if (dev->open_handle_count > 0)
|
|
|
|
dev->open_handle_count--;
|
|
|
|
|
|
|
|
/* never clear the 0 bit */
|
|
|
|
if (cl->host_client_id)
|
|
|
|
clear_bit(cl->host_client_id, dev->host_clients_map);
|
|
|
|
|
|
|
|
list_del_init(&cl->link);
|
|
|
|
|
|
|
|
cl->state = MEI_FILE_INITIALIZING;
|
|
|
|
|
2013-01-09 05:07:14 +08:00
|
|
|
return 0;
|
2013-01-09 05:07:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void mei_host_client_init(struct work_struct *work)
|
|
|
|
{
|
|
|
|
struct mei_device *dev = container_of(work,
|
|
|
|
struct mei_device, init_work);
|
|
|
|
struct mei_client_properties *client_props;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
mutex_lock(&dev->device_lock);
|
|
|
|
|
|
|
|
for (i = 0; i < dev->me_clients_num; i++) {
|
|
|
|
client_props = &dev->me_clients[i].props;
|
|
|
|
|
2013-01-09 05:07:21 +08:00
|
|
|
if (!uuid_le_cmp(client_props->protocol_name, mei_amthif_guid))
|
2013-01-09 05:07:13 +08:00
|
|
|
mei_amthif_host_init(dev);
|
|
|
|
else if (!uuid_le_cmp(client_props->protocol_name, mei_wd_guid))
|
|
|
|
mei_wd_host_init(dev);
|
2013-04-11 09:03:29 +08:00
|
|
|
else if (!uuid_le_cmp(client_props->protocol_name, mei_nfc_guid))
|
|
|
|
mei_nfc_host_init(dev);
|
|
|
|
|
2013-01-09 05:07:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
dev->dev_state = MEI_DEV_ENABLED;
|
2014-01-12 06:36:10 +08:00
|
|
|
dev->reset_count = 0;
|
2013-01-09 05:07:13 +08:00
|
|
|
|
|
|
|
mutex_unlock(&dev->device_lock);
|
2014-03-19 04:52:04 +08:00
|
|
|
|
|
|
|
pm_runtime_mark_last_busy(&dev->pdev->dev);
|
|
|
|
dev_dbg(&dev->pdev->dev, "rpm: autosuspend\n");
|
|
|
|
pm_runtime_autosuspend(&dev->pdev->dev);
|
2013-01-09 05:07:13 +08:00
|
|
|
}
|
|
|
|
|
2014-02-19 23:35:47 +08:00
|
|
|
/**
|
|
|
|
* mei_hbuf_acquire: try to acquire host buffer
|
|
|
|
*
|
|
|
|
* @dev: the device structure
|
|
|
|
* returns true if host buffer was acquired
|
|
|
|
*/
|
|
|
|
bool mei_hbuf_acquire(struct mei_device *dev)
|
|
|
|
{
|
2014-03-19 04:52:04 +08:00
|
|
|
if (mei_pg_state(dev) == MEI_PG_ON ||
|
|
|
|
dev->pg_event == MEI_PG_EVENT_WAIT) {
|
|
|
|
dev_dbg(&dev->pdev->dev, "device is in pg\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-02-19 23:35:47 +08:00
|
|
|
if (!dev->hbuf_is_ready) {
|
|
|
|
dev_dbg(&dev->pdev->dev, "hbuf is not ready\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
dev->hbuf_is_ready = false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2013-01-09 05:07:13 +08:00
|
|
|
|
|
|
|
/**
|
2014-01-09 04:31:46 +08:00
|
|
|
* mei_cl_disconnect - disconnect host client from the me one
|
2013-01-09 05:07:13 +08:00
|
|
|
*
|
2013-01-09 05:07:14 +08:00
|
|
|
* @cl: host client
|
2013-01-09 05:07:13 +08:00
|
|
|
*
|
|
|
|
* Locking: called under "dev->device_lock" lock
|
|
|
|
*
|
|
|
|
* returns 0 on success, <0 on failure.
|
|
|
|
*/
|
2013-01-09 05:07:14 +08:00
|
|
|
int mei_cl_disconnect(struct mei_cl *cl)
|
2013-01-09 05:07:13 +08:00
|
|
|
{
|
2013-01-09 05:07:14 +08:00
|
|
|
struct mei_device *dev;
|
2013-01-09 05:07:13 +08:00
|
|
|
struct mei_cl_cb *cb;
|
2014-07-17 15:53:38 +08:00
|
|
|
int rets;
|
2013-01-09 05:07:13 +08:00
|
|
|
|
2013-01-09 05:07:14 +08:00
|
|
|
if (WARN_ON(!cl || !cl->dev))
|
2013-01-09 05:07:13 +08:00
|
|
|
return -ENODEV;
|
|
|
|
|
2013-01-09 05:07:14 +08:00
|
|
|
dev = cl->dev;
|
|
|
|
|
2013-09-15 23:11:07 +08:00
|
|
|
cl_dbg(dev, cl, "disconnecting");
|
|
|
|
|
2013-01-09 05:07:13 +08:00
|
|
|
if (cl->state != MEI_FILE_DISCONNECTING)
|
|
|
|
return 0;
|
|
|
|
|
2014-03-19 04:52:04 +08:00
|
|
|
rets = pm_runtime_get(&dev->pdev->dev);
|
|
|
|
if (rets < 0 && rets != -EINPROGRESS) {
|
|
|
|
pm_runtime_put_noidle(&dev->pdev->dev);
|
|
|
|
cl_err(dev, cl, "rpm: get failed %d\n", rets);
|
|
|
|
return rets;
|
|
|
|
}
|
|
|
|
|
2013-01-09 05:07:13 +08:00
|
|
|
cb = mei_io_cb_init(cl, NULL);
|
2014-03-19 04:52:04 +08:00
|
|
|
if (!cb) {
|
|
|
|
rets = -ENOMEM;
|
|
|
|
goto free;
|
|
|
|
}
|
2013-01-09 05:07:13 +08:00
|
|
|
|
|
|
|
cb->fop_type = MEI_FOP_CLOSE;
|
2014-02-19 23:35:47 +08:00
|
|
|
if (mei_hbuf_acquire(dev)) {
|
2013-01-09 05:07:13 +08:00
|
|
|
if (mei_hbm_cl_disconnect_req(dev, cl)) {
|
|
|
|
rets = -ENODEV;
|
2013-09-15 23:11:07 +08:00
|
|
|
cl_err(dev, cl, "failed to disconnect.\n");
|
2013-01-09 05:07:13 +08:00
|
|
|
goto free;
|
|
|
|
}
|
2014-07-17 15:53:35 +08:00
|
|
|
cl->timer_count = MEI_CONNECT_TIMEOUT;
|
2013-01-09 05:07:13 +08:00
|
|
|
mdelay(10); /* Wait for hardware disconnection ready */
|
|
|
|
list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
|
|
|
|
} else {
|
2013-09-15 23:11:07 +08:00
|
|
|
cl_dbg(dev, cl, "add disconnect cb to control write list\n");
|
2013-01-09 05:07:13 +08:00
|
|
|
list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
|
|
|
|
|
|
|
|
}
|
|
|
|
mutex_unlock(&dev->device_lock);
|
|
|
|
|
2014-07-17 15:53:38 +08:00
|
|
|
wait_event_timeout(dev->wait_recvd_msg,
|
2013-01-09 05:07:13 +08:00
|
|
|
MEI_FILE_DISCONNECTED == cl->state,
|
|
|
|
mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
|
|
|
|
|
|
|
|
mutex_lock(&dev->device_lock);
|
2014-07-17 15:53:38 +08:00
|
|
|
|
2013-01-09 05:07:13 +08:00
|
|
|
if (MEI_FILE_DISCONNECTED == cl->state) {
|
|
|
|
rets = 0;
|
2013-09-15 23:11:07 +08:00
|
|
|
cl_dbg(dev, cl, "successfully disconnected from FW client.\n");
|
2013-01-09 05:07:13 +08:00
|
|
|
} else {
|
2014-07-17 15:53:38 +08:00
|
|
|
cl_dbg(dev, cl, "timeout on disconnect from FW client.\n");
|
|
|
|
rets = -ETIME;
|
2013-01-09 05:07:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
mei_io_list_flush(&dev->ctrl_rd_list, cl);
|
|
|
|
mei_io_list_flush(&dev->ctrl_wr_list, cl);
|
|
|
|
free:
|
2014-03-19 04:52:04 +08:00
|
|
|
cl_dbg(dev, cl, "rpm: autosuspend\n");
|
|
|
|
pm_runtime_mark_last_busy(&dev->pdev->dev);
|
|
|
|
pm_runtime_put_autosuspend(&dev->pdev->dev);
|
|
|
|
|
2013-01-09 05:07:13 +08:00
|
|
|
mei_io_cb_free(cb);
|
|
|
|
return rets;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2013-01-09 05:07:14 +08:00
|
|
|
* mei_cl_is_other_connecting - checks if other
|
|
|
|
* client with the same me client id is connecting
|
2013-01-09 05:07:13 +08:00
|
|
|
*
|
|
|
|
* @cl: private data of the file object
|
|
|
|
*
|
2014-01-09 04:31:46 +08:00
|
|
|
* returns true if other client is connected, false - otherwise.
|
2013-01-09 05:07:13 +08:00
|
|
|
*/
|
2013-01-09 05:07:14 +08:00
|
|
|
bool mei_cl_is_other_connecting(struct mei_cl *cl)
|
2013-01-09 05:07:13 +08:00
|
|
|
{
|
2013-01-09 05:07:14 +08:00
|
|
|
struct mei_device *dev;
|
2014-02-17 21:13:25 +08:00
|
|
|
struct mei_cl *ocl; /* the other client */
|
2013-01-09 05:07:13 +08:00
|
|
|
|
2013-01-09 05:07:14 +08:00
|
|
|
if (WARN_ON(!cl || !cl->dev))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
dev = cl->dev;
|
|
|
|
|
2014-02-17 21:13:25 +08:00
|
|
|
list_for_each_entry(ocl, &dev->file_list, link) {
|
|
|
|
if (ocl->state == MEI_FILE_CONNECTING &&
|
|
|
|
ocl != cl &&
|
|
|
|
cl->me_client_id == ocl->me_client_id)
|
2013-01-09 05:07:14 +08:00
|
|
|
return true;
|
2013-01-09 05:07:13 +08:00
|
|
|
|
|
|
|
}
|
2013-01-09 05:07:14 +08:00
|
|
|
|
|
|
|
return false;
|
2013-01-09 05:07:13 +08:00
|
|
|
}
|
|
|
|
|
2013-01-09 05:07:15 +08:00
|
|
|
/**
|
2014-01-09 04:31:46 +08:00
|
|
|
* mei_cl_connect - connect host client to the me one
|
2013-01-09 05:07:15 +08:00
|
|
|
*
|
|
|
|
* @cl: host client
|
|
|
|
*
|
|
|
|
* Locking: called under "dev->device_lock" lock
|
|
|
|
*
|
|
|
|
* returns 0 on success, <0 on failure.
|
|
|
|
*/
|
|
|
|
int mei_cl_connect(struct mei_cl *cl, struct file *file)
|
|
|
|
{
|
|
|
|
struct mei_device *dev;
|
|
|
|
struct mei_cl_cb *cb;
|
|
|
|
int rets;
|
|
|
|
|
|
|
|
if (WARN_ON(!cl || !cl->dev))
|
|
|
|
return -ENODEV;
|
|
|
|
|
|
|
|
dev = cl->dev;
|
|
|
|
|
2014-03-19 04:52:04 +08:00
|
|
|
rets = pm_runtime_get(&dev->pdev->dev);
|
|
|
|
if (rets < 0 && rets != -EINPROGRESS) {
|
|
|
|
pm_runtime_put_noidle(&dev->pdev->dev);
|
|
|
|
cl_err(dev, cl, "rpm: get failed %d\n", rets);
|
|
|
|
return rets;
|
|
|
|
}
|
|
|
|
|
2013-01-09 05:07:15 +08:00
|
|
|
cb = mei_io_cb_init(cl, file);
|
|
|
|
if (!cb) {
|
|
|
|
rets = -ENOMEM;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2014-02-13 03:41:51 +08:00
|
|
|
cb->fop_type = MEI_FOP_CONNECT;
|
2013-01-09 05:07:15 +08:00
|
|
|
|
2014-02-19 23:35:47 +08:00
|
|
|
/* run hbuf acquire last so we don't have to undo */
|
|
|
|
if (!mei_cl_is_other_connecting(cl) && mei_hbuf_acquire(dev)) {
|
2014-04-27 20:42:21 +08:00
|
|
|
cl->state = MEI_FILE_CONNECTING;
|
2013-01-09 05:07:15 +08:00
|
|
|
if (mei_hbm_cl_connect_req(dev, cl)) {
|
|
|
|
rets = -ENODEV;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
cl->timer_count = MEI_CONNECT_TIMEOUT;
|
|
|
|
list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
|
|
|
|
} else {
|
2014-08-12 23:07:56 +08:00
|
|
|
cl->state = MEI_FILE_INITIALIZING;
|
2013-01-09 05:07:15 +08:00
|
|
|
list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
|
|
|
|
}
|
|
|
|
|
|
|
|
mutex_unlock(&dev->device_lock);
|
2014-02-17 21:13:20 +08:00
|
|
|
wait_event_timeout(dev->wait_recvd_msg,
|
|
|
|
(cl->state == MEI_FILE_CONNECTED ||
|
|
|
|
cl->state == MEI_FILE_DISCONNECTED),
|
|
|
|
mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
|
2013-01-09 05:07:15 +08:00
|
|
|
mutex_lock(&dev->device_lock);
|
|
|
|
|
|
|
|
if (cl->state != MEI_FILE_CONNECTED) {
|
2014-07-17 15:53:34 +08:00
|
|
|
cl->state = MEI_FILE_DISCONNECTED;
|
2014-02-17 21:13:20 +08:00
|
|
|
/* something went really wrong */
|
|
|
|
if (!cl->status)
|
|
|
|
cl->status = -EFAULT;
|
2013-01-09 05:07:15 +08:00
|
|
|
|
|
|
|
mei_io_list_flush(&dev->ctrl_rd_list, cl);
|
|
|
|
mei_io_list_flush(&dev->ctrl_wr_list, cl);
|
|
|
|
}
|
|
|
|
|
|
|
|
rets = cl->status;
|
|
|
|
|
|
|
|
out:
|
2014-03-19 04:52:04 +08:00
|
|
|
cl_dbg(dev, cl, "rpm: autosuspend\n");
|
|
|
|
pm_runtime_mark_last_busy(&dev->pdev->dev);
|
|
|
|
pm_runtime_put_autosuspend(&dev->pdev->dev);
|
|
|
|
|
2013-01-09 05:07:15 +08:00
|
|
|
mei_io_cb_free(cb);
|
|
|
|
return rets;
|
|
|
|
}
|
|
|
|
|
2013-01-09 05:07:13 +08:00
|
|
|
/**
|
2013-01-09 05:07:14 +08:00
|
|
|
* mei_cl_flow_ctrl_creds - checks flow_control credits for cl.
|
2013-01-09 05:07:13 +08:00
|
|
|
*
|
|
|
|
* @cl: private data of the file object
|
|
|
|
*
|
|
|
|
* returns 1 if mei_flow_ctrl_creds >0, 0 - otherwise.
|
|
|
|
* -ENOENT if mei_cl is not present
|
|
|
|
* -EINVAL if single_recv_buf == 0
|
|
|
|
*/
|
2013-01-09 05:07:14 +08:00
|
|
|
int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
|
2013-01-09 05:07:13 +08:00
|
|
|
{
|
2013-01-09 05:07:14 +08:00
|
|
|
struct mei_device *dev;
|
2014-02-17 21:13:23 +08:00
|
|
|
struct mei_me_client *me_cl;
|
|
|
|
int id;
|
2013-01-09 05:07:13 +08:00
|
|
|
|
2013-01-09 05:07:14 +08:00
|
|
|
if (WARN_ON(!cl || !cl->dev))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
dev = cl->dev;
|
|
|
|
|
2013-01-09 05:07:13 +08:00
|
|
|
if (!dev->me_clients_num)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (cl->mei_flow_ctrl_creds > 0)
|
|
|
|
return 1;
|
|
|
|
|
2014-02-17 21:13:23 +08:00
|
|
|
id = mei_me_cl_by_id(dev, cl->me_client_id);
|
|
|
|
if (id < 0) {
|
|
|
|
cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
|
|
|
|
return id;
|
2013-01-09 05:07:13 +08:00
|
|
|
}
|
2014-02-17 21:13:23 +08:00
|
|
|
|
|
|
|
me_cl = &dev->me_clients[id];
|
|
|
|
if (me_cl->mei_flow_ctrl_creds) {
|
|
|
|
if (WARN_ON(me_cl->props.single_recv_buf == 0))
|
|
|
|
return -EINVAL;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
2013-01-09 05:07:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-01-09 05:07:14 +08:00
|
|
|
* mei_cl_flow_ctrl_reduce - reduces flow_control.
|
2013-01-09 05:07:13 +08:00
|
|
|
*
|
|
|
|
* @cl: private data of the file object
|
2013-04-05 00:05:05 +08:00
|
|
|
*
|
2013-01-09 05:07:13 +08:00
|
|
|
* @returns
|
|
|
|
* 0 on success
|
|
|
|
* -ENOENT when me client is not found
|
|
|
|
* -EINVAL when ctrl credits are <= 0
|
|
|
|
*/
|
2013-01-09 05:07:14 +08:00
|
|
|
int mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
|
2013-01-09 05:07:13 +08:00
|
|
|
{
|
2013-01-09 05:07:14 +08:00
|
|
|
struct mei_device *dev;
|
2014-02-17 21:13:23 +08:00
|
|
|
struct mei_me_client *me_cl;
|
|
|
|
int id;
|
2013-01-09 05:07:13 +08:00
|
|
|
|
2013-01-09 05:07:14 +08:00
|
|
|
if (WARN_ON(!cl || !cl->dev))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
dev = cl->dev;
|
|
|
|
|
2014-02-17 21:13:23 +08:00
|
|
|
id = mei_me_cl_by_id(dev, cl->me_client_id);
|
|
|
|
if (id < 0) {
|
|
|
|
cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
|
|
|
|
return id;
|
|
|
|
}
|
2013-01-09 05:07:13 +08:00
|
|
|
|
2014-02-17 21:13:23 +08:00
|
|
|
me_cl = &dev->me_clients[id];
|
|
|
|
if (me_cl->props.single_recv_buf != 0) {
|
|
|
|
if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0))
|
|
|
|
return -EINVAL;
|
|
|
|
me_cl->mei_flow_ctrl_creds--;
|
|
|
|
} else {
|
|
|
|
if (WARN_ON(cl->mei_flow_ctrl_creds <= 0))
|
|
|
|
return -EINVAL;
|
|
|
|
cl->mei_flow_ctrl_creds--;
|
2013-01-09 05:07:13 +08:00
|
|
|
}
|
2014-02-17 21:13:23 +08:00
|
|
|
return 0;
|
2013-01-09 05:07:13 +08:00
|
|
|
}
|
|
|
|
|
staging/mei: PCI device and char driver support.
contains module entries and PCI driver and char device
definitions (using file_operations, pci_driver struts).
The HW interface is exposed on PCI interface.
PCI:
The MEI HW resources are memory map 32 bit registers
(Host and ME Status Registers and Data Registers)
and interrupt (shared, with Intel GFX on some chipsets
and USB2 controller on others).
The device is part of the chipsets and cannot be hotplugged.
The MEI device present is determined by BIOS configuration.
Probe:
The driver starts the init MEI flow, that is explained
in the patch "MEI driver init flow" [06/10],
then schedules a timer that handles
timeouts and watchdog heartbeats.
Remove:
The driver closes all connections and stops the watchdog.
The driver expose char device that supports:
open, release, write, read, ioctl, poll.
Open:
Upon open the driver allocates HOST data structure
on behalf of application which will resides in the file's
private data and assign a host ID number which
will identify messages between driver client instance
and MEI client.
The driver also checks readiness of the device. The number
of simultaneously opened instances is limited to 253.
(255 - (amthi + watchdog))
Release:
In release the driver sends a Disconnect Command to
ME feature and clean all the data structs.
IOCTL:
MEI adds new IOCTL: (IOCTL_MEI_CONNECT_CLIENT)
The IOCTL links the current file descriptor to ME feature.
This is done by sending MEI Bus command: 'hbm_client_connect_request'
to the ME and waiting for an answer :'hbm_client_connect_response'.
Upon answer reception the driver updates its and HOST data
structures in file structure to indicate that the file
descriptor is associated to ME feature.
Each ME feature is represented by UUID which is given as
an input parameter to the IOCTL, upon success connect command the
IOCTL will return the ME feature properties.
ME can reject CONNECT commands due to several reasons,
most common are:
Invalid UUID ME or feature does not exists in ME.
No More Connection allowed to this is feature,
usually only one connection is allowed.
Write:
Upon write, the driver splits the user data into several MEI
messages up to 512 bytes each and sends it to the HW.
If the user wants to write data to AMTHI ME feature then the
drivers routes the messages through AMTHI queues.
Read:
In read the driver checks is a connection exists to
current file descriptor and then wait until a data is available.
Message might be received (by interrupt from ME) in multiple chunks.
Only complete message is released to the application.
Poll:
Nothing special here. Waiting for see if we have
data available for reading.
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Itzhak Tzeel-Krupp <itzhak.tzeel-krupp@intel.com>
Signed-off-by: Oren Weil <oren.jer.weil@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2011-05-15 18:43:41 +08:00
|
|
|
/**
|
2013-04-05 00:05:05 +08:00
|
|
|
* mei_cl_read_start - the start read client message function.
|
staging/mei: PCI device and char driver support.
contains module entries and PCI driver and char device
definitions (using file_operations, pci_driver struts).
The HW interface is exposed on PCI interface.
PCI:
The MEI HW resources are memory map 32 bit registers
(Host and ME Status Registers and Data Registers)
and interrupt (shared, with Intel GFX on some chipsets
and USB2 controller on others).
The device is part of the chipsets and cannot be hotplugged.
The MEI device present is determined by BIOS configuration.
Probe:
The driver starts the init MEI flow, that is explained
in the patch "MEI driver init flow" [06/10],
then schedules a timer that handles
timeouts and watchdog heartbeats.
Remove:
The driver closes all connections and stops the watchdog.
The driver expose char device that supports:
open, release, write, read, ioctl, poll.
Open:
Upon open the driver allocates HOST data structure
on behalf of application which will resides in the file's
private data and assign a host ID number which
will identify messages between driver client instance
and MEI client.
The driver also checks readiness of the device. The number
of simultaneously opened instances is limited to 253.
(255 - (amthi + watchdog))
Release:
In release the driver sends a Disconnect Command to
ME feature and clean all the data structs.
IOCTL:
MEI adds new IOCTL: (IOCTL_MEI_CONNECT_CLIENT)
The IOCTL links the current file descriptor to ME feature.
This is done by sending MEI Bus command: 'hbm_client_connect_request'
to the ME and waiting for an answer :'hbm_client_connect_response'.
Upon answer reception the driver updates its and HOST data
structures in file structure to indicate that the file
descriptor is associated to ME feature.
Each ME feature is represented by UUID which is given as
an input parameter to the IOCTL, upon success connect command the
IOCTL will return the ME feature properties.
ME can reject CONNECT commands due to several reasons,
most common are:
Invalid UUID ME or feature does not exists in ME.
No More Connection allowed to this is feature,
usually only one connection is allowed.
Write:
Upon write, the driver splits the user data into several MEI
messages up to 512 bytes each and sends it to the HW.
If the user wants to write data to AMTHI ME feature then the
drivers routes the messages through AMTHI queues.
Read:
In read the driver checks is a connection exists to
current file descriptor and then wait until a data is available.
Message might be received (by interrupt from ME) in multiple chunks.
Only complete message is released to the application.
Poll:
Nothing special here. Waiting for see if we have
data available for reading.
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Itzhak Tzeel-Krupp <itzhak.tzeel-krupp@intel.com>
Signed-off-by: Oren Weil <oren.jer.weil@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2011-05-15 18:43:41 +08:00
|
|
|
*
|
2013-01-09 05:07:14 +08:00
|
|
|
* @cl: host client
|
staging/mei: PCI device and char driver support.
contains module entries and PCI driver and char device
definitions (using file_operations, pci_driver struts).
The HW interface is exposed on PCI interface.
PCI:
The MEI HW resources are memory map 32 bit registers
(Host and ME Status Registers and Data Registers)
and interrupt (shared, with Intel GFX on some chipsets
and USB2 controller on others).
The device is part of the chipsets and cannot be hotplugged.
The MEI device present is determined by BIOS configuration.
Probe:
The driver starts the init MEI flow, that is explained
in the patch "MEI driver init flow" [06/10],
then schedules a timer that handles
timeouts and watchdog heartbeats.
Remove:
The driver closes all connections and stops the watchdog.
The driver expose char device that supports:
open, release, write, read, ioctl, poll.
Open:
Upon open the driver allocates HOST data structure
on behalf of application which will resides in the file's
private data and assign a host ID number which
will identify messages between driver client instance
and MEI client.
The driver also checks readiness of the device. The number
of simultaneously opened instances is limited to 253.
(255 - (amthi + watchdog))
Release:
In release the driver sends a Disconnect Command to
ME feature and clean all the data structs.
IOCTL:
MEI adds new IOCTL: (IOCTL_MEI_CONNECT_CLIENT)
The IOCTL links the current file descriptor to ME feature.
This is done by sending MEI Bus command: 'hbm_client_connect_request'
to the ME and waiting for an answer :'hbm_client_connect_response'.
Upon answer reception the driver updates its and HOST data
structures in file structure to indicate that the file
descriptor is associated to ME feature.
Each ME feature is represented by UUID which is given as
an input parameter to the IOCTL, upon success connect command the
IOCTL will return the ME feature properties.
ME can reject CONNECT commands due to several reasons,
most common are:
Invalid UUID ME or feature does not exists in ME.
No More Connection allowed to this is feature,
usually only one connection is allowed.
Write:
Upon write, the driver splits the user data into several MEI
messages up to 512 bytes each and sends it to the HW.
If the user wants to write data to AMTHI ME feature then the
drivers routes the messages through AMTHI queues.
Read:
In read the driver checks is a connection exists to
current file descriptor and then wait until a data is available.
Message might be received (by interrupt from ME) in multiple chunks.
Only complete message is released to the application.
Poll:
Nothing special here. Waiting for see if we have
data available for reading.
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Itzhak Tzeel-Krupp <itzhak.tzeel-krupp@intel.com>
Signed-off-by: Oren Weil <oren.jer.weil@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2011-05-15 18:43:41 +08:00
|
|
|
*
|
|
|
|
* returns 0 on success, <0 on failure.
|
|
|
|
*/
|
2013-04-20 03:01:35 +08:00
|
|
|
int mei_cl_read_start(struct mei_cl *cl, size_t length)
|
staging/mei: PCI device and char driver support.
contains module entries and PCI driver and char device
definitions (using file_operations, pci_driver struts).
The HW interface is exposed on PCI interface.
PCI:
The MEI HW resources are memory map 32 bit registers
(Host and ME Status Registers and Data Registers)
and interrupt (shared, with Intel GFX on some chipsets
and USB2 controller on others).
The device is part of the chipsets and cannot be hotplugged.
The MEI device present is determined by BIOS configuration.
Probe:
The driver starts the init MEI flow, that is explained
in the patch "MEI driver init flow" [06/10],
then schedules a timer that handles
timeouts and watchdog heartbeats.
Remove:
The driver closes all connections and stops the watchdog.
The driver expose char device that supports:
open, release, write, read, ioctl, poll.
Open:
Upon open the driver allocates HOST data structure
on behalf of application which will resides in the file's
private data and assign a host ID number which
will identify messages between driver client instance
and MEI client.
The driver also checks readiness of the device. The number
of simultaneously opened instances is limited to 253.
(255 - (amthi + watchdog))
Release:
In release the driver sends a Disconnect Command to
ME feature and clean all the data structs.
IOCTL:
MEI adds new IOCTL: (IOCTL_MEI_CONNECT_CLIENT)
The IOCTL links the current file descriptor to ME feature.
This is done by sending MEI Bus command: 'hbm_client_connect_request'
to the ME and waiting for an answer :'hbm_client_connect_response'.
Upon answer reception the driver updates its and HOST data
structures in file structure to indicate that the file
descriptor is associated to ME feature.
Each ME feature is represented by UUID which is given as
an input parameter to the IOCTL, upon success connect command the
IOCTL will return the ME feature properties.
ME can reject CONNECT commands due to several reasons,
most common are:
Invalid UUID ME or feature does not exists in ME.
No More Connection allowed to this is feature,
usually only one connection is allowed.
Write:
Upon write, the driver splits the user data into several MEI
messages up to 512 bytes each and sends it to the HW.
If the user wants to write data to AMTHI ME feature then the
drivers routes the messages through AMTHI queues.
Read:
In read the driver checks is a connection exists to
current file descriptor and then wait until a data is available.
Message might be received (by interrupt from ME) in multiple chunks.
Only complete message is released to the application.
Poll:
Nothing special here. Waiting for see if we have
data available for reading.
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Itzhak Tzeel-Krupp <itzhak.tzeel-krupp@intel.com>
Signed-off-by: Oren Weil <oren.jer.weil@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2011-05-15 18:43:41 +08:00
|
|
|
{
|
2013-01-09 05:07:14 +08:00
|
|
|
struct mei_device *dev;
|
staging/mei: PCI device and char driver support.
contains module entries and PCI driver and char device
definitions (using file_operations, pci_driver struts).
The HW interface is exposed on PCI interface.
PCI:
The MEI HW resources are memory map 32 bit registers
(Host and ME Status Registers and Data Registers)
and interrupt (shared, with Intel GFX on some chipsets
and USB2 controller on others).
The device is part of the chipsets and cannot be hotplugged.
The MEI device present is determined by BIOS configuration.
Probe:
The driver starts the init MEI flow, that is explained
in the patch "MEI driver init flow" [06/10],
then schedules a timer that handles
timeouts and watchdog heartbeats.
Remove:
The driver closes all connections and stops the watchdog.
The driver expose char device that supports:
open, release, write, read, ioctl, poll.
Open:
Upon open the driver allocates HOST data structure
on behalf of application which will resides in the file's
private data and assign a host ID number which
will identify messages between driver client instance
and MEI client.
The driver also checks readiness of the device. The number
of simultaneously opened instances is limited to 253.
(255 - (amthi + watchdog))
Release:
In release the driver sends a Disconnect Command to
ME feature and clean all the data structs.
IOCTL:
MEI adds new IOCTL: (IOCTL_MEI_CONNECT_CLIENT)
The IOCTL links the current file descriptor to ME feature.
This is done by sending MEI Bus command: 'hbm_client_connect_request'
to the ME and waiting for an answer :'hbm_client_connect_response'.
Upon answer reception the driver updates its and HOST data
structures in file structure to indicate that the file
descriptor is associated to ME feature.
Each ME feature is represented by UUID which is given as
an input parameter to the IOCTL, upon success connect command the
IOCTL will return the ME feature properties.
ME can reject CONNECT commands due to several reasons,
most common are:
Invalid UUID ME or feature does not exists in ME.
No More Connection allowed to this is feature,
usually only one connection is allowed.
Write:
Upon write, the driver splits the user data into several MEI
messages up to 512 bytes each and sends it to the HW.
If the user wants to write data to AMTHI ME feature then the
drivers routes the messages through AMTHI queues.
Read:
In read the driver checks is a connection exists to
current file descriptor and then wait until a data is available.
Message might be received (by interrupt from ME) in multiple chunks.
Only complete message is released to the application.
Poll:
Nothing special here. Waiting for see if we have
data available for reading.
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Itzhak Tzeel-Krupp <itzhak.tzeel-krupp@intel.com>
Signed-off-by: Oren Weil <oren.jer.weil@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2011-05-15 18:43:41 +08:00
|
|
|
struct mei_cl_cb *cb;
|
2012-10-11 22:35:08 +08:00
|
|
|
int rets;
|
staging/mei: PCI device and char driver support.
contains module entries and PCI driver and char device
definitions (using file_operations, pci_driver struts).
The HW interface is exposed on PCI interface.
PCI:
The MEI HW resources are memory map 32 bit registers
(Host and ME Status Registers and Data Registers)
and interrupt (shared, with Intel GFX on some chipsets
and USB2 controller on others).
The device is part of the chipsets and cannot be hotplugged.
The MEI device present is determined by BIOS configuration.
Probe:
The driver starts the init MEI flow, that is explained
in the patch "MEI driver init flow" [06/10],
then schedules a timer that handles
timeouts and watchdog heartbeats.
Remove:
The driver closes all connections and stops the watchdog.
The driver expose char device that supports:
open, release, write, read, ioctl, poll.
Open:
Upon open the driver allocates HOST data structure
on behalf of application which will resides in the file's
private data and assign a host ID number which
will identify messages between driver client instance
and MEI client.
The driver also checks readiness of the device. The number
of simultaneously opened instances is limited to 253.
(255 - (amthi + watchdog))
Release:
In release the driver sends a Disconnect Command to
ME feature and clean all the data structs.
IOCTL:
MEI adds new IOCTL: (IOCTL_MEI_CONNECT_CLIENT)
The IOCTL links the current file descriptor to ME feature.
This is done by sending MEI Bus command: 'hbm_client_connect_request'
to the ME and waiting for an answer :'hbm_client_connect_response'.
Upon answer reception the driver updates its and HOST data
structures in file structure to indicate that the file
descriptor is associated to ME feature.
Each ME feature is represented by UUID which is given as
an input parameter to the IOCTL, upon success connect command the
IOCTL will return the ME feature properties.
ME can reject CONNECT commands due to several reasons,
most common are:
Invalid UUID ME or feature does not exists in ME.
No More Connection allowed to this is feature,
usually only one connection is allowed.
Write:
Upon write, the driver splits the user data into several MEI
messages up to 512 bytes each and sends it to the HW.
If the user wants to write data to AMTHI ME feature then the
drivers routes the messages through AMTHI queues.
Read:
In read the driver checks is a connection exists to
current file descriptor and then wait until a data is available.
Message might be received (by interrupt from ME) in multiple chunks.
Only complete message is released to the application.
Poll:
Nothing special here. Waiting for see if we have
data available for reading.
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Itzhak Tzeel-Krupp <itzhak.tzeel-krupp@intel.com>
Signed-off-by: Oren Weil <oren.jer.weil@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2011-05-15 18:43:41 +08:00
|
|
|
int i;
|
|
|
|
|
2013-01-09 05:07:14 +08:00
|
|
|
if (WARN_ON(!cl || !cl->dev))
|
|
|
|
return -ENODEV;
|
|
|
|
|
|
|
|
dev = cl->dev;
|
|
|
|
|
2013-07-26 01:15:53 +08:00
|
|
|
if (!mei_cl_is_connected(cl))
|
staging/mei: PCI device and char driver support.
contains module entries and PCI driver and char device
definitions (using file_operations, pci_driver struts).
The HW interface is exposed on PCI interface.
PCI:
The MEI HW resources are memory map 32 bit registers
(Host and ME Status Registers and Data Registers)
and interrupt (shared, with Intel GFX on some chipsets
and USB2 controller on others).
The device is part of the chipsets and cannot be hotplugged.
The MEI device present is determined by BIOS configuration.
Probe:
The driver starts the init MEI flow, that is explained
in the patch "MEI driver init flow" [06/10],
then schedules a timer that handles
timeouts and watchdog heartbeats.
Remove:
The driver closes all connections and stops the watchdog.
The driver expose char device that supports:
open, release, write, read, ioctl, poll.
Open:
Upon open the driver allocates HOST data structure
on behalf of application which will resides in the file's
private data and assign a host ID number which
will identify messages between driver client instance
and MEI client.
The driver also checks readiness of the device. The number
of simultaneously opened instances is limited to 253.
(255 - (amthi + watchdog))
Release:
In release the driver sends a Disconnect Command to
ME feature and clean all the data structs.
IOCTL:
MEI adds new IOCTL: (IOCTL_MEI_CONNECT_CLIENT)
The IOCTL links the current file descriptor to ME feature.
This is done by sending MEI Bus command: 'hbm_client_connect_request'
to the ME and waiting for an answer :'hbm_client_connect_response'.
Upon answer reception the driver updates its and HOST data
structures in file structure to indicate that the file
descriptor is associated to ME feature.
Each ME feature is represented by UUID which is given as
an input parameter to the IOCTL, upon success connect command the
IOCTL will return the ME feature properties.
ME can reject CONNECT commands due to several reasons,
most common are:
Invalid UUID ME or feature does not exists in ME.
No More Connection allowed to this is feature,
usually only one connection is allowed.
Write:
Upon write, the driver splits the user data into several MEI
messages up to 512 bytes each and sends it to the HW.
If the user wants to write data to AMTHI ME feature then the
drivers routes the messages through AMTHI queues.
Read:
In read the driver checks is a connection exists to
current file descriptor and then wait until a data is available.
Message might be received (by interrupt from ME) in multiple chunks.
Only complete message is released to the application.
Poll:
Nothing special here. Waiting for see if we have
data available for reading.
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Itzhak Tzeel-Krupp <itzhak.tzeel-krupp@intel.com>
Signed-off-by: Oren Weil <oren.jer.weil@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2011-05-15 18:43:41 +08:00
|
|
|
return -ENODEV;
|
|
|
|
|
2013-01-09 05:07:18 +08:00
|
|
|
if (cl->read_cb) {
|
2013-09-15 23:11:07 +08:00
|
|
|
cl_dbg(dev, cl, "read is pending.\n");
|
staging/mei: PCI device and char driver support.
contains module entries and PCI driver and char device
definitions (using file_operations, pci_driver struts).
The HW interface is exposed on PCI interface.
PCI:
The MEI HW resources are memory map 32 bit registers
(Host and ME Status Registers and Data Registers)
and interrupt (shared, with Intel GFX on some chipsets
and USB2 controller on others).
The device is part of the chipsets and cannot be hotplugged.
The MEI device present is determined by BIOS configuration.
Probe:
The driver starts the init MEI flow, that is explained
in the patch "MEI driver init flow" [06/10],
then schedules a timer that handles
timeouts and watchdog heartbeats.
Remove:
The driver closes all connections and stops the watchdog.
The driver expose char device that supports:
open, release, write, read, ioctl, poll.
Open:
Upon open the driver allocates HOST data structure
on behalf of application which will resides in the file's
private data and assign a host ID number which
will identify messages between driver client instance
and MEI client.
The driver also checks readiness of the device. The number
of simultaneously opened instances is limited to 253.
(255 - (amthi + watchdog))
Release:
In release the driver sends a Disconnect Command to
ME feature and clean all the data structs.
IOCTL:
MEI adds new IOCTL: (IOCTL_MEI_CONNECT_CLIENT)
The IOCTL links the current file descriptor to ME feature.
This is done by sending MEI Bus command: 'hbm_client_connect_request'
to the ME and waiting for an answer :'hbm_client_connect_response'.
Upon answer reception the driver updates its and HOST data
structures in file structure to indicate that the file
descriptor is associated to ME feature.
Each ME feature is represented by UUID which is given as
an input parameter to the IOCTL, upon success connect command the
IOCTL will return the ME feature properties.
ME can reject CONNECT commands due to several reasons,
most common are:
Invalid UUID ME or feature does not exists in ME.
No More Connection allowed to this is feature,
usually only one connection is allowed.
Write:
Upon write, the driver splits the user data into several MEI
messages up to 512 bytes each and sends it to the HW.
If the user wants to write data to AMTHI ME feature then the
drivers routes the messages through AMTHI queues.
Read:
In read the driver checks is a connection exists to
current file descriptor and then wait until a data is available.
Message might be received (by interrupt from ME) in multiple chunks.
Only complete message is released to the application.
Poll:
Nothing special here. Waiting for see if we have
data available for reading.
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Itzhak Tzeel-Krupp <itzhak.tzeel-krupp@intel.com>
Signed-off-by: Oren Weil <oren.jer.weil@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2011-05-15 18:43:41 +08:00
|
|
|
return -EBUSY;
|
|
|
|
}
|
2012-10-11 22:35:08 +08:00
|
|
|
i = mei_me_cl_by_id(dev, cl->me_client_id);
|
|
|
|
if (i < 0) {
|
2013-09-15 23:11:07 +08:00
|
|
|
cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
|
2014-02-19 23:35:49 +08:00
|
|
|
return -ENOTTY;
|
2012-10-11 22:35:08 +08:00
|
|
|
}
|
staging/mei: PCI device and char driver support.
contains module entries and PCI driver and char device
definitions (using file_operations, pci_driver struts).
The HW interface is exposed on PCI interface.
PCI:
The MEI HW resources are memory map 32 bit registers
(Host and ME Status Registers and Data Registers)
and interrupt (shared, with Intel GFX on some chipsets
and USB2 controller on others).
The device is part of the chipsets and cannot be hotplugged.
The MEI device present is determined by BIOS configuration.
Probe:
The driver starts the init MEI flow, that is explained
in the patch "MEI driver init flow" [06/10],
then schedules a timer that handles
timeouts and watchdog heartbeats.
Remove:
The driver closes all connections and stops the watchdog.
The driver expose char device that supports:
open, release, write, read, ioctl, poll.
Open:
Upon open the driver allocates HOST data structure
on behalf of application which will resides in the file's
private data and assign a host ID number which
will identify messages between driver client instance
and MEI client.
The driver also checks readiness of the device. The number
of simultaneously opened instances is limited to 253.
(255 - (amthi + watchdog))
Release:
In release the driver sends a Disconnect Command to
ME feature and clean all the data structs.
IOCTL:
MEI adds new IOCTL: (IOCTL_MEI_CONNECT_CLIENT)
The IOCTL links the current file descriptor to ME feature.
This is done by sending MEI Bus command: 'hbm_client_connect_request'
to the ME and waiting for an answer :'hbm_client_connect_response'.
Upon answer reception the driver updates its and HOST data
structures in file structure to indicate that the file
descriptor is associated to ME feature.
Each ME feature is represented by UUID which is given as
an input parameter to the IOCTL, upon success connect command the
IOCTL will return the ME feature properties.
ME can reject CONNECT commands due to several reasons,
most common are:
Invalid UUID ME or feature does not exists in ME.
No More Connection allowed to this is feature,
usually only one connection is allowed.
Write:
Upon write, the driver splits the user data into several MEI
messages up to 512 bytes each and sends it to the HW.
If the user wants to write data to AMTHI ME feature then the
drivers routes the messages through AMTHI queues.
Read:
In read the driver checks is a connection exists to
current file descriptor and then wait until a data is available.
Message might be received (by interrupt from ME) in multiple chunks.
Only complete message is released to the application.
Poll:
Nothing special here. Waiting for see if we have
data available for reading.
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Itzhak Tzeel-Krupp <itzhak.tzeel-krupp@intel.com>
Signed-off-by: Oren Weil <oren.jer.weil@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2011-05-15 18:43:41 +08:00
|
|
|
|
2014-03-19 04:52:04 +08:00
|
|
|
rets = pm_runtime_get(&dev->pdev->dev);
|
|
|
|
if (rets < 0 && rets != -EINPROGRESS) {
|
|
|
|
pm_runtime_put_noidle(&dev->pdev->dev);
|
|
|
|
cl_err(dev, cl, "rpm: get failed %d\n", rets);
|
|
|
|
return rets;
|
|
|
|
}
|
|
|
|
|
2012-10-11 22:35:08 +08:00
|
|
|
cb = mei_io_cb_init(cl, NULL);
|
2014-03-19 04:52:04 +08:00
|
|
|
if (!cb) {
|
|
|
|
rets = -ENOMEM;
|
|
|
|
goto out;
|
|
|
|
}
|
staging/mei: PCI device and char driver support.
contains module entries and PCI driver and char device
definitions (using file_operations, pci_driver struts).
The HW interface is exposed on PCI interface.
PCI:
The MEI HW resources are memory map 32 bit registers
(Host and ME Status Registers and Data Registers)
and interrupt (shared, with Intel GFX on some chipsets
and USB2 controller on others).
The device is part of the chipsets and cannot be hotplugged.
The MEI device present is determined by BIOS configuration.
Probe:
The driver starts the init MEI flow, that is explained
in the patch "MEI driver init flow" [06/10],
then schedules a timer that handles
timeouts and watchdog heartbeats.
Remove:
The driver closes all connections and stops the watchdog.
The driver expose char device that supports:
open, release, write, read, ioctl, poll.
Open:
Upon open the driver allocates HOST data structure
on behalf of application which will resides in the file's
private data and assign a host ID number which
will identify messages between driver client instance
and MEI client.
The driver also checks readiness of the device. The number
of simultaneously opened instances is limited to 253.
(255 - (amthi + watchdog))
Release:
In release the driver sends a Disconnect Command to
ME feature and clean all the data structs.
IOCTL:
MEI adds new IOCTL: (IOCTL_MEI_CONNECT_CLIENT)
The IOCTL links the current file descriptor to ME feature.
This is done by sending MEI Bus command: 'hbm_client_connect_request'
to the ME and waiting for an answer :'hbm_client_connect_response'.
Upon answer reception the driver updates its and HOST data
structures in file structure to indicate that the file
descriptor is associated to ME feature.
Each ME feature is represented by UUID which is given as
an input parameter to the IOCTL, upon success connect command the
IOCTL will return the ME feature properties.
ME can reject CONNECT commands due to several reasons,
most common are:
Invalid UUID ME or feature does not exists in ME.
No More Connection allowed to this is feature,
usually only one connection is allowed.
Write:
Upon write, the driver splits the user data into several MEI
messages up to 512 bytes each and sends it to the HW.
If the user wants to write data to AMTHI ME feature then the
drivers routes the messages through AMTHI queues.
Read:
In read the driver checks is a connection exists to
current file descriptor and then wait until a data is available.
Message might be received (by interrupt from ME) in multiple chunks.
Only complete message is released to the application.
Poll:
Nothing special here. Waiting for see if we have
data available for reading.
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Itzhak Tzeel-Krupp <itzhak.tzeel-krupp@intel.com>
Signed-off-by: Oren Weil <oren.jer.weil@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2011-05-15 18:43:41 +08:00
|
|
|
|
2013-04-20 03:01:35 +08:00
|
|
|
/* always allocate at least client max message */
|
|
|
|
length = max_t(size_t, length, dev->me_clients[i].props.max_msg_length);
|
|
|
|
rets = mei_io_cb_alloc_resp_buf(cb, length);
|
2012-10-11 22:35:08 +08:00
|
|
|
if (rets)
|
2014-03-19 04:52:04 +08:00
|
|
|
goto out;
|
staging/mei: PCI device and char driver support.
contains module entries and PCI driver and char device
definitions (using file_operations, pci_driver struts).
The HW interface is exposed on PCI interface.
PCI:
The MEI HW resources are memory map 32 bit registers
(Host and ME Status Registers and Data Registers)
and interrupt (shared, with Intel GFX on some chipsets
and USB2 controller on others).
The device is part of the chipsets and cannot be hotplugged.
The MEI device present is determined by BIOS configuration.
Probe:
The driver starts the init MEI flow, that is explained
in the patch "MEI driver init flow" [06/10],
then schedules a timer that handles
timeouts and watchdog heartbeats.
Remove:
The driver closes all connections and stops the watchdog.
The driver expose char device that supports:
open, release, write, read, ioctl, poll.
Open:
Upon open the driver allocates HOST data structure
on behalf of application which will resides in the file's
private data and assign a host ID number which
will identify messages between driver client instance
and MEI client.
The driver also checks readiness of the device. The number
of simultaneously opened instances is limited to 253.
(255 - (amthi + watchdog))
Release:
In release the driver sends a Disconnect Command to
ME feature and clean all the data structs.
IOCTL:
MEI adds new IOCTL: (IOCTL_MEI_CONNECT_CLIENT)
The IOCTL links the current file descriptor to ME feature.
This is done by sending MEI Bus command: 'hbm_client_connect_request'
to the ME and waiting for an answer :'hbm_client_connect_response'.
Upon answer reception the driver updates its and HOST data
structures in file structure to indicate that the file
descriptor is associated to ME feature.
Each ME feature is represented by UUID which is given as
an input parameter to the IOCTL, upon success connect command the
IOCTL will return the ME feature properties.
ME can reject CONNECT commands due to several reasons,
most common are:
Invalid UUID ME or feature does not exists in ME.
No More Connection allowed to this is feature,
usually only one connection is allowed.
Write:
Upon write, the driver splits the user data into several MEI
messages up to 512 bytes each and sends it to the HW.
If the user wants to write data to AMTHI ME feature then the
drivers routes the messages through AMTHI queues.
Read:
In read the driver checks is a connection exists to
current file descriptor and then wait until a data is available.
Message might be received (by interrupt from ME) in multiple chunks.
Only complete message is released to the application.
Poll:
Nothing special here. Waiting for see if we have
data available for reading.
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Itzhak Tzeel-Krupp <itzhak.tzeel-krupp@intel.com>
Signed-off-by: Oren Weil <oren.jer.weil@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2011-05-15 18:43:41 +08:00
|
|
|
|
2012-11-11 23:38:00 +08:00
|
|
|
cb->fop_type = MEI_FOP_READ;
|
2014-02-19 23:35:47 +08:00
|
|
|
if (mei_hbuf_acquire(dev)) {
|
2014-03-31 22:59:24 +08:00
|
|
|
rets = mei_hbm_cl_flow_control_req(dev, cl);
|
|
|
|
if (rets < 0)
|
2014-03-19 04:52:04 +08:00
|
|
|
goto out;
|
|
|
|
|
2012-10-15 18:06:48 +08:00
|
|
|
list_add_tail(&cb->list, &dev->read_list.list);
|
staging/mei: PCI device and char driver support.
contains module entries and PCI driver and char device
definitions (using file_operations, pci_driver struts).
The HW interface is exposed on PCI interface.
PCI:
The MEI HW resources are memory map 32 bit registers
(Host and ME Status Registers and Data Registers)
and interrupt (shared, with Intel GFX on some chipsets
and USB2 controller on others).
The device is part of the chipsets and cannot be hotplugged.
The MEI device present is determined by BIOS configuration.
Probe:
The driver starts the init MEI flow, that is explained
in the patch "MEI driver init flow" [06/10],
then schedules a timer that handles
timeouts and watchdog heartbeats.
Remove:
The driver closes all connections and stops the watchdog.
The driver expose char device that supports:
open, release, write, read, ioctl, poll.
Open:
Upon open the driver allocates HOST data structure
on behalf of application which will resides in the file's
private data and assign a host ID number which
will identify messages between driver client instance
and MEI client.
The driver also checks readiness of the device. The number
of simultaneously opened instances is limited to 253.
(255 - (amthi + watchdog))
Release:
In release the driver sends a Disconnect Command to
ME feature and clean all the data structs.
IOCTL:
MEI adds new IOCTL: (IOCTL_MEI_CONNECT_CLIENT)
The IOCTL links the current file descriptor to ME feature.
This is done by sending MEI Bus command: 'hbm_client_connect_request'
to the ME and waiting for an answer :'hbm_client_connect_response'.
Upon answer reception the driver updates its and HOST data
structures in file structure to indicate that the file
descriptor is associated to ME feature.
Each ME feature is represented by UUID which is given as
an input parameter to the IOCTL, upon success connect command the
IOCTL will return the ME feature properties.
ME can reject CONNECT commands due to several reasons,
most common are:
Invalid UUID ME or feature does not exists in ME.
No More Connection allowed to this is feature,
usually only one connection is allowed.
Write:
Upon write, the driver splits the user data into several MEI
messages up to 512 bytes each and sends it to the HW.
If the user wants to write data to AMTHI ME feature then the
drivers routes the messages through AMTHI queues.
Read:
In read the driver checks is a connection exists to
current file descriptor and then wait until a data is available.
Message might be received (by interrupt from ME) in multiple chunks.
Only complete message is released to the application.
Poll:
Nothing special here. Waiting for see if we have
data available for reading.
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Itzhak Tzeel-Krupp <itzhak.tzeel-krupp@intel.com>
Signed-off-by: Oren Weil <oren.jer.weil@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2011-05-15 18:43:41 +08:00
|
|
|
} else {
|
2012-10-15 18:06:48 +08:00
|
|
|
list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
|
staging/mei: PCI device and char driver support.
contains module entries and PCI driver and char device
definitions (using file_operations, pci_driver struts).
The HW interface is exposed on PCI interface.
PCI:
The MEI HW resources are memory map 32 bit registers
(Host and ME Status Registers and Data Registers)
and interrupt (shared, with Intel GFX on some chipsets
and USB2 controller on others).
The device is part of the chipsets and cannot be hotplugged.
The MEI device present is determined by BIOS configuration.
Probe:
The driver starts the init MEI flow, that is explained
in the patch "MEI driver init flow" [06/10],
then schedules a timer that handles
timeouts and watchdog heartbeats.
Remove:
The driver closes all connections and stops the watchdog.
The driver expose char device that supports:
open, release, write, read, ioctl, poll.
Open:
Upon open the driver allocates HOST data structure
on behalf of application which will resides in the file's
private data and assign a host ID number which
will identify messages between driver client instance
and MEI client.
The driver also checks readiness of the device. The number
of simultaneously opened instances is limited to 253.
(255 - (amthi + watchdog))
Release:
In release the driver sends a Disconnect Command to
ME feature and clean all the data structs.
IOCTL:
MEI adds new IOCTL: (IOCTL_MEI_CONNECT_CLIENT)
The IOCTL links the current file descriptor to ME feature.
This is done by sending MEI Bus command: 'hbm_client_connect_request'
to the ME and waiting for an answer :'hbm_client_connect_response'.
Upon answer reception the driver updates its and HOST data
structures in file structure to indicate that the file
descriptor is associated to ME feature.
Each ME feature is represented by UUID which is given as
an input parameter to the IOCTL, upon success connect command the
IOCTL will return the ME feature properties.
ME can reject CONNECT commands due to several reasons,
most common are:
Invalid UUID ME or feature does not exists in ME.
No More Connection allowed to this is feature,
usually only one connection is allowed.
Write:
Upon write, the driver splits the user data into several MEI
messages up to 512 bytes each and sends it to the HW.
If the user wants to write data to AMTHI ME feature then the
drivers routes the messages through AMTHI queues.
Read:
In read the driver checks is a connection exists to
current file descriptor and then wait until a data is available.
Message might be received (by interrupt from ME) in multiple chunks.
Only complete message is released to the application.
Poll:
Nothing special here. Waiting for see if we have
data available for reading.
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Itzhak Tzeel-Krupp <itzhak.tzeel-krupp@intel.com>
Signed-off-by: Oren Weil <oren.jer.weil@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2011-05-15 18:43:41 +08:00
|
|
|
}
|
2014-02-13 03:27:25 +08:00
|
|
|
|
|
|
|
cl->read_cb = cb;
|
|
|
|
|
2014-03-19 04:52:04 +08:00
|
|
|
out:
|
|
|
|
cl_dbg(dev, cl, "rpm: autosuspend\n");
|
|
|
|
pm_runtime_mark_last_busy(&dev->pdev->dev);
|
|
|
|
pm_runtime_put_autosuspend(&dev->pdev->dev);
|
|
|
|
|
|
|
|
if (rets)
|
|
|
|
mei_io_cb_free(cb);
|
|
|
|
|
staging/mei: PCI device and char driver support.
contains module entries and PCI driver and char device
definitions (using file_operations, pci_driver struts).
The HW interface is exposed on PCI interface.
PCI:
The MEI HW resources are memory map 32 bit registers
(Host and ME Status Registers and Data Registers)
and interrupt (shared, with Intel GFX on some chipsets
and USB2 controller on others).
The device is part of the chipsets and cannot be hotplugged.
The MEI device present is determined by BIOS configuration.
Probe:
The driver starts the init MEI flow, that is explained
in the patch "MEI driver init flow" [06/10],
then schedules a timer that handles
timeouts and watchdog heartbeats.
Remove:
The driver closes all connections and stops the watchdog.
The driver expose char device that supports:
open, release, write, read, ioctl, poll.
Open:
Upon open the driver allocates HOST data structure
on behalf of application which will resides in the file's
private data and assign a host ID number which
will identify messages between driver client instance
and MEI client.
The driver also checks readiness of the device. The number
of simultaneously opened instances is limited to 253.
(255 - (amthi + watchdog))
Release:
In release the driver sends a Disconnect Command to
ME feature and clean all the data structs.
IOCTL:
MEI adds new IOCTL: (IOCTL_MEI_CONNECT_CLIENT)
The IOCTL links the current file descriptor to ME feature.
This is done by sending MEI Bus command: 'hbm_client_connect_request'
to the ME and waiting for an answer :'hbm_client_connect_response'.
Upon answer reception the driver updates its and HOST data
structures in file structure to indicate that the file
descriptor is associated to ME feature.
Each ME feature is represented by UUID which is given as
an input parameter to the IOCTL, upon success connect command the
IOCTL will return the ME feature properties.
ME can reject CONNECT commands due to several reasons,
most common are:
Invalid UUID ME or feature does not exists in ME.
No More Connection allowed to this is feature,
usually only one connection is allowed.
Write:
Upon write, the driver splits the user data into several MEI
messages up to 512 bytes each and sends it to the HW.
If the user wants to write data to AMTHI ME feature then the
drivers routes the messages through AMTHI queues.
Read:
In read the driver checks is a connection exists to
current file descriptor and then wait until a data is available.
Message might be received (by interrupt from ME) in multiple chunks.
Only complete message is released to the application.
Poll:
Nothing special here. Waiting for see if we have
data available for reading.
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Itzhak Tzeel-Krupp <itzhak.tzeel-krupp@intel.com>
Signed-off-by: Oren Weil <oren.jer.weil@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2011-05-15 18:43:41 +08:00
|
|
|
return rets;
|
|
|
|
}
|
|
|
|
|
2013-06-23 14:36:59 +08:00
|
|
|
/**
|
2014-02-19 23:35:48 +08:00
|
|
|
* mei_cl_irq_write - write a message to device
|
2013-06-23 14:36:59 +08:00
|
|
|
* from the interrupt thread context
|
|
|
|
*
|
|
|
|
* @cl: client
|
|
|
|
* @cb: callback block.
|
|
|
|
* @cmpl_list: complete list.
|
|
|
|
*
|
|
|
|
* returns 0, OK; otherwise error.
|
|
|
|
*/
|
2014-02-19 23:35:48 +08:00
|
|
|
int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
|
|
|
|
struct mei_cl_cb *cmpl_list)
|
2013-06-23 14:36:59 +08:00
|
|
|
{
|
2013-09-17 04:44:44 +08:00
|
|
|
struct mei_device *dev;
|
|
|
|
struct mei_msg_data *buf;
|
2013-06-23 14:36:59 +08:00
|
|
|
struct mei_msg_hdr mei_hdr;
|
2013-09-17 04:44:44 +08:00
|
|
|
size_t len;
|
|
|
|
u32 msg_slots;
|
2014-02-19 23:35:48 +08:00
|
|
|
int slots;
|
2013-09-17 04:44:43 +08:00
|
|
|
int rets;
|
2013-06-23 14:36:59 +08:00
|
|
|
|
2013-09-17 04:44:44 +08:00
|
|
|
if (WARN_ON(!cl || !cl->dev))
|
|
|
|
return -ENODEV;
|
|
|
|
|
|
|
|
dev = cl->dev;
|
|
|
|
|
|
|
|
buf = &cb->request_buffer;
|
|
|
|
|
|
|
|
rets = mei_cl_flow_ctrl_creds(cl);
|
|
|
|
if (rets < 0)
|
|
|
|
return rets;
|
|
|
|
|
|
|
|
if (rets == 0) {
|
2014-03-19 04:52:04 +08:00
|
|
|
cl_dbg(dev, cl, "No flow control credentials: not sending.\n");
|
2013-09-17 04:44:44 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-02-19 23:35:48 +08:00
|
|
|
slots = mei_hbuf_empty_slots(dev);
|
2013-09-17 04:44:44 +08:00
|
|
|
len = buf->size - cb->buf_idx;
|
|
|
|
msg_slots = mei_data2slots(len);
|
|
|
|
|
2013-06-23 14:36:59 +08:00
|
|
|
mei_hdr.host_addr = cl->host_client_id;
|
|
|
|
mei_hdr.me_addr = cl->me_client_id;
|
|
|
|
mei_hdr.reserved = 0;
|
2013-12-17 21:56:56 +08:00
|
|
|
mei_hdr.internal = cb->internal;
|
2013-06-23 14:36:59 +08:00
|
|
|
|
2014-02-19 23:35:48 +08:00
|
|
|
if (slots >= msg_slots) {
|
2013-06-23 14:36:59 +08:00
|
|
|
mei_hdr.length = len;
|
|
|
|
mei_hdr.msg_complete = 1;
|
|
|
|
/* Split the message only if we can write the whole host buffer */
|
2014-02-19 23:35:48 +08:00
|
|
|
} else if (slots == dev->hbuf_depth) {
|
|
|
|
msg_slots = slots;
|
|
|
|
len = (slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
|
2013-06-23 14:36:59 +08:00
|
|
|
mei_hdr.length = len;
|
|
|
|
mei_hdr.msg_complete = 0;
|
|
|
|
} else {
|
|
|
|
/* wait for next time the host buffer is empty */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-09-15 23:11:07 +08:00
|
|
|
cl_dbg(dev, cl, "buf: size = %d idx = %lu\n",
|
2013-06-23 14:36:59 +08:00
|
|
|
cb->request_buffer.size, cb->buf_idx);
|
|
|
|
|
2013-09-17 04:44:44 +08:00
|
|
|
rets = mei_write_message(dev, &mei_hdr, buf->data + cb->buf_idx);
|
2013-09-17 04:44:43 +08:00
|
|
|
if (rets) {
|
|
|
|
cl->status = rets;
|
2013-06-23 14:36:59 +08:00
|
|
|
list_move_tail(&cb->list, &cmpl_list->list);
|
2013-09-17 04:44:43 +08:00
|
|
|
return rets;
|
2013-06-23 14:36:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
cl->status = 0;
|
2013-06-23 14:37:00 +08:00
|
|
|
cl->writing_state = MEI_WRITING;
|
2013-06-23 14:36:59 +08:00
|
|
|
cb->buf_idx += mei_hdr.length;
|
2013-06-23 14:37:00 +08:00
|
|
|
|
2013-06-23 14:36:59 +08:00
|
|
|
if (mei_hdr.msg_complete) {
|
|
|
|
if (mei_cl_flow_ctrl_reduce(cl))
|
2013-09-17 04:44:43 +08:00
|
|
|
return -EIO;
|
2013-06-23 14:36:59 +08:00
|
|
|
list_move_tail(&cb->list, &dev->write_waiting_list.list);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-04-09 02:56:37 +08:00
|
|
|
/**
|
|
|
|
* mei_cl_write - submit a write cb to mei device
|
|
|
|
assumes device_lock is locked
|
|
|
|
*
|
|
|
|
* @cl: host client
|
|
|
|
* @cl: write callback with filled data
|
|
|
|
*
|
2014-01-09 04:31:46 +08:00
|
|
|
* returns number of bytes sent on success, <0 on failure.
|
2013-04-09 02:56:37 +08:00
|
|
|
*/
|
|
|
|
int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
|
|
|
|
{
|
|
|
|
struct mei_device *dev;
|
|
|
|
struct mei_msg_data *buf;
|
|
|
|
struct mei_msg_hdr mei_hdr;
|
|
|
|
int rets;
|
|
|
|
|
|
|
|
|
|
|
|
if (WARN_ON(!cl || !cl->dev))
|
|
|
|
return -ENODEV;
|
|
|
|
|
|
|
|
if (WARN_ON(!cb))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
dev = cl->dev;
|
|
|
|
|
|
|
|
|
|
|
|
buf = &cb->request_buffer;
|
|
|
|
|
2013-09-15 23:11:07 +08:00
|
|
|
cl_dbg(dev, cl, "mei_cl_write %d\n", buf->size);
|
2013-04-09 02:56:37 +08:00
|
|
|
|
2014-03-19 04:52:04 +08:00
|
|
|
rets = pm_runtime_get(&dev->pdev->dev);
|
|
|
|
if (rets < 0 && rets != -EINPROGRESS) {
|
|
|
|
pm_runtime_put_noidle(&dev->pdev->dev);
|
|
|
|
cl_err(dev, cl, "rpm: get failed %d\n", rets);
|
|
|
|
return rets;
|
|
|
|
}
|
2013-04-09 02:56:37 +08:00
|
|
|
|
|
|
|
cb->fop_type = MEI_FOP_WRITE;
|
2014-02-19 23:35:47 +08:00
|
|
|
cb->buf_idx = 0;
|
|
|
|
cl->writing_state = MEI_IDLE;
|
|
|
|
|
|
|
|
mei_hdr.host_addr = cl->host_client_id;
|
|
|
|
mei_hdr.me_addr = cl->me_client_id;
|
|
|
|
mei_hdr.reserved = 0;
|
|
|
|
mei_hdr.msg_complete = 0;
|
|
|
|
mei_hdr.internal = cb->internal;
|
2013-04-09 02:56:37 +08:00
|
|
|
|
|
|
|
rets = mei_cl_flow_ctrl_creds(cl);
|
|
|
|
if (rets < 0)
|
|
|
|
goto err;
|
|
|
|
|
2014-02-19 23:35:47 +08:00
|
|
|
if (rets == 0) {
|
|
|
|
cl_dbg(dev, cl, "No flow control credentials: not sending.\n");
|
|
|
|
rets = buf->size;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
if (!mei_hbuf_acquire(dev)) {
|
|
|
|
cl_dbg(dev, cl, "Cannot acquire the host buffer: not sending.\n");
|
2013-04-09 02:56:37 +08:00
|
|
|
rets = buf->size;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for a maximum length */
|
|
|
|
if (buf->size > mei_hbuf_max_len(dev)) {
|
|
|
|
mei_hdr.length = mei_hbuf_max_len(dev);
|
|
|
|
mei_hdr.msg_complete = 0;
|
|
|
|
} else {
|
|
|
|
mei_hdr.length = buf->size;
|
|
|
|
mei_hdr.msg_complete = 1;
|
|
|
|
}
|
|
|
|
|
2013-09-17 04:44:43 +08:00
|
|
|
rets = mei_write_message(dev, &mei_hdr, buf->data);
|
|
|
|
if (rets)
|
2013-04-09 02:56:37 +08:00
|
|
|
goto err;
|
|
|
|
|
|
|
|
cl->writing_state = MEI_WRITING;
|
|
|
|
cb->buf_idx = mei_hdr.length;
|
|
|
|
|
|
|
|
out:
|
|
|
|
if (mei_hdr.msg_complete) {
|
2014-02-19 23:35:49 +08:00
|
|
|
rets = mei_cl_flow_ctrl_reduce(cl);
|
|
|
|
if (rets < 0)
|
2013-04-09 02:56:37 +08:00
|
|
|
goto err;
|
2014-02-19 23:35:49 +08:00
|
|
|
|
2013-04-09 02:56:37 +08:00
|
|
|
list_add_tail(&cb->list, &dev->write_waiting_list.list);
|
|
|
|
} else {
|
|
|
|
list_add_tail(&cb->list, &dev->write_list.list);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (blocking && cl->writing_state != MEI_WRITE_COMPLETE) {
|
|
|
|
|
|
|
|
mutex_unlock(&dev->device_lock);
|
2014-02-19 23:35:49 +08:00
|
|
|
rets = wait_event_interruptible(cl->tx_wait,
|
|
|
|
cl->writing_state == MEI_WRITE_COMPLETE);
|
2013-04-09 02:56:37 +08:00
|
|
|
mutex_lock(&dev->device_lock);
|
2014-02-19 23:35:49 +08:00
|
|
|
/* wait_event_interruptible returns -ERESTARTSYS */
|
|
|
|
if (rets) {
|
|
|
|
if (signal_pending(current))
|
|
|
|
rets = -EINTR;
|
|
|
|
goto err;
|
|
|
|
}
|
2013-04-09 02:56:37 +08:00
|
|
|
}
|
2014-02-19 23:35:49 +08:00
|
|
|
|
|
|
|
rets = buf->size;
|
2013-04-09 02:56:37 +08:00
|
|
|
err:
|
2014-03-19 04:52:04 +08:00
|
|
|
cl_dbg(dev, cl, "rpm: autosuspend\n");
|
|
|
|
pm_runtime_mark_last_busy(&dev->pdev->dev);
|
|
|
|
pm_runtime_put_autosuspend(&dev->pdev->dev);
|
|
|
|
|
2013-04-09 02:56:37 +08:00
|
|
|
return rets;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-05-12 20:34:45 +08:00
|
|
|
/**
|
|
|
|
* mei_cl_complete - processes completed operation for a client
|
|
|
|
*
|
|
|
|
* @cl: private data of the file object.
|
|
|
|
* @cb: callback block.
|
|
|
|
*/
|
|
|
|
void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
|
|
|
|
{
|
|
|
|
if (cb->fop_type == MEI_FOP_WRITE) {
|
|
|
|
mei_io_cb_free(cb);
|
|
|
|
cb = NULL;
|
|
|
|
cl->writing_state = MEI_WRITE_COMPLETE;
|
|
|
|
if (waitqueue_active(&cl->tx_wait))
|
|
|
|
wake_up_interruptible(&cl->tx_wait);
|
|
|
|
|
|
|
|
} else if (cb->fop_type == MEI_FOP_READ &&
|
|
|
|
MEI_READING == cl->reading_state) {
|
|
|
|
cl->reading_state = MEI_READ_COMPLETE;
|
|
|
|
if (waitqueue_active(&cl->rx_wait))
|
|
|
|
wake_up_interruptible(&cl->rx_wait);
|
|
|
|
else
|
|
|
|
mei_cl_bus_rx_event(cl);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-09 02:56:37 +08:00
|
|
|
|
2013-02-06 20:06:44 +08:00
|
|
|
/**
|
|
|
|
* mei_cl_all_disconnect - disconnect forcefully all connected clients
|
|
|
|
*
|
|
|
|
* @dev - mei device
|
|
|
|
*/
|
|
|
|
|
|
|
|
void mei_cl_all_disconnect(struct mei_device *dev)
|
|
|
|
{
|
2014-02-17 21:13:25 +08:00
|
|
|
struct mei_cl *cl;
|
2013-02-06 20:06:44 +08:00
|
|
|
|
2014-02-17 21:13:25 +08:00
|
|
|
list_for_each_entry(cl, &dev->file_list, link) {
|
2013-02-06 20:06:44 +08:00
|
|
|
cl->state = MEI_FILE_DISCONNECTED;
|
|
|
|
cl->mei_flow_ctrl_creds = 0;
|
|
|
|
cl->timer_count = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2013-07-24 21:22:57 +08:00
|
|
|
* mei_cl_all_wakeup - wake up all readers and writers they can be interrupted
|
2013-02-06 20:06:44 +08:00
|
|
|
*
|
|
|
|
* @dev - mei device
|
|
|
|
*/
|
2013-07-24 21:22:57 +08:00
|
|
|
void mei_cl_all_wakeup(struct mei_device *dev)
|
2013-02-06 20:06:44 +08:00
|
|
|
{
|
2014-02-17 21:13:25 +08:00
|
|
|
struct mei_cl *cl;
|
|
|
|
list_for_each_entry(cl, &dev->file_list, link) {
|
2013-02-06 20:06:44 +08:00
|
|
|
if (waitqueue_active(&cl->rx_wait)) {
|
2013-09-15 23:11:07 +08:00
|
|
|
cl_dbg(dev, cl, "Waking up reading client!\n");
|
2013-02-06 20:06:44 +08:00
|
|
|
wake_up_interruptible(&cl->rx_wait);
|
|
|
|
}
|
2013-07-24 21:22:57 +08:00
|
|
|
if (waitqueue_active(&cl->tx_wait)) {
|
2013-09-15 23:11:07 +08:00
|
|
|
cl_dbg(dev, cl, "Waking up writing client!\n");
|
2013-07-24 21:22:57 +08:00
|
|
|
wake_up_interruptible(&cl->tx_wait);
|
|
|
|
}
|
2013-02-06 20:06:44 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* mei_cl_all_write_clear - clear all pending writes
|
|
|
|
|
|
|
|
* @dev - mei device
|
|
|
|
*/
|
|
|
|
void mei_cl_all_write_clear(struct mei_device *dev)
|
|
|
|
{
|
2014-03-10 21:10:40 +08:00
|
|
|
mei_io_list_free(&dev->write_list, NULL);
|
|
|
|
mei_io_list_free(&dev->write_waiting_list, NULL);
|
2013-02-06 20:06:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|