19ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/*
29ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
39ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * Intel Management Engine Interface (Intel MEI) Linux driver
49ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * Copyright (c) 2003-2012, Intel Corporation.
59ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
69ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * This program is free software; you can redistribute it and/or modify it
79ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * under the terms and conditions of the GNU General Public License,
89ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * version 2, as published by the Free Software Foundation.
99ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
109ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * This program is distributed in the hope it will be useful, but WITHOUT
119ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
129ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
139ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * more details.
149ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
159ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */
169ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
179ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler#include <linux/sched.h>
189ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler#include <linux/wait.h>
199ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler#include <linux/delay.h>
201f180359f42fc6fda4600175c63f2a84f444cc92Tomas Winkler#include <linux/slab.h>
2104bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler#include <linux/pm_runtime.h>
229ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
239ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler#include <linux/mei.h>
249ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
259ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler#include "mei_dev.h"
269ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler#include "hbm.h"
2790e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler#include "client.h"
2890e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler
2990e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler/**
30a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * mei_me_cl_by_uuid - locate me client by uuid
3190e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler *
3290e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler * @dev: mei device
33a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * @uuid: me client uuid
34a27a76d3c07de08a0d0d298b6bc280c5b820e997Alexander Usyskin *
35a27a76d3c07de08a0d0d298b6bc280c5b820e997Alexander Usyskin * Locking: called under "dev->device_lock" lock
36a27a76d3c07de08a0d0d298b6bc280c5b820e997Alexander Usyskin *
37a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * Return: me client or NULL if not found
3890e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler */
39d320832f64666089a06778782e42fac29abd7bf7Tomas Winklerstruct mei_me_client *mei_me_cl_by_uuid(const struct mei_device *dev,
40d320832f64666089a06778782e42fac29abd7bf7Tomas Winkler					const uuid_le *uuid)
4190e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler{
425ca2d3882d60c040285d0b45df731e11f5da7c64Tomas Winkler	struct mei_me_client *me_cl;
4390e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler
445ca2d3882d60c040285d0b45df731e11f5da7c64Tomas Winkler	list_for_each_entry(me_cl, &dev->me_clients, list)
455ca2d3882d60c040285d0b45df731e11f5da7c64Tomas Winkler		if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0)
465ca2d3882d60c040285d0b45df731e11f5da7c64Tomas Winkler			return me_cl;
4790e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler
48d320832f64666089a06778782e42fac29abd7bf7Tomas Winkler	return NULL;
4990e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler}
5090e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler
5190e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler/**
52a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * mei_me_cl_by_id - locate me client by client id
5390e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler *
5490e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler * @dev: the device structure
5590e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler * @client_id: me client id
5690e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler *
5790e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler * Locking: called under "dev->device_lock" lock
5890e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler *
59a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * Return: me client or NULL if not found
6090e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler */
61d320832f64666089a06778782e42fac29abd7bf7Tomas Winklerstruct mei_me_client *mei_me_cl_by_id(struct mei_device *dev, u8 client_id)
6290e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler{
63a27a76d3c07de08a0d0d298b6bc280c5b820e997Alexander Usyskin
645ca2d3882d60c040285d0b45df731e11f5da7c64Tomas Winkler	struct mei_me_client *me_cl;
6590e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler
665ca2d3882d60c040285d0b45df731e11f5da7c64Tomas Winkler	list_for_each_entry(me_cl, &dev->me_clients, list)
675ca2d3882d60c040285d0b45df731e11f5da7c64Tomas Winkler		if (me_cl->client_id == client_id)
685ca2d3882d60c040285d0b45df731e11f5da7c64Tomas Winkler			return me_cl;
69d320832f64666089a06778782e42fac29abd7bf7Tomas Winkler	return NULL;
7090e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler}
719ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
72a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin/**
73a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * mei_me_cl_by_uuid_id - locate me client by client id and uuid
74a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin *
75a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * @dev: the device structure
76a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * @uuid: me client uuid
77a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * @client_id: me client id
78a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin *
79a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * Locking: called under "dev->device_lock" lock
80a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin *
81a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * Return: me client or NULL if not found
82a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin */
83d880f3294d0576e79dfab4e2cd5a2eb62fe188f0Tomas Winklerstruct mei_me_client *mei_me_cl_by_uuid_id(struct mei_device *dev,
84d880f3294d0576e79dfab4e2cd5a2eb62fe188f0Tomas Winkler					   const uuid_le *uuid, u8 client_id)
85d880f3294d0576e79dfab4e2cd5a2eb62fe188f0Tomas Winkler{
86d880f3294d0576e79dfab4e2cd5a2eb62fe188f0Tomas Winkler	struct mei_me_client *me_cl;
87d880f3294d0576e79dfab4e2cd5a2eb62fe188f0Tomas Winkler
88d880f3294d0576e79dfab4e2cd5a2eb62fe188f0Tomas Winkler	list_for_each_entry(me_cl, &dev->me_clients, list)
89d880f3294d0576e79dfab4e2cd5a2eb62fe188f0Tomas Winkler		if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0 &&
90d880f3294d0576e79dfab4e2cd5a2eb62fe188f0Tomas Winkler		    me_cl->client_id == client_id)
91d880f3294d0576e79dfab4e2cd5a2eb62fe188f0Tomas Winkler			return me_cl;
92d880f3294d0576e79dfab4e2cd5a2eb62fe188f0Tomas Winkler	return NULL;
93d880f3294d0576e79dfab4e2cd5a2eb62fe188f0Tomas Winkler}
94d880f3294d0576e79dfab4e2cd5a2eb62fe188f0Tomas Winkler
9525ca6472b590e87efba314892a76bd5629c8c989Tomas Winkler/**
9625ca6472b590e87efba314892a76bd5629c8c989Tomas Winkler * mei_me_cl_remove - remove me client matching uuid and client_id
9725ca6472b590e87efba314892a76bd5629c8c989Tomas Winkler *
9825ca6472b590e87efba314892a76bd5629c8c989Tomas Winkler * @dev: the device structure
9925ca6472b590e87efba314892a76bd5629c8c989Tomas Winkler * @uuid: me client uuid
10025ca6472b590e87efba314892a76bd5629c8c989Tomas Winkler * @client_id: me client address
10125ca6472b590e87efba314892a76bd5629c8c989Tomas Winkler */
10225ca6472b590e87efba314892a76bd5629c8c989Tomas Winklervoid mei_me_cl_remove(struct mei_device *dev, const uuid_le *uuid, u8 client_id)
10325ca6472b590e87efba314892a76bd5629c8c989Tomas Winkler{
10425ca6472b590e87efba314892a76bd5629c8c989Tomas Winkler	struct mei_me_client *me_cl, *next;
10525ca6472b590e87efba314892a76bd5629c8c989Tomas Winkler
10625ca6472b590e87efba314892a76bd5629c8c989Tomas Winkler	list_for_each_entry_safe(me_cl, next, &dev->me_clients, list) {
10725ca6472b590e87efba314892a76bd5629c8c989Tomas Winkler		if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0 &&
10825ca6472b590e87efba314892a76bd5629c8c989Tomas Winkler		    me_cl->client_id == client_id) {
10925ca6472b590e87efba314892a76bd5629c8c989Tomas Winkler			list_del(&me_cl->list);
11025ca6472b590e87efba314892a76bd5629c8c989Tomas Winkler			kfree(me_cl);
11125ca6472b590e87efba314892a76bd5629c8c989Tomas Winkler			break;
11225ca6472b590e87efba314892a76bd5629c8c989Tomas Winkler		}
11325ca6472b590e87efba314892a76bd5629c8c989Tomas Winkler	}
11425ca6472b590e87efba314892a76bd5629c8c989Tomas Winkler}
11525ca6472b590e87efba314892a76bd5629c8c989Tomas Winkler
1169ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
1179ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/**
118cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * mei_cl_cmp_id - tells if the clients are the same
1199ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
120cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * @cl1: host client 1
121cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * @cl2: host client 2
122cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler *
123a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * Return: true  - if the clients has same host and me ids
124cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler *         false - otherwise
125cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler */
126cc99ecfdac01215594c73907726b12f251c21e20Tomas Winklerstatic inline bool mei_cl_cmp_id(const struct mei_cl *cl1,
127cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler				const struct mei_cl *cl2)
128cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler{
129cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler	return cl1 && cl2 &&
130cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler		(cl1->host_client_id == cl2->host_client_id) &&
131cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler		(cl1->me_client_id == cl2->me_client_id);
132cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler}
133cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler
134cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler/**
135cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * mei_io_list_flush - removes cbs belonging to cl.
136cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler *
137cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * @list:  an instance of our list structure
138cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * @cl:    host client, can be NULL for flushing the whole list
139cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * @free:  whether to free the cbs
1409ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */
141cc99ecfdac01215594c73907726b12f251c21e20Tomas Winklerstatic void __mei_io_list_flush(struct mei_cl_cb *list,
142cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler				struct mei_cl *cl, bool free)
1439ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{
1449ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	struct mei_cl_cb *cb;
1459ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	struct mei_cl_cb *next;
1469ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
147cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler	/* enable removing everything if no cl is specified */
1489ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	list_for_each_entry_safe(cb, next, &list->list, list) {
149cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler		if (!cl || (cb->cl && mei_cl_cmp_id(cl, cb->cl))) {
1509ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler			list_del(&cb->list);
151cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler			if (free)
152cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler				mei_io_cb_free(cb);
153cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler		}
1549ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	}
1559ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler}
1569ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
1579ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/**
158cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * mei_io_list_flush - removes list entry belonging to cl.
159cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler *
160cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * @list:  An instance of our list structure
161cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * @cl: host client
162cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler */
1635456796b1a2aedd2d6345944b73ac41aeb8cb589Alexander Usyskinvoid mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl)
164cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler{
165cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler	__mei_io_list_flush(list, cl, false);
166cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler}
167cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler
168cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler
169cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler/**
170cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * mei_io_list_free - removes cb belonging to cl and free them
171cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler *
172cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * @list:  An instance of our list structure
173cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * @cl: host client
174cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler */
175cc99ecfdac01215594c73907726b12f251c21e20Tomas Winklerstatic inline void mei_io_list_free(struct mei_cl_cb *list, struct mei_cl *cl)
176cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler{
177cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler	__mei_io_list_flush(list, cl, true);
178cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler}
179cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler
180cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler/**
1819ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * mei_io_cb_free - free mei_cb_private related memory
1829ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
1839ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * @cb: mei callback struct
1849ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */
1859ca9050b3df690d9d44e39424ab2a531120af936Tomas Winklervoid mei_io_cb_free(struct mei_cl_cb *cb)
1869ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{
1879ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	if (cb == NULL)
1889ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		return;
1899ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
1909ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	kfree(cb->request_buffer.data);
1919ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	kfree(cb->response_buffer.data);
1929ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	kfree(cb);
1939ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler}
1949ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
1959ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/**
1969ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * mei_io_cb_init - allocate and initialize io callback
1979ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
198a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * @cl: mei client
199393b148f9d0e70cfcb0096985bb0f0742802929eMasanari Iida * @fp: pointer to file structure
2009ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
201a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * Return: mei_cl_cb pointer or NULL;
2029ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */
2039ca9050b3df690d9d44e39424ab2a531120af936Tomas Winklerstruct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp)
2049ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{
2059ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	struct mei_cl_cb *cb;
2069ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
2079ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL);
2089ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	if (!cb)
2099ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		return NULL;
2109ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
2119ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	mei_io_list_init(cb);
2129ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
2139ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	cb->file_object = fp;
2149ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	cb->cl = cl;
2159ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	cb->buf_idx = 0;
2169ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	return cb;
2179ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler}
2189ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
2199ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/**
2209ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * mei_io_cb_alloc_req_buf - allocate request buffer
2219ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
222393b148f9d0e70cfcb0096985bb0f0742802929eMasanari Iida * @cb: io callback structure
223393b148f9d0e70cfcb0096985bb0f0742802929eMasanari Iida * @length: size of the buffer
2249ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
225a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * Return: 0 on success
2269ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *         -EINVAL if cb is NULL
2279ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *         -ENOMEM if allocation failed
2289ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */
2299ca9050b3df690d9d44e39424ab2a531120af936Tomas Winklerint mei_io_cb_alloc_req_buf(struct mei_cl_cb *cb, size_t length)
2309ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{
2319ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	if (!cb)
2329ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		return -EINVAL;
2339ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
2349ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	if (length == 0)
2359ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		return 0;
2369ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
2379ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	cb->request_buffer.data = kmalloc(length, GFP_KERNEL);
2389ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	if (!cb->request_buffer.data)
2399ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		return -ENOMEM;
2409ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	cb->request_buffer.size = length;
2419ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	return 0;
2429ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler}
2439ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/**
24483ce07411dc2316aaaf95a0f193fa2fd76e2e739Alexander Usyskin * mei_io_cb_alloc_resp_buf - allocate response buffer
2459ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
246393b148f9d0e70cfcb0096985bb0f0742802929eMasanari Iida * @cb: io callback structure
247393b148f9d0e70cfcb0096985bb0f0742802929eMasanari Iida * @length: size of the buffer
2489ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
249a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * Return: 0 on success
2509ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *         -EINVAL if cb is NULL
2519ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *         -ENOMEM if allocation failed
2529ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */
2539ca9050b3df690d9d44e39424ab2a531120af936Tomas Winklerint mei_io_cb_alloc_resp_buf(struct mei_cl_cb *cb, size_t length)
2549ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{
2559ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	if (!cb)
2569ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		return -EINVAL;
2579ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
2589ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	if (length == 0)
2599ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		return 0;
2609ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
2619ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	cb->response_buffer.data = kmalloc(length, GFP_KERNEL);
2629ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	if (!cb->response_buffer.data)
2639ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		return -ENOMEM;
2649ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	cb->response_buffer.size = length;
2659ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	return 0;
2669ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler}
2679ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
2689ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
2699ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
2709ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/**
2719ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * mei_cl_flush_queues - flushes queue lists belonging to cl.
2729ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
2739ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * @cl: host client
274ce23139c6c2ee92d5eace20f6f10d716cf295a5bAlexander Usyskin *
275ce23139c6c2ee92d5eace20f6f10d716cf295a5bAlexander Usyskin * Return: 0 on success, -EINVAL if cl or cl->dev is NULL.
2769ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */
2779ca9050b3df690d9d44e39424ab2a531120af936Tomas Winklerint mei_cl_flush_queues(struct mei_cl *cl)
2789ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{
279c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin	struct mei_device *dev;
280c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin
28190e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	if (WARN_ON(!cl || !cl->dev))
2829ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		return -EINVAL;
2839ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
284c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin	dev = cl->dev;
285c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin
286c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin	cl_dbg(dev, cl, "remove list entry belonging to cl\n");
2879ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	mei_io_list_flush(&cl->dev->read_list, cl);
288cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler	mei_io_list_free(&cl->dev->write_list, cl);
289cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler	mei_io_list_free(&cl->dev->write_waiting_list, cl);
2909ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	mei_io_list_flush(&cl->dev->ctrl_wr_list, cl);
2919ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	mei_io_list_flush(&cl->dev->ctrl_rd_list, cl);
2929ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	mei_io_list_flush(&cl->dev->amthif_cmd_list, cl);
2939ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	mei_io_list_flush(&cl->dev->amthif_rd_complete_list, cl);
2949ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	return 0;
2959ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler}
2969ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
2979ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
2989ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/**
29983ce07411dc2316aaaf95a0f193fa2fd76e2e739Alexander Usyskin * mei_cl_init - initializes cl.
3009ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
3019ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * @cl: host client to be initialized
3029ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * @dev: mei device
3039ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */
3049ca9050b3df690d9d44e39424ab2a531120af936Tomas Winklervoid mei_cl_init(struct mei_cl *cl, struct mei_device *dev)
3059ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{
3069ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	memset(cl, 0, sizeof(struct mei_cl));
3079ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	init_waitqueue_head(&cl->wait);
3089ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	init_waitqueue_head(&cl->rx_wait);
3099ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	init_waitqueue_head(&cl->tx_wait);
3109ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	INIT_LIST_HEAD(&cl->link);
311a7b71bc043aded9da4cf51f85271e0779161fe22Samuel Ortiz	INIT_LIST_HEAD(&cl->device_link);
3129ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	cl->reading_state = MEI_IDLE;
3139ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	cl->writing_state = MEI_IDLE;
3149ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	cl->dev = dev;
3159ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler}
3169ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
3179ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/**
3189ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * mei_cl_allocate - allocates cl  structure and sets it up.
3199ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
3209ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * @dev: mei device
321a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * Return:  The allocated file or NULL on failure
3229ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */
3239ca9050b3df690d9d44e39424ab2a531120af936Tomas Winklerstruct mei_cl *mei_cl_allocate(struct mei_device *dev)
3249ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{
3259ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	struct mei_cl *cl;
3269ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
3279ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	cl = kmalloc(sizeof(struct mei_cl), GFP_KERNEL);
3289ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	if (!cl)
3299ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		return NULL;
3309ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
3319ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	mei_cl_init(cl, dev);
3329ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
3339ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	return cl;
3349ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler}
3359ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
33690e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler/**
33790e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler * mei_cl_find_read_cb - find this cl's callback in the read list
33890e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler *
339393b148f9d0e70cfcb0096985bb0f0742802929eMasanari Iida * @cl: host client
340393b148f9d0e70cfcb0096985bb0f0742802929eMasanari Iida *
341a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * Return: cb on success, NULL on error
34290e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler */
34390e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winklerstruct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl)
34490e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler{
34590e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	struct mei_device *dev = cl->dev;
34631f88f5739e966cb3c524083e2d19b423ece3585Tomas Winkler	struct mei_cl_cb *cb;
34790e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler
34831f88f5739e966cb3c524083e2d19b423ece3585Tomas Winkler	list_for_each_entry(cb, &dev->read_list.list, list)
34990e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler		if (mei_cl_cmp_id(cl, cb->cl))
35090e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler			return cb;
35190e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	return NULL;
35290e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler}
35390e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler
35483ce07411dc2316aaaf95a0f193fa2fd76e2e739Alexander Usyskin/** mei_cl_link: allocate host id in the host map
3559ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
356781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler * @cl - host client
35783ce07411dc2316aaaf95a0f193fa2fd76e2e739Alexander Usyskin * @id - fixed host id or -1 for generic one
358393b148f9d0e70cfcb0096985bb0f0742802929eMasanari Iida *
359a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * Return: 0 on success
3609ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *	-EINVAL on incorrect values
3619ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *	-ENONET if client not found
3629ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */
363781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winklerint mei_cl_link(struct mei_cl *cl, int id)
3649ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{
36590e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	struct mei_device *dev;
36622f96a0eb6c62b570621d77dacbf2589a6de2997Tomas Winkler	long open_handle_count;
3679ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
368781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler	if (WARN_ON(!cl || !cl->dev))
3699ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		return -EINVAL;
3709ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
37190e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	dev = cl->dev;
37290e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler
37383ce07411dc2316aaaf95a0f193fa2fd76e2e739Alexander Usyskin	/* If Id is not assigned get one*/
374781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler	if (id == MEI_HOST_CLIENT_ID_ANY)
375781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler		id = find_first_zero_bit(dev->host_clients_map,
376781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler					MEI_CLIENTS_MAX);
3779ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
378781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler	if (id >= MEI_CLIENTS_MAX) {
3792bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler		dev_err(dev->dev, "id exceeded %d", MEI_CLIENTS_MAX);
380e036cc5727eb6d471442d2a9218990aa11215400Tomas Winkler		return -EMFILE;
381e036cc5727eb6d471442d2a9218990aa11215400Tomas Winkler	}
382e036cc5727eb6d471442d2a9218990aa11215400Tomas Winkler
38322f96a0eb6c62b570621d77dacbf2589a6de2997Tomas Winkler	open_handle_count = dev->open_handle_count + dev->iamthif_open_count;
38422f96a0eb6c62b570621d77dacbf2589a6de2997Tomas Winkler	if (open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) {
3852bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler		dev_err(dev->dev, "open_handle_count exceeded %d",
386e036cc5727eb6d471442d2a9218990aa11215400Tomas Winkler			MEI_MAX_OPEN_HANDLE_COUNT);
387e036cc5727eb6d471442d2a9218990aa11215400Tomas Winkler		return -EMFILE;
3889ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	}
3899ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
390781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler	dev->open_handle_count++;
391781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler
392781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler	cl->host_client_id = id;
393781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler	list_add_tail(&cl->link, &dev->file_list);
394781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler
395781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler	set_bit(id, dev->host_clients_map);
396781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler
397781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler	cl->state = MEI_FILE_INITIALIZING;
398781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler
399c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin	cl_dbg(dev, cl, "link cl\n");
400781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler	return 0;
4019ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler}
402781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler
4039ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/**
40490e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler * mei_cl_unlink - remove me_cl from the list
4059ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
406393b148f9d0e70cfcb0096985bb0f0742802929eMasanari Iida * @cl: host client
407ce23139c6c2ee92d5eace20f6f10d716cf295a5bAlexander Usyskin *
408ce23139c6c2ee92d5eace20f6f10d716cf295a5bAlexander Usyskin * Return: always 0
4099ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */
41090e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winklerint mei_cl_unlink(struct mei_cl *cl)
4119ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{
41290e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	struct mei_device *dev;
41390e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler
414781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler	/* don't shout on error exit path */
415781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler	if (!cl)
416781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler		return 0;
417781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler
4188e9a4a9a5c8e8765417d54ed6917c7e1e4d09f4dTomas Winkler	/* wd and amthif might not be initialized */
4198e9a4a9a5c8e8765417d54ed6917c7e1e4d09f4dTomas Winkler	if (!cl->dev)
4208e9a4a9a5c8e8765417d54ed6917c7e1e4d09f4dTomas Winkler		return 0;
42190e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler
42290e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	dev = cl->dev;
42390e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler
424a14c44d82fcff280fd1138574d4480b2bdd40216Tomas Winkler	cl_dbg(dev, cl, "unlink client");
425a14c44d82fcff280fd1138574d4480b2bdd40216Tomas Winkler
42622f96a0eb6c62b570621d77dacbf2589a6de2997Tomas Winkler	if (dev->open_handle_count > 0)
42722f96a0eb6c62b570621d77dacbf2589a6de2997Tomas Winkler		dev->open_handle_count--;
42822f96a0eb6c62b570621d77dacbf2589a6de2997Tomas Winkler
42922f96a0eb6c62b570621d77dacbf2589a6de2997Tomas Winkler	/* never clear the 0 bit */
43022f96a0eb6c62b570621d77dacbf2589a6de2997Tomas Winkler	if (cl->host_client_id)
43122f96a0eb6c62b570621d77dacbf2589a6de2997Tomas Winkler		clear_bit(cl->host_client_id, dev->host_clients_map);
43222f96a0eb6c62b570621d77dacbf2589a6de2997Tomas Winkler
43322f96a0eb6c62b570621d77dacbf2589a6de2997Tomas Winkler	list_del_init(&cl->link);
43422f96a0eb6c62b570621d77dacbf2589a6de2997Tomas Winkler
43522f96a0eb6c62b570621d77dacbf2589a6de2997Tomas Winkler	cl->state = MEI_FILE_INITIALIZING;
43622f96a0eb6c62b570621d77dacbf2589a6de2997Tomas Winkler
43790e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	return 0;
4389ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler}
4399ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
4409ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
4419ca9050b3df690d9d44e39424ab2a531120af936Tomas Winklervoid mei_host_client_init(struct work_struct *work)
4429ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{
4439ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	struct mei_device *dev = container_of(work,
4449ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler					      struct mei_device, init_work);
4455ca2d3882d60c040285d0b45df731e11f5da7c64Tomas Winkler	struct mei_me_client *me_cl;
4465ca2d3882d60c040285d0b45df731e11f5da7c64Tomas Winkler	struct mei_client_properties *props;
4479ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
4489ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	mutex_lock(&dev->device_lock);
4499ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
4505ca2d3882d60c040285d0b45df731e11f5da7c64Tomas Winkler	list_for_each_entry(me_cl, &dev->me_clients, list) {
4515ca2d3882d60c040285d0b45df731e11f5da7c64Tomas Winkler		props = &me_cl->props;
4529ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
4535ca2d3882d60c040285d0b45df731e11f5da7c64Tomas Winkler		if (!uuid_le_cmp(props->protocol_name, mei_amthif_guid))
4549ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler			mei_amthif_host_init(dev);
4555ca2d3882d60c040285d0b45df731e11f5da7c64Tomas Winkler		else if (!uuid_le_cmp(props->protocol_name, mei_wd_guid))
4569ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler			mei_wd_host_init(dev);
4575ca2d3882d60c040285d0b45df731e11f5da7c64Tomas Winkler		else if (!uuid_le_cmp(props->protocol_name, mei_nfc_guid))
45859fcd7c63abf0340f551f487264b67ff5f7a0b86Samuel Ortiz			mei_nfc_host_init(dev);
45959fcd7c63abf0340f551f487264b67ff5f7a0b86Samuel Ortiz
4609ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	}
4619ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
4629ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	dev->dev_state = MEI_DEV_ENABLED;
4636adb8efb024a7e413b93b22848fc13395b1a438aTomas Winkler	dev->reset_count = 0;
4649ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
4659ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	mutex_unlock(&dev->device_lock);
46604bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler
4672bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler	pm_runtime_mark_last_busy(dev->dev);
4682bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler	dev_dbg(dev->dev, "rpm: autosuspend\n");
4692bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler	pm_runtime_autosuspend(dev->dev);
4709ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler}
4719ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
4726aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler/**
473a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * mei_hbuf_acquire - try to acquire host buffer
4746aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler *
4756aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler * @dev: the device structure
476a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * Return: true if host buffer was acquired
4776aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler */
4786aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winklerbool mei_hbuf_acquire(struct mei_device *dev)
4796aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler{
48004bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler	if (mei_pg_state(dev) == MEI_PG_ON ||
48104bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler	    dev->pg_event == MEI_PG_EVENT_WAIT) {
4822bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler		dev_dbg(dev->dev, "device is in pg\n");
48304bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler		return false;
48404bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler	}
48504bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler
4866aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler	if (!dev->hbuf_is_ready) {
4872bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler		dev_dbg(dev->dev, "hbuf is not ready\n");
4886aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler		return false;
4896aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler	}
4906aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler
4916aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler	dev->hbuf_is_ready = false;
4926aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler
4936aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler	return true;
4946aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler}
4959ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
4969ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/**
49783ce07411dc2316aaaf95a0f193fa2fd76e2e739Alexander Usyskin * mei_cl_disconnect - disconnect host client from the me one
4989ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
49990e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler * @cl: host client
5009ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
5019ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * Locking: called under "dev->device_lock" lock
5029ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
503a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * Return: 0 on success, <0 on failure.
5049ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */
50590e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winklerint mei_cl_disconnect(struct mei_cl *cl)
5069ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{
50790e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	struct mei_device *dev;
5089ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	struct mei_cl_cb *cb;
509fe2f17eb3da38ac0d5a00c511255bf3a33d16d24Alexander Usyskin	int rets;
5109ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
51190e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	if (WARN_ON(!cl || !cl->dev))
5129ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		return -ENODEV;
5139ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
51490e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	dev = cl->dev;
51590e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler
516c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin	cl_dbg(dev, cl, "disconnecting");
517c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin
5189ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	if (cl->state != MEI_FILE_DISCONNECTING)
5199ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		return 0;
5209ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
5212bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler	rets = pm_runtime_get(dev->dev);
52204bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler	if (rets < 0 && rets != -EINPROGRESS) {
5232bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler		pm_runtime_put_noidle(dev->dev);
52404bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler		cl_err(dev, cl, "rpm: get failed %d\n", rets);
52504bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler		return rets;
52604bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler	}
52704bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler
5289ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	cb = mei_io_cb_init(cl, NULL);
52904bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler	if (!cb) {
53004bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler		rets = -ENOMEM;
53104bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler		goto free;
53204bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler	}
5339ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
5345a8373fba0ab2cec8d206747ad60ca4a30821a37Tomas Winkler	cb->fop_type = MEI_FOP_DISCONNECT;
5355a8373fba0ab2cec8d206747ad60ca4a30821a37Tomas Winkler
5366aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler	if (mei_hbuf_acquire(dev)) {
5379ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		if (mei_hbm_cl_disconnect_req(dev, cl)) {
5389ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler			rets = -ENODEV;
539c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin			cl_err(dev, cl, "failed to disconnect.\n");
5409ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler			goto free;
5419ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		}
54222b987a325701223f9a37db700c6eb20b9924c6fAlexander Usyskin		cl->timer_count = MEI_CONNECT_TIMEOUT;
5439ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		mdelay(10); /* Wait for hardware disconnection ready */
5449ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
5459ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	} else {
546c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin		cl_dbg(dev, cl, "add disconnect cb to control write list\n");
5479ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
5489ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
5499ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	}
5509ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	mutex_unlock(&dev->device_lock);
5519ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
55212f45ed414c8d2eac1a98bf2deaf4117e8c0324fTomas Winkler	wait_event_timeout(cl->wait,
5539ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler			MEI_FILE_DISCONNECTED == cl->state,
5549ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler			mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
5559ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
5569ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	mutex_lock(&dev->device_lock);
557fe2f17eb3da38ac0d5a00c511255bf3a33d16d24Alexander Usyskin
5589ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	if (MEI_FILE_DISCONNECTED == cl->state) {
5599ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		rets = 0;
560c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin		cl_dbg(dev, cl, "successfully disconnected from FW client.\n");
5619ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	} else {
562fe2f17eb3da38ac0d5a00c511255bf3a33d16d24Alexander Usyskin		cl_dbg(dev, cl, "timeout on disconnect from FW client.\n");
563fe2f17eb3da38ac0d5a00c511255bf3a33d16d24Alexander Usyskin		rets = -ETIME;
5649ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	}
5659ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
5669ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	mei_io_list_flush(&dev->ctrl_rd_list, cl);
5679ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	mei_io_list_flush(&dev->ctrl_wr_list, cl);
5689ca9050b3df690d9d44e39424ab2a531120af936Tomas Winklerfree:
56904bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler	cl_dbg(dev, cl, "rpm: autosuspend\n");
5702bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler	pm_runtime_mark_last_busy(dev->dev);
5712bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler	pm_runtime_put_autosuspend(dev->dev);
57204bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler
5739ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	mei_io_cb_free(cb);
5749ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	return rets;
5759ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler}
5769ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
5779ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
5789ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/**
57990e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler * mei_cl_is_other_connecting - checks if other
58090e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler *    client with the same me client id is connecting
5819ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
5829ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * @cl: private data of the file object
5839ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
584a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * Return: true if other client is connected, false - otherwise.
5859ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */
58690e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winklerbool mei_cl_is_other_connecting(struct mei_cl *cl)
5879ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{
58890e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	struct mei_device *dev;
58931f88f5739e966cb3c524083e2d19b423ece3585Tomas Winkler	struct mei_cl *ocl; /* the other client */
5909ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
59190e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	if (WARN_ON(!cl || !cl->dev))
59290e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler		return false;
59390e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler
59490e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	dev = cl->dev;
59590e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler
59631f88f5739e966cb3c524083e2d19b423ece3585Tomas Winkler	list_for_each_entry(ocl, &dev->file_list, link) {
59731f88f5739e966cb3c524083e2d19b423ece3585Tomas Winkler		if (ocl->state == MEI_FILE_CONNECTING &&
59831f88f5739e966cb3c524083e2d19b423ece3585Tomas Winkler		    ocl != cl &&
59931f88f5739e966cb3c524083e2d19b423ece3585Tomas Winkler		    cl->me_client_id == ocl->me_client_id)
60090e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler			return true;
6019ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
6029ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	}
60390e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler
60490e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	return false;
6059ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler}
6069ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
6079ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/**
60883ce07411dc2316aaaf95a0f193fa2fd76e2e739Alexander Usyskin * mei_cl_connect - connect host client to the me one
6099f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler *
6109f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler * @cl: host client
611a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * @file: pointer to file structure
6129f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler *
6139f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler * Locking: called under "dev->device_lock" lock
6149f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler *
615a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * Return: 0 on success, <0 on failure.
6169f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler */
6179f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winklerint mei_cl_connect(struct mei_cl *cl, struct file *file)
6189f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler{
6199f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler	struct mei_device *dev;
6209f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler	struct mei_cl_cb *cb;
6219f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler	int rets;
6229f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler
6239f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler	if (WARN_ON(!cl || !cl->dev))
6249f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler		return -ENODEV;
6259f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler
6269f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler	dev = cl->dev;
6279f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler
6282bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler	rets = pm_runtime_get(dev->dev);
62904bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler	if (rets < 0 && rets != -EINPROGRESS) {
6302bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler		pm_runtime_put_noidle(dev->dev);
63104bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler		cl_err(dev, cl, "rpm: get failed %d\n", rets);
63204bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler		return rets;
63304bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler	}
63404bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler
6359f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler	cb = mei_io_cb_init(cl, file);
6369f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler	if (!cb) {
6379f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler		rets = -ENOMEM;
6389f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler		goto out;
6399f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler	}
6409f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler
64102a7eecc6ee565f5f3af836d56fe25bafcc49c98Tomas Winkler	cb->fop_type = MEI_FOP_CONNECT;
6429f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler
6436aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler	/* run hbuf acquire last so we don't have to undo */
6446aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler	if (!mei_cl_is_other_connecting(cl) && mei_hbuf_acquire(dev)) {
645e4d8270e604c3202131bac607969605ac397b893Alexander Usyskin		cl->state = MEI_FILE_CONNECTING;
6469f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler		if (mei_hbm_cl_connect_req(dev, cl)) {
6479f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler			rets = -ENODEV;
6489f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler			goto out;
6499f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler		}
6509f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler		cl->timer_count = MEI_CONNECT_TIMEOUT;
6519f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler		list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
6529f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler	} else {
65373ab4232388b7a08f17c8d08141ff2099fa0b161Alexander Usyskin		cl->state = MEI_FILE_INITIALIZING;
6549f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler		list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
6559f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler	}
6569f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler
6579f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler	mutex_unlock(&dev->device_lock);
65812f45ed414c8d2eac1a98bf2deaf4117e8c0324fTomas Winkler	wait_event_timeout(cl->wait,
659285e2996655b7bbfb5eb83076a7d7e6f03e2f5c2Alexander Usyskin			(cl->state == MEI_FILE_CONNECTED ||
660285e2996655b7bbfb5eb83076a7d7e6f03e2f5c2Alexander Usyskin			 cl->state == MEI_FILE_DISCONNECTED),
661285e2996655b7bbfb5eb83076a7d7e6f03e2f5c2Alexander Usyskin			mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
6629f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler	mutex_lock(&dev->device_lock);
6639f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler
6649f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler	if (cl->state != MEI_FILE_CONNECTED) {
6653e37ebb7183f0c4eb92a88c60657ac319c01b3e9Alexander Usyskin		cl->state = MEI_FILE_DISCONNECTED;
666285e2996655b7bbfb5eb83076a7d7e6f03e2f5c2Alexander Usyskin		/* something went really wrong */
667285e2996655b7bbfb5eb83076a7d7e6f03e2f5c2Alexander Usyskin		if (!cl->status)
668285e2996655b7bbfb5eb83076a7d7e6f03e2f5c2Alexander Usyskin			cl->status = -EFAULT;
6699f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler
6709f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler		mei_io_list_flush(&dev->ctrl_rd_list, cl);
6719f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler		mei_io_list_flush(&dev->ctrl_wr_list, cl);
6729f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler	}
6739f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler
6749f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler	rets = cl->status;
6759f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler
6769f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winklerout:
67704bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler	cl_dbg(dev, cl, "rpm: autosuspend\n");
6782bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler	pm_runtime_mark_last_busy(dev->dev);
6792bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler	pm_runtime_put_autosuspend(dev->dev);
68004bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler
6819f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler	mei_io_cb_free(cb);
6829f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler	return rets;
6839f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler}
6849f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler
6859f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler/**
68690e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler * mei_cl_flow_ctrl_creds - checks flow_control credits for cl.
6879ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
6889ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * @cl: private data of the file object
6899ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
690a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * Return: 1 if mei_flow_ctrl_creds >0, 0 - otherwise.
6919ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *	-ENOENT if mei_cl is not present
6929ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *	-EINVAL if single_recv_buf == 0
6939ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */
69490e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winklerint mei_cl_flow_ctrl_creds(struct mei_cl *cl)
6959ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{
69690e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	struct mei_device *dev;
69712d0066526f386538de80b4d86d2008461b36674Alexander Usyskin	struct mei_me_client *me_cl;
6989ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
69990e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	if (WARN_ON(!cl || !cl->dev))
70090e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler		return -EINVAL;
70190e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler
70290e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	dev = cl->dev;
70390e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler
7049ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	if (cl->mei_flow_ctrl_creds > 0)
7059ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		return 1;
7069ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
707d320832f64666089a06778782e42fac29abd7bf7Tomas Winkler	me_cl = mei_me_cl_by_id(dev, cl->me_client_id);
708d320832f64666089a06778782e42fac29abd7bf7Tomas Winkler	if (!me_cl) {
70912d0066526f386538de80b4d86d2008461b36674Alexander Usyskin		cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
710d320832f64666089a06778782e42fac29abd7bf7Tomas Winkler		return -ENOENT;
7119ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	}
71212d0066526f386538de80b4d86d2008461b36674Alexander Usyskin
71312d0066526f386538de80b4d86d2008461b36674Alexander Usyskin	if (me_cl->mei_flow_ctrl_creds) {
71412d0066526f386538de80b4d86d2008461b36674Alexander Usyskin		if (WARN_ON(me_cl->props.single_recv_buf == 0))
71512d0066526f386538de80b4d86d2008461b36674Alexander Usyskin			return -EINVAL;
71612d0066526f386538de80b4d86d2008461b36674Alexander Usyskin		return 1;
71712d0066526f386538de80b4d86d2008461b36674Alexander Usyskin	}
71812d0066526f386538de80b4d86d2008461b36674Alexander Usyskin	return 0;
7199ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler}
7209ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
7219ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/**
72290e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler * mei_cl_flow_ctrl_reduce - reduces flow_control.
7239ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
7249ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * @cl: private data of the file object
725393b148f9d0e70cfcb0096985bb0f0742802929eMasanari Iida *
726a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * Return:
7279ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *	0 on success
7289ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *	-ENOENT when me client is not found
7299ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *	-EINVAL when ctrl credits are <= 0
7309ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */
73190e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winklerint mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
7329ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{
73390e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	struct mei_device *dev;
73412d0066526f386538de80b4d86d2008461b36674Alexander Usyskin	struct mei_me_client *me_cl;
7359ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
73690e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	if (WARN_ON(!cl || !cl->dev))
73790e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler		return -EINVAL;
73890e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler
73990e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	dev = cl->dev;
74090e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler
741d320832f64666089a06778782e42fac29abd7bf7Tomas Winkler	me_cl = mei_me_cl_by_id(dev, cl->me_client_id);
742d320832f64666089a06778782e42fac29abd7bf7Tomas Winkler	if (!me_cl) {
74312d0066526f386538de80b4d86d2008461b36674Alexander Usyskin		cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
744d320832f64666089a06778782e42fac29abd7bf7Tomas Winkler		return -ENOENT;
74512d0066526f386538de80b4d86d2008461b36674Alexander Usyskin	}
7469ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
747d320832f64666089a06778782e42fac29abd7bf7Tomas Winkler	if (me_cl->props.single_recv_buf) {
74812d0066526f386538de80b4d86d2008461b36674Alexander Usyskin		if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0))
74912d0066526f386538de80b4d86d2008461b36674Alexander Usyskin			return -EINVAL;
75012d0066526f386538de80b4d86d2008461b36674Alexander Usyskin		me_cl->mei_flow_ctrl_creds--;
75112d0066526f386538de80b4d86d2008461b36674Alexander Usyskin	} else {
75212d0066526f386538de80b4d86d2008461b36674Alexander Usyskin		if (WARN_ON(cl->mei_flow_ctrl_creds <= 0))
75312d0066526f386538de80b4d86d2008461b36674Alexander Usyskin			return -EINVAL;
75412d0066526f386538de80b4d86d2008461b36674Alexander Usyskin		cl->mei_flow_ctrl_creds--;
7559ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	}
75612d0066526f386538de80b4d86d2008461b36674Alexander Usyskin	return 0;
7579ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler}
7589ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
7599ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/**
760393b148f9d0e70cfcb0096985bb0f0742802929eMasanari Iida * mei_cl_read_start - the start read client message function.
7619ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
76290e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler * @cl: host client
763ce23139c6c2ee92d5eace20f6f10d716cf295a5bAlexander Usyskin * @length: number of bytes to read
7649ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
765a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * Return: 0 on success, <0 on failure.
7669ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */
767fcb136e1ac5774909e0d85189f721b8dfa800e0fTomas Winklerint mei_cl_read_start(struct mei_cl *cl, size_t length)
7689ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{
76990e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	struct mei_device *dev;
7709ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	struct mei_cl_cb *cb;
771d320832f64666089a06778782e42fac29abd7bf7Tomas Winkler	struct mei_me_client *me_cl;
7729ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	int rets;
7739ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
77490e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	if (WARN_ON(!cl || !cl->dev))
77590e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler		return -ENODEV;
77690e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler
77790e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	dev = cl->dev;
77890e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler
779b950ac1dabfcbf97b99f26fa75f86087e1960aefTomas Winkler	if (!mei_cl_is_connected(cl))
7809ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		return -ENODEV;
7819ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
782d91aaed30a938c5daae2641e6758dfab8727862eTomas Winkler	if (cl->read_cb) {
783c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin		cl_dbg(dev, cl, "read is pending.\n");
7849ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		return -EBUSY;
7859ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	}
786d880f3294d0576e79dfab4e2cd5a2eb62fe188f0Tomas Winkler	me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
787d320832f64666089a06778782e42fac29abd7bf7Tomas Winkler	if (!me_cl) {
788c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin		cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
7897ca96aa278f8b9983184e318b06a0ed9ad0297b8Alexander Usyskin		return  -ENOTTY;
7909ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	}
7919ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
7922bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler	rets = pm_runtime_get(dev->dev);
79304bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler	if (rets < 0 && rets != -EINPROGRESS) {
7942bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler		pm_runtime_put_noidle(dev->dev);
79504bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler		cl_err(dev, cl, "rpm: get failed %d\n", rets);
79604bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler		return rets;
79704bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler	}
79804bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler
7999ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	cb = mei_io_cb_init(cl, NULL);
80004bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler	if (!cb) {
80104bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler		rets = -ENOMEM;
80204bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler		goto out;
80304bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler	}
8049ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
805fcb136e1ac5774909e0d85189f721b8dfa800e0fTomas Winkler	/* always allocate at least client max message */
806d320832f64666089a06778782e42fac29abd7bf7Tomas Winkler	length = max_t(size_t, length, me_cl->props.max_msg_length);
807fcb136e1ac5774909e0d85189f721b8dfa800e0fTomas Winkler	rets = mei_io_cb_alloc_resp_buf(cb, length);
8089ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	if (rets)
80904bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler		goto out;
8109ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
8119ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	cb->fop_type = MEI_FOP_READ;
8126aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler	if (mei_hbuf_acquire(dev)) {
81386113500c060bccb0f08bdcadcecc0bd267fd25aAlexander Usyskin		rets = mei_hbm_cl_flow_control_req(dev, cl);
81486113500c060bccb0f08bdcadcecc0bd267fd25aAlexander Usyskin		if (rets < 0)
81504bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler			goto out;
81604bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler
8179ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		list_add_tail(&cb->list, &dev->read_list.list);
8189ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	} else {
8199ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
8209ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	}
821accb884b32e82f943340688c9cd30290531e73e0Chao Bi
822accb884b32e82f943340688c9cd30290531e73e0Chao Bi	cl->read_cb = cb;
823accb884b32e82f943340688c9cd30290531e73e0Chao Bi
82404bb139a071fef549892718f8965a7c61b1924e0Tomas Winklerout:
82504bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler	cl_dbg(dev, cl, "rpm: autosuspend\n");
8262bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler	pm_runtime_mark_last_busy(dev->dev);
8272bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler	pm_runtime_put_autosuspend(dev->dev);
82804bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler
82904bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler	if (rets)
83004bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler		mei_io_cb_free(cb);
83104bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler
8329ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	return rets;
8339ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler}
8349ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
835074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler/**
8369d098192c3d45ab6dd90ae87d649950a9ef70ccbTomas Winkler * mei_cl_irq_write - write a message to device
83721767546e955c3c1705387ca4548db812382fe08Tomas Winkler *	from the interrupt thread context
83821767546e955c3c1705387ca4548db812382fe08Tomas Winkler *
83921767546e955c3c1705387ca4548db812382fe08Tomas Winkler * @cl: client
84021767546e955c3c1705387ca4548db812382fe08Tomas Winkler * @cb: callback block.
84121767546e955c3c1705387ca4548db812382fe08Tomas Winkler * @cmpl_list: complete list.
84221767546e955c3c1705387ca4548db812382fe08Tomas Winkler *
843a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * Return: 0, OK; otherwise error.
84421767546e955c3c1705387ca4548db812382fe08Tomas Winkler */
8459d098192c3d45ab6dd90ae87d649950a9ef70ccbTomas Winklerint mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
8469d098192c3d45ab6dd90ae87d649950a9ef70ccbTomas Winkler		     struct mei_cl_cb *cmpl_list)
84721767546e955c3c1705387ca4548db812382fe08Tomas Winkler{
848136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler	struct mei_device *dev;
849136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler	struct mei_msg_data *buf;
85021767546e955c3c1705387ca4548db812382fe08Tomas Winkler	struct mei_msg_hdr mei_hdr;
851136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler	size_t len;
852136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler	u32 msg_slots;
8539d098192c3d45ab6dd90ae87d649950a9ef70ccbTomas Winkler	int slots;
8542ebf8c94d431078d93599ba56efa58bf850078a1Tomas Winkler	int rets;
85521767546e955c3c1705387ca4548db812382fe08Tomas Winkler
856136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler	if (WARN_ON(!cl || !cl->dev))
857136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler		return -ENODEV;
858136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler
859136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler	dev = cl->dev;
860136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler
861136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler	buf = &cb->request_buffer;
862136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler
863136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler	rets = mei_cl_flow_ctrl_creds(cl);
864136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler	if (rets < 0)
865136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler		return rets;
866136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler
867136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler	if (rets == 0) {
86804bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler		cl_dbg(dev, cl, "No flow control credentials: not sending.\n");
869136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler		return 0;
870136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler	}
871136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler
8729d098192c3d45ab6dd90ae87d649950a9ef70ccbTomas Winkler	slots = mei_hbuf_empty_slots(dev);
873136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler	len = buf->size - cb->buf_idx;
874136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler	msg_slots = mei_data2slots(len);
875136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler
87621767546e955c3c1705387ca4548db812382fe08Tomas Winkler	mei_hdr.host_addr = cl->host_client_id;
87721767546e955c3c1705387ca4548db812382fe08Tomas Winkler	mei_hdr.me_addr = cl->me_client_id;
87821767546e955c3c1705387ca4548db812382fe08Tomas Winkler	mei_hdr.reserved = 0;
879479327fc42737234a1f76f20010334c99110d256Tomas Winkler	mei_hdr.internal = cb->internal;
88021767546e955c3c1705387ca4548db812382fe08Tomas Winkler
8819d098192c3d45ab6dd90ae87d649950a9ef70ccbTomas Winkler	if (slots >= msg_slots) {
88221767546e955c3c1705387ca4548db812382fe08Tomas Winkler		mei_hdr.length = len;
88321767546e955c3c1705387ca4548db812382fe08Tomas Winkler		mei_hdr.msg_complete = 1;
88421767546e955c3c1705387ca4548db812382fe08Tomas Winkler	/* Split the message only if we can write the whole host buffer */
8859d098192c3d45ab6dd90ae87d649950a9ef70ccbTomas Winkler	} else if (slots == dev->hbuf_depth) {
8869d098192c3d45ab6dd90ae87d649950a9ef70ccbTomas Winkler		msg_slots = slots;
8879d098192c3d45ab6dd90ae87d649950a9ef70ccbTomas Winkler		len = (slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
88821767546e955c3c1705387ca4548db812382fe08Tomas Winkler		mei_hdr.length = len;
88921767546e955c3c1705387ca4548db812382fe08Tomas Winkler		mei_hdr.msg_complete = 0;
89021767546e955c3c1705387ca4548db812382fe08Tomas Winkler	} else {
89121767546e955c3c1705387ca4548db812382fe08Tomas Winkler		/* wait for next time the host buffer is empty */
89221767546e955c3c1705387ca4548db812382fe08Tomas Winkler		return 0;
89321767546e955c3c1705387ca4548db812382fe08Tomas Winkler	}
89421767546e955c3c1705387ca4548db812382fe08Tomas Winkler
895c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin	cl_dbg(dev, cl, "buf: size = %d idx = %lu\n",
89621767546e955c3c1705387ca4548db812382fe08Tomas Winkler			cb->request_buffer.size, cb->buf_idx);
89721767546e955c3c1705387ca4548db812382fe08Tomas Winkler
898136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler	rets = mei_write_message(dev, &mei_hdr, buf->data + cb->buf_idx);
8992ebf8c94d431078d93599ba56efa58bf850078a1Tomas Winkler	if (rets) {
9002ebf8c94d431078d93599ba56efa58bf850078a1Tomas Winkler		cl->status = rets;
90121767546e955c3c1705387ca4548db812382fe08Tomas Winkler		list_move_tail(&cb->list, &cmpl_list->list);
9022ebf8c94d431078d93599ba56efa58bf850078a1Tomas Winkler		return rets;
90321767546e955c3c1705387ca4548db812382fe08Tomas Winkler	}
90421767546e955c3c1705387ca4548db812382fe08Tomas Winkler
90521767546e955c3c1705387ca4548db812382fe08Tomas Winkler	cl->status = 0;
9064dfaa9f7020b1ff4bf87899f4797d2efd76e80fdTomas Winkler	cl->writing_state = MEI_WRITING;
90721767546e955c3c1705387ca4548db812382fe08Tomas Winkler	cb->buf_idx += mei_hdr.length;
9084dfaa9f7020b1ff4bf87899f4797d2efd76e80fdTomas Winkler
90921767546e955c3c1705387ca4548db812382fe08Tomas Winkler	if (mei_hdr.msg_complete) {
91021767546e955c3c1705387ca4548db812382fe08Tomas Winkler		if (mei_cl_flow_ctrl_reduce(cl))
9112ebf8c94d431078d93599ba56efa58bf850078a1Tomas Winkler			return -EIO;
91221767546e955c3c1705387ca4548db812382fe08Tomas Winkler		list_move_tail(&cb->list, &dev->write_waiting_list.list);
91321767546e955c3c1705387ca4548db812382fe08Tomas Winkler	}
91421767546e955c3c1705387ca4548db812382fe08Tomas Winkler
91521767546e955c3c1705387ca4548db812382fe08Tomas Winkler	return 0;
91621767546e955c3c1705387ca4548db812382fe08Tomas Winkler}
91721767546e955c3c1705387ca4548db812382fe08Tomas Winkler
91821767546e955c3c1705387ca4548db812382fe08Tomas Winkler/**
9194234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler * mei_cl_write - submit a write cb to mei device
920a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin *	assumes device_lock is locked
9214234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler *
9224234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler * @cl: host client
923a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * @cb: write callback with filled data
924ce23139c6c2ee92d5eace20f6f10d716cf295a5bAlexander Usyskin * @blocking: block until completed
9254234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler *
926a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * Return: number of bytes sent on success, <0 on failure.
9274234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler */
9284234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winklerint mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
9294234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler{
9304234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	struct mei_device *dev;
9314234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	struct mei_msg_data *buf;
9324234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	struct mei_msg_hdr mei_hdr;
9334234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	int rets;
9344234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler
9354234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler
9364234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	if (WARN_ON(!cl || !cl->dev))
9374234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler		return -ENODEV;
9384234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler
9394234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	if (WARN_ON(!cb))
9404234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler		return -EINVAL;
9414234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler
9424234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	dev = cl->dev;
9434234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler
9444234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler
9454234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	buf = &cb->request_buffer;
9464234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler
9470a01e97432a6ee5c5b78c0425dd7518a80f87b54Alexander Usyskin	cl_dbg(dev, cl, "size=%d\n", buf->size);
9484234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler
9492bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler	rets = pm_runtime_get(dev->dev);
95004bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler	if (rets < 0 && rets != -EINPROGRESS) {
9512bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler		pm_runtime_put_noidle(dev->dev);
95204bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler		cl_err(dev, cl, "rpm: get failed %d\n", rets);
95304bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler		return rets;
95404bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler	}
9554234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler
9564234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	cb->fop_type = MEI_FOP_WRITE;
9576aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler	cb->buf_idx = 0;
9586aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler	cl->writing_state = MEI_IDLE;
9596aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler
9606aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler	mei_hdr.host_addr = cl->host_client_id;
9616aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler	mei_hdr.me_addr = cl->me_client_id;
9626aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler	mei_hdr.reserved = 0;
9636aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler	mei_hdr.msg_complete = 0;
9646aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler	mei_hdr.internal = cb->internal;
9654234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler
9664234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	rets = mei_cl_flow_ctrl_creds(cl);
9674234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	if (rets < 0)
9684234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler		goto err;
9694234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler
9706aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler	if (rets == 0) {
9716aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler		cl_dbg(dev, cl, "No flow control credentials: not sending.\n");
9726aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler		rets = buf->size;
9736aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler		goto out;
9746aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler	}
9756aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler	if (!mei_hbuf_acquire(dev)) {
9766aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler		cl_dbg(dev, cl, "Cannot acquire the host buffer: not sending.\n");
9774234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler		rets = buf->size;
9784234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler		goto out;
9794234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	}
9804234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler
9814234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	/* Check for a maximum length */
9824234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	if (buf->size > mei_hbuf_max_len(dev)) {
9834234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler		mei_hdr.length = mei_hbuf_max_len(dev);
9844234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler		mei_hdr.msg_complete = 0;
9854234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	} else {
9864234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler		mei_hdr.length = buf->size;
9874234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler		mei_hdr.msg_complete = 1;
9884234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	}
9894234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler
9902ebf8c94d431078d93599ba56efa58bf850078a1Tomas Winkler	rets = mei_write_message(dev, &mei_hdr, buf->data);
9912ebf8c94d431078d93599ba56efa58bf850078a1Tomas Winkler	if (rets)
9924234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler		goto err;
9934234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler
9944234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	cl->writing_state = MEI_WRITING;
9954234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	cb->buf_idx = mei_hdr.length;
9964234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler
9974234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winklerout:
9984234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	if (mei_hdr.msg_complete) {
9997ca96aa278f8b9983184e318b06a0ed9ad0297b8Alexander Usyskin		rets = mei_cl_flow_ctrl_reduce(cl);
10007ca96aa278f8b9983184e318b06a0ed9ad0297b8Alexander Usyskin		if (rets < 0)
10014234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler			goto err;
10027ca96aa278f8b9983184e318b06a0ed9ad0297b8Alexander Usyskin
10034234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler		list_add_tail(&cb->list, &dev->write_waiting_list.list);
10044234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	} else {
10054234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler		list_add_tail(&cb->list, &dev->write_list.list);
10064234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	}
10074234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler
10084234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler
10094234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	if (blocking && cl->writing_state != MEI_WRITE_COMPLETE) {
10104234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler
10114234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler		mutex_unlock(&dev->device_lock);
10127ca96aa278f8b9983184e318b06a0ed9ad0297b8Alexander Usyskin		rets = wait_event_interruptible(cl->tx_wait,
10137ca96aa278f8b9983184e318b06a0ed9ad0297b8Alexander Usyskin				cl->writing_state == MEI_WRITE_COMPLETE);
10144234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler		mutex_lock(&dev->device_lock);
10157ca96aa278f8b9983184e318b06a0ed9ad0297b8Alexander Usyskin		/* wait_event_interruptible returns -ERESTARTSYS */
10167ca96aa278f8b9983184e318b06a0ed9ad0297b8Alexander Usyskin		if (rets) {
10177ca96aa278f8b9983184e318b06a0ed9ad0297b8Alexander Usyskin			if (signal_pending(current))
10187ca96aa278f8b9983184e318b06a0ed9ad0297b8Alexander Usyskin				rets = -EINTR;
10197ca96aa278f8b9983184e318b06a0ed9ad0297b8Alexander Usyskin			goto err;
10207ca96aa278f8b9983184e318b06a0ed9ad0297b8Alexander Usyskin		}
10214234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	}
10227ca96aa278f8b9983184e318b06a0ed9ad0297b8Alexander Usyskin
10237ca96aa278f8b9983184e318b06a0ed9ad0297b8Alexander Usyskin	rets = buf->size;
10244234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winklererr:
102504bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler	cl_dbg(dev, cl, "rpm: autosuspend\n");
10262bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler	pm_runtime_mark_last_busy(dev->dev);
10272bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler	pm_runtime_put_autosuspend(dev->dev);
102804bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler
10294234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	return rets;
10304234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler}
10314234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler
10324234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler
1033db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler/**
1034db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler * mei_cl_complete - processes completed operation for a client
1035db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler *
1036db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler * @cl: private data of the file object.
1037db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler * @cb: callback block.
1038db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler */
1039db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winklervoid mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
1040db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler{
1041db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler	if (cb->fop_type == MEI_FOP_WRITE) {
1042db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler		mei_io_cb_free(cb);
1043db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler		cb = NULL;
1044db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler		cl->writing_state = MEI_WRITE_COMPLETE;
1045db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler		if (waitqueue_active(&cl->tx_wait))
1046db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler			wake_up_interruptible(&cl->tx_wait);
1047db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler
1048db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler	} else if (cb->fop_type == MEI_FOP_READ &&
1049db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler			MEI_READING == cl->reading_state) {
1050db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler		cl->reading_state = MEI_READ_COMPLETE;
1051db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler		if (waitqueue_active(&cl->rx_wait))
1052db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler			wake_up_interruptible(&cl->rx_wait);
1053db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler		else
1054db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler			mei_cl_bus_rx_event(cl);
1055db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler
1056db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler	}
1057db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler}
1058db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler
10594234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler
10604234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler/**
1061074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler * mei_cl_all_disconnect - disconnect forcefully all connected clients
1062074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler *
1063a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * @dev: mei device
1064074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler */
1065074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler
1066074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winklervoid mei_cl_all_disconnect(struct mei_device *dev)
1067074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler{
106831f88f5739e966cb3c524083e2d19b423ece3585Tomas Winkler	struct mei_cl *cl;
1069074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler
107031f88f5739e966cb3c524083e2d19b423ece3585Tomas Winkler	list_for_each_entry(cl, &dev->file_list, link) {
1071074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler		cl->state = MEI_FILE_DISCONNECTED;
1072074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler		cl->mei_flow_ctrl_creds = 0;
1073074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler		cl->timer_count = 0;
1074074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler	}
1075074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler}
1076074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler
1077074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler
1078074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler/**
10795290801c23231c8e192943d3beb01fdbeb536395Tomas Winkler * mei_cl_all_wakeup  - wake up all readers and writers they can be interrupted
1080074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler *
1081a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * @dev: mei device
1082074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler */
10835290801c23231c8e192943d3beb01fdbeb536395Tomas Winklervoid mei_cl_all_wakeup(struct mei_device *dev)
1084074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler{
108531f88f5739e966cb3c524083e2d19b423ece3585Tomas Winkler	struct mei_cl *cl;
108692db1555f3b9c9be257ef4070d87eb9410493cf3Tomas Winkler
108731f88f5739e966cb3c524083e2d19b423ece3585Tomas Winkler	list_for_each_entry(cl, &dev->file_list, link) {
1088074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler		if (waitqueue_active(&cl->rx_wait)) {
1089c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin			cl_dbg(dev, cl, "Waking up reading client!\n");
1090074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler			wake_up_interruptible(&cl->rx_wait);
1091074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler		}
10925290801c23231c8e192943d3beb01fdbeb536395Tomas Winkler		if (waitqueue_active(&cl->tx_wait)) {
1093c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin			cl_dbg(dev, cl, "Waking up writing client!\n");
10945290801c23231c8e192943d3beb01fdbeb536395Tomas Winkler			wake_up_interruptible(&cl->tx_wait);
10955290801c23231c8e192943d3beb01fdbeb536395Tomas Winkler		}
1096074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler	}
1097074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler}
1098074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler
1099074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler/**
1100074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler * mei_cl_all_write_clear - clear all pending writes
1101a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin *
1102a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * @dev: mei device
1103074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler */
1104074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winklervoid mei_cl_all_write_clear(struct mei_device *dev)
1105074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler{
1106cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler	mei_io_list_free(&dev->write_list, NULL);
1107cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler	mei_io_list_free(&dev->write_waiting_list, NULL);
1108074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler}
1109074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler
1110074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler
1111