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