client.c revision 5456796b1a2aedd2d6345944b73ac41aeb8cb589
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/pci.h> 189ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler#include <linux/sched.h> 199ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler#include <linux/wait.h> 209ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler#include <linux/delay.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/** 3090e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler * mei_me_cl_by_uuid - locate index of me client 3190e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler * 3290e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler * @dev: mei device 33a27a76d3c07de08a0d0d298b6bc280c5b820e997Alexander Usyskin * 34a27a76d3c07de08a0d0d298b6bc280c5b820e997Alexander Usyskin * Locking: called under "dev->device_lock" lock 35a27a76d3c07de08a0d0d298b6bc280c5b820e997Alexander Usyskin * 3690e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler * returns me client index or -ENOENT if not found 3790e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler */ 3890e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winklerint mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *uuid) 3990e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler{ 40a27a76d3c07de08a0d0d298b6bc280c5b820e997Alexander Usyskin int i; 4190e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler 4290e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler for (i = 0; i < dev->me_clients_num; ++i) 4390e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler if (uuid_le_cmp(*uuid, 44a27a76d3c07de08a0d0d298b6bc280c5b820e997Alexander Usyskin dev->me_clients[i].props.protocol_name) == 0) 45a27a76d3c07de08a0d0d298b6bc280c5b820e997Alexander Usyskin return i; 4690e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler 47a27a76d3c07de08a0d0d298b6bc280c5b820e997Alexander Usyskin return -ENOENT; 4890e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler} 4990e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler 5090e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler 5190e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler/** 5290e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler * mei_me_cl_by_id return index to me_clients for 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 * 5990e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler * returns index on success, -ENOENT on failure. 6090e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler */ 6190e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler 6290e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winklerint mei_me_cl_by_id(struct mei_device *dev, u8 client_id) 6390e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler{ 6490e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler int i; 65a27a76d3c07de08a0d0d298b6bc280c5b820e997Alexander Usyskin 6690e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler for (i = 0; i < dev->me_clients_num; i++) 6790e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler if (dev->me_clients[i].client_id == client_id) 68a27a76d3c07de08a0d0d298b6bc280c5b820e997Alexander Usyskin return i; 6990e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler 70a27a76d3c07de08a0d0d298b6bc280c5b820e997Alexander Usyskin return -ENOENT; 7190e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler} 729ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 739ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 749ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/** 75cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * mei_cl_cmp_id - tells if the clients are the same 769ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * 77cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * @cl1: host client 1 78cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * @cl2: host client 2 79cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * 80cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * returns true - if the clients has same host and me ids 81cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * false - otherwise 82cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler */ 83cc99ecfdac01215594c73907726b12f251c21e20Tomas Winklerstatic inline bool mei_cl_cmp_id(const struct mei_cl *cl1, 84cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler const struct mei_cl *cl2) 85cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler{ 86cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler return cl1 && cl2 && 87cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler (cl1->host_client_id == cl2->host_client_id) && 88cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler (cl1->me_client_id == cl2->me_client_id); 89cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler} 90cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler 91cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler/** 92cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * mei_io_list_flush - removes cbs belonging to cl. 93cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * 94cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * @list: an instance of our list structure 95cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * @cl: host client, can be NULL for flushing the whole list 96cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * @free: whether to free the cbs 979ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */ 98cc99ecfdac01215594c73907726b12f251c21e20Tomas Winklerstatic void __mei_io_list_flush(struct mei_cl_cb *list, 99cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler struct mei_cl *cl, bool free) 1009ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{ 1019ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler struct mei_cl_cb *cb; 1029ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler struct mei_cl_cb *next; 1039ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 104cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler /* enable removing everything if no cl is specified */ 1059ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler list_for_each_entry_safe(cb, next, &list->list, list) { 106cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler if (!cl || (cb->cl && mei_cl_cmp_id(cl, cb->cl))) { 1079ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler list_del(&cb->list); 108cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler if (free) 109cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler mei_io_cb_free(cb); 110cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler } 1119ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler } 1129ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler} 1139ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 1149ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/** 115cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * mei_io_list_flush - removes list entry belonging to cl. 116cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * 117cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * @list: An instance of our list structure 118cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * @cl: host client 119cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler */ 1205456796b1a2aedd2d6345944b73ac41aeb8cb589Alexander Usyskinvoid mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl) 121cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler{ 122cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler __mei_io_list_flush(list, cl, false); 123cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler} 124cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler 125cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler 126cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler/** 127cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * mei_io_list_free - removes cb belonging to cl and free them 128cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * 129cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * @list: An instance of our list structure 130cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * @cl: host client 131cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler */ 132cc99ecfdac01215594c73907726b12f251c21e20Tomas Winklerstatic inline void mei_io_list_free(struct mei_cl_cb *list, struct mei_cl *cl) 133cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler{ 134cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler __mei_io_list_flush(list, cl, true); 135cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler} 136cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler 137cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler/** 1389ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * mei_io_cb_free - free mei_cb_private related memory 1399ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * 1409ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * @cb: mei callback struct 1419ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */ 1429ca9050b3df690d9d44e39424ab2a531120af936Tomas Winklervoid mei_io_cb_free(struct mei_cl_cb *cb) 1439ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{ 1449ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler if (cb == NULL) 1459ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler return; 1469ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 1479ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler kfree(cb->request_buffer.data); 1489ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler kfree(cb->response_buffer.data); 1499ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler kfree(cb); 1509ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler} 1519ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 1529ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/** 1539ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * mei_io_cb_init - allocate and initialize io callback 1549ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * 1559ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * @cl - mei client 156393b148f9d0e70cfcb0096985bb0f0742802929eMasanari Iida * @fp: pointer to file structure 1579ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * 1589ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * returns mei_cl_cb pointer or NULL; 1599ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */ 1609ca9050b3df690d9d44e39424ab2a531120af936Tomas Winklerstruct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp) 1619ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{ 1629ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler struct mei_cl_cb *cb; 1639ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 1649ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL); 1659ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler if (!cb) 1669ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler return NULL; 1679ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 1689ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler mei_io_list_init(cb); 1699ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 1709ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler cb->file_object = fp; 1719ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler cb->cl = cl; 1729ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler cb->buf_idx = 0; 1739ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler return cb; 1749ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler} 1759ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 1769ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/** 1779ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * mei_io_cb_alloc_req_buf - allocate request buffer 1789ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * 179393b148f9d0e70cfcb0096985bb0f0742802929eMasanari Iida * @cb: io callback structure 180393b148f9d0e70cfcb0096985bb0f0742802929eMasanari Iida * @length: size of the buffer 1819ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * 1829ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * returns 0 on success 1839ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * -EINVAL if cb is NULL 1849ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * -ENOMEM if allocation failed 1859ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */ 1869ca9050b3df690d9d44e39424ab2a531120af936Tomas Winklerint mei_io_cb_alloc_req_buf(struct mei_cl_cb *cb, size_t length) 1879ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{ 1889ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler if (!cb) 1899ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler return -EINVAL; 1909ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 1919ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler if (length == 0) 1929ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler return 0; 1939ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 1949ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler cb->request_buffer.data = kmalloc(length, GFP_KERNEL); 1959ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler if (!cb->request_buffer.data) 1969ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler return -ENOMEM; 1979ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler cb->request_buffer.size = length; 1989ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler return 0; 1999ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler} 2009ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/** 20183ce07411dc2316aaaf95a0f193fa2fd76e2e739Alexander Usyskin * mei_io_cb_alloc_resp_buf - allocate response buffer 2029ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * 203393b148f9d0e70cfcb0096985bb0f0742802929eMasanari Iida * @cb: io callback structure 204393b148f9d0e70cfcb0096985bb0f0742802929eMasanari Iida * @length: size of the buffer 2059ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * 2069ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * returns 0 on success 2079ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * -EINVAL if cb is NULL 2089ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * -ENOMEM if allocation failed 2099ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */ 2109ca9050b3df690d9d44e39424ab2a531120af936Tomas Winklerint mei_io_cb_alloc_resp_buf(struct mei_cl_cb *cb, size_t length) 2119ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{ 2129ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler if (!cb) 2139ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler return -EINVAL; 2149ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 2159ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler if (length == 0) 2169ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler return 0; 2179ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 2189ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler cb->response_buffer.data = kmalloc(length, GFP_KERNEL); 2199ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler if (!cb->response_buffer.data) 2209ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler return -ENOMEM; 2219ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler cb->response_buffer.size = length; 2229ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler return 0; 2239ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler} 2249ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 2259ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 2269ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 2279ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/** 2289ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * mei_cl_flush_queues - flushes queue lists belonging to cl. 2299ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * 2309ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * @cl: host client 2319ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */ 2329ca9050b3df690d9d44e39424ab2a531120af936Tomas Winklerint mei_cl_flush_queues(struct mei_cl *cl) 2339ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{ 234c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin struct mei_device *dev; 235c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin 23690e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler if (WARN_ON(!cl || !cl->dev)) 2379ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler return -EINVAL; 2389ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 239c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin dev = cl->dev; 240c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin 241c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin cl_dbg(dev, cl, "remove list entry belonging to cl\n"); 2429ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler mei_io_list_flush(&cl->dev->read_list, cl); 243cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler mei_io_list_free(&cl->dev->write_list, cl); 244cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler mei_io_list_free(&cl->dev->write_waiting_list, cl); 2459ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler mei_io_list_flush(&cl->dev->ctrl_wr_list, cl); 2469ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler mei_io_list_flush(&cl->dev->ctrl_rd_list, cl); 2479ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler mei_io_list_flush(&cl->dev->amthif_cmd_list, cl); 2489ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler mei_io_list_flush(&cl->dev->amthif_rd_complete_list, cl); 2499ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler return 0; 2509ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler} 2519ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 2529ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 2539ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/** 25483ce07411dc2316aaaf95a0f193fa2fd76e2e739Alexander Usyskin * mei_cl_init - initializes cl. 2559ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * 2569ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * @cl: host client to be initialized 2579ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * @dev: mei device 2589ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */ 2599ca9050b3df690d9d44e39424ab2a531120af936Tomas Winklervoid mei_cl_init(struct mei_cl *cl, struct mei_device *dev) 2609ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{ 2619ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler memset(cl, 0, sizeof(struct mei_cl)); 2629ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler init_waitqueue_head(&cl->wait); 2639ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler init_waitqueue_head(&cl->rx_wait); 2649ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler init_waitqueue_head(&cl->tx_wait); 2659ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler INIT_LIST_HEAD(&cl->link); 266a7b71bc043aded9da4cf51f85271e0779161fe22Samuel Ortiz INIT_LIST_HEAD(&cl->device_link); 2679ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler cl->reading_state = MEI_IDLE; 2689ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler cl->writing_state = MEI_IDLE; 2699ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler cl->dev = dev; 2709ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler} 2719ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 2729ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/** 2739ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * mei_cl_allocate - allocates cl structure and sets it up. 2749ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * 2759ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * @dev: mei device 2769ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * returns The allocated file or NULL on failure 2779ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */ 2789ca9050b3df690d9d44e39424ab2a531120af936Tomas Winklerstruct mei_cl *mei_cl_allocate(struct mei_device *dev) 2799ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{ 2809ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler struct mei_cl *cl; 2819ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 2829ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler cl = kmalloc(sizeof(struct mei_cl), GFP_KERNEL); 2839ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler if (!cl) 2849ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler return NULL; 2859ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 2869ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler mei_cl_init(cl, dev); 2879ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 2889ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler return cl; 2899ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler} 2909ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 29190e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler/** 29290e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler * mei_cl_find_read_cb - find this cl's callback in the read list 29390e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler * 294393b148f9d0e70cfcb0096985bb0f0742802929eMasanari Iida * @cl: host client 295393b148f9d0e70cfcb0096985bb0f0742802929eMasanari Iida * 29690e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler * returns cb on success, NULL on error 29790e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler */ 29890e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winklerstruct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl) 29990e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler{ 30090e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler struct mei_device *dev = cl->dev; 30131f88f5739e966cb3c524083e2d19b423ece3585Tomas Winkler struct mei_cl_cb *cb; 30290e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler 30331f88f5739e966cb3c524083e2d19b423ece3585Tomas Winkler list_for_each_entry(cb, &dev->read_list.list, list) 30490e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler if (mei_cl_cmp_id(cl, cb->cl)) 30590e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler return cb; 30690e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler return NULL; 30790e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler} 30890e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler 30983ce07411dc2316aaaf95a0f193fa2fd76e2e739Alexander Usyskin/** mei_cl_link: allocate host id in the host map 3109ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * 311781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler * @cl - host client 31283ce07411dc2316aaaf95a0f193fa2fd76e2e739Alexander Usyskin * @id - fixed host id or -1 for generic one 313393b148f9d0e70cfcb0096985bb0f0742802929eMasanari Iida * 314781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler * returns 0 on success 3159ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * -EINVAL on incorrect values 3169ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * -ENONET if client not found 3179ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */ 318781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winklerint mei_cl_link(struct mei_cl *cl, int id) 3199ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{ 32090e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler struct mei_device *dev; 32122f96a0eb6c62b570621d77dacbf2589a6de2997Tomas Winkler long open_handle_count; 3229ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 323781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler if (WARN_ON(!cl || !cl->dev)) 3249ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler return -EINVAL; 3259ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 32690e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler dev = cl->dev; 32790e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler 32883ce07411dc2316aaaf95a0f193fa2fd76e2e739Alexander Usyskin /* If Id is not assigned get one*/ 329781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler if (id == MEI_HOST_CLIENT_ID_ANY) 330781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler id = find_first_zero_bit(dev->host_clients_map, 331781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler MEI_CLIENTS_MAX); 3329ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 333781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler if (id >= MEI_CLIENTS_MAX) { 33483ce07411dc2316aaaf95a0f193fa2fd76e2e739Alexander Usyskin dev_err(&dev->pdev->dev, "id exceeded %d", MEI_CLIENTS_MAX); 335e036cc5727eb6d471442d2a9218990aa11215400Tomas Winkler return -EMFILE; 336e036cc5727eb6d471442d2a9218990aa11215400Tomas Winkler } 337e036cc5727eb6d471442d2a9218990aa11215400Tomas Winkler 33822f96a0eb6c62b570621d77dacbf2589a6de2997Tomas Winkler open_handle_count = dev->open_handle_count + dev->iamthif_open_count; 33922f96a0eb6c62b570621d77dacbf2589a6de2997Tomas Winkler if (open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) { 34083ce07411dc2316aaaf95a0f193fa2fd76e2e739Alexander Usyskin dev_err(&dev->pdev->dev, "open_handle_count exceeded %d", 341e036cc5727eb6d471442d2a9218990aa11215400Tomas Winkler MEI_MAX_OPEN_HANDLE_COUNT); 342e036cc5727eb6d471442d2a9218990aa11215400Tomas Winkler return -EMFILE; 3439ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler } 3449ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 345781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler dev->open_handle_count++; 346781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler 347781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler cl->host_client_id = id; 348781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler list_add_tail(&cl->link, &dev->file_list); 349781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler 350781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler set_bit(id, dev->host_clients_map); 351781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler 352781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler cl->state = MEI_FILE_INITIALIZING; 353781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler 354c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin cl_dbg(dev, cl, "link cl\n"); 355781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler return 0; 3569ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler} 357781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler 3589ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/** 35990e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler * mei_cl_unlink - remove me_cl from the list 3609ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * 361393b148f9d0e70cfcb0096985bb0f0742802929eMasanari Iida * @cl: host client 3629ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */ 36390e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winklerint mei_cl_unlink(struct mei_cl *cl) 3649ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{ 36590e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler struct mei_device *dev; 36690e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler 367781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler /* don't shout on error exit path */ 368781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler if (!cl) 369781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler return 0; 370781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler 3718e9a4a9a5c8e8765417d54ed6917c7e1e4d09f4dTomas Winkler /* wd and amthif might not be initialized */ 3728e9a4a9a5c8e8765417d54ed6917c7e1e4d09f4dTomas Winkler if (!cl->dev) 3738e9a4a9a5c8e8765417d54ed6917c7e1e4d09f4dTomas Winkler return 0; 37490e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler 37590e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler dev = cl->dev; 37690e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler 377a14c44d82fcff280fd1138574d4480b2bdd40216Tomas Winkler cl_dbg(dev, cl, "unlink client"); 378a14c44d82fcff280fd1138574d4480b2bdd40216Tomas Winkler 37922f96a0eb6c62b570621d77dacbf2589a6de2997Tomas Winkler if (dev->open_handle_count > 0) 38022f96a0eb6c62b570621d77dacbf2589a6de2997Tomas Winkler dev->open_handle_count--; 38122f96a0eb6c62b570621d77dacbf2589a6de2997Tomas Winkler 38222f96a0eb6c62b570621d77dacbf2589a6de2997Tomas Winkler /* never clear the 0 bit */ 38322f96a0eb6c62b570621d77dacbf2589a6de2997Tomas Winkler if (cl->host_client_id) 38422f96a0eb6c62b570621d77dacbf2589a6de2997Tomas Winkler clear_bit(cl->host_client_id, dev->host_clients_map); 38522f96a0eb6c62b570621d77dacbf2589a6de2997Tomas Winkler 38622f96a0eb6c62b570621d77dacbf2589a6de2997Tomas Winkler list_del_init(&cl->link); 38722f96a0eb6c62b570621d77dacbf2589a6de2997Tomas Winkler 38822f96a0eb6c62b570621d77dacbf2589a6de2997Tomas Winkler cl->state = MEI_FILE_INITIALIZING; 38922f96a0eb6c62b570621d77dacbf2589a6de2997Tomas Winkler 39090e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler return 0; 3919ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler} 3929ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 3939ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 3949ca9050b3df690d9d44e39424ab2a531120af936Tomas Winklervoid mei_host_client_init(struct work_struct *work) 3959ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{ 3969ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler struct mei_device *dev = container_of(work, 3979ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler struct mei_device, init_work); 3989ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler struct mei_client_properties *client_props; 3999ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler int i; 4009ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 4019ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler mutex_lock(&dev->device_lock); 4029ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 4039ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler for (i = 0; i < dev->me_clients_num; i++) { 4049ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler client_props = &dev->me_clients[i].props; 4059ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 4061a1aca42c989051dce34d49b4e04a25dafe01d74Tomas Winkler if (!uuid_le_cmp(client_props->protocol_name, mei_amthif_guid)) 4079ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler mei_amthif_host_init(dev); 4089ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler else if (!uuid_le_cmp(client_props->protocol_name, mei_wd_guid)) 4099ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler mei_wd_host_init(dev); 41059fcd7c63abf0340f551f487264b67ff5f7a0b86Samuel Ortiz else if (!uuid_le_cmp(client_props->protocol_name, mei_nfc_guid)) 41159fcd7c63abf0340f551f487264b67ff5f7a0b86Samuel Ortiz mei_nfc_host_init(dev); 41259fcd7c63abf0340f551f487264b67ff5f7a0b86Samuel Ortiz 4139ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler } 4149ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 4159ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler dev->dev_state = MEI_DEV_ENABLED; 4166adb8efb024a7e413b93b22848fc13395b1a438aTomas Winkler dev->reset_count = 0; 4179ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 4189ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler mutex_unlock(&dev->device_lock); 41904bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler 42004bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler pm_runtime_mark_last_busy(&dev->pdev->dev); 42104bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler dev_dbg(&dev->pdev->dev, "rpm: autosuspend\n"); 42204bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler pm_runtime_autosuspend(&dev->pdev->dev); 4239ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler} 4249ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 4256aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler/** 4266aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler * mei_hbuf_acquire: try to acquire host buffer 4276aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler * 4286aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler * @dev: the device structure 4296aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler * returns true if host buffer was acquired 4306aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler */ 4316aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winklerbool mei_hbuf_acquire(struct mei_device *dev) 4326aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler{ 43304bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler if (mei_pg_state(dev) == MEI_PG_ON || 43404bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler dev->pg_event == MEI_PG_EVENT_WAIT) { 43504bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler dev_dbg(&dev->pdev->dev, "device is in pg\n"); 43604bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler return false; 43704bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler } 43804bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler 4396aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler if (!dev->hbuf_is_ready) { 4406aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler dev_dbg(&dev->pdev->dev, "hbuf is not ready\n"); 4416aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler return false; 4426aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler } 4436aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler 4446aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler dev->hbuf_is_ready = false; 4456aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler 4466aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler return true; 4476aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler} 4489ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 4499ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/** 45083ce07411dc2316aaaf95a0f193fa2fd76e2e739Alexander Usyskin * mei_cl_disconnect - disconnect host client from the me one 4519ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * 45290e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler * @cl: host client 4539ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * 4549ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * Locking: called under "dev->device_lock" lock 4559ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * 4569ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * returns 0 on success, <0 on failure. 4579ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */ 45890e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winklerint mei_cl_disconnect(struct mei_cl *cl) 4599ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{ 46090e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler struct mei_device *dev; 4619ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler struct mei_cl_cb *cb; 462fe2f17eb3da38ac0d5a00c511255bf3a33d16d24Alexander Usyskin int rets; 4639ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 46490e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler if (WARN_ON(!cl || !cl->dev)) 4659ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler return -ENODEV; 4669ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 46790e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler dev = cl->dev; 46890e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler 469c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin cl_dbg(dev, cl, "disconnecting"); 470c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin 4719ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler if (cl->state != MEI_FILE_DISCONNECTING) 4729ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler return 0; 4739ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 47404bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler rets = pm_runtime_get(&dev->pdev->dev); 47504bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler if (rets < 0 && rets != -EINPROGRESS) { 47604bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler pm_runtime_put_noidle(&dev->pdev->dev); 47704bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler cl_err(dev, cl, "rpm: get failed %d\n", rets); 47804bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler return rets; 47904bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler } 48004bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler 4819ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler cb = mei_io_cb_init(cl, NULL); 48204bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler if (!cb) { 48304bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler rets = -ENOMEM; 48404bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler goto free; 48504bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler } 4869ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 4879ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler cb->fop_type = MEI_FOP_CLOSE; 4886aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler if (mei_hbuf_acquire(dev)) { 4899ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler if (mei_hbm_cl_disconnect_req(dev, cl)) { 4909ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler rets = -ENODEV; 491c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin cl_err(dev, cl, "failed to disconnect.\n"); 4929ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler goto free; 4939ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler } 49422b987a325701223f9a37db700c6eb20b9924c6fAlexander Usyskin cl->timer_count = MEI_CONNECT_TIMEOUT; 4959ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler mdelay(10); /* Wait for hardware disconnection ready */ 4969ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler list_add_tail(&cb->list, &dev->ctrl_rd_list.list); 4979ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler } else { 498c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin cl_dbg(dev, cl, "add disconnect cb to control write list\n"); 4999ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler list_add_tail(&cb->list, &dev->ctrl_wr_list.list); 5009ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 5019ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler } 5029ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler mutex_unlock(&dev->device_lock); 5039ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 504fe2f17eb3da38ac0d5a00c511255bf3a33d16d24Alexander Usyskin wait_event_timeout(dev->wait_recvd_msg, 5059ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler MEI_FILE_DISCONNECTED == cl->state, 5069ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT)); 5079ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 5089ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler mutex_lock(&dev->device_lock); 509fe2f17eb3da38ac0d5a00c511255bf3a33d16d24Alexander Usyskin 5109ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler if (MEI_FILE_DISCONNECTED == cl->state) { 5119ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler rets = 0; 512c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin cl_dbg(dev, cl, "successfully disconnected from FW client.\n"); 5139ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler } else { 514fe2f17eb3da38ac0d5a00c511255bf3a33d16d24Alexander Usyskin cl_dbg(dev, cl, "timeout on disconnect from FW client.\n"); 515fe2f17eb3da38ac0d5a00c511255bf3a33d16d24Alexander Usyskin rets = -ETIME; 5169ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler } 5179ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 5189ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler mei_io_list_flush(&dev->ctrl_rd_list, cl); 5199ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler mei_io_list_flush(&dev->ctrl_wr_list, cl); 5209ca9050b3df690d9d44e39424ab2a531120af936Tomas Winklerfree: 52104bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler cl_dbg(dev, cl, "rpm: autosuspend\n"); 52204bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler pm_runtime_mark_last_busy(&dev->pdev->dev); 52304bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler pm_runtime_put_autosuspend(&dev->pdev->dev); 52404bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler 5259ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler mei_io_cb_free(cb); 5269ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler return rets; 5279ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler} 5289ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 5299ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 5309ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/** 53190e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler * mei_cl_is_other_connecting - checks if other 53290e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler * client with the same me client id is connecting 5339ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * 5349ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * @cl: private data of the file object 5359ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * 53683ce07411dc2316aaaf95a0f193fa2fd76e2e739Alexander Usyskin * returns true if other client is connected, false - otherwise. 5379ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */ 53890e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winklerbool mei_cl_is_other_connecting(struct mei_cl *cl) 5399ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{ 54090e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler struct mei_device *dev; 54131f88f5739e966cb3c524083e2d19b423ece3585Tomas Winkler struct mei_cl *ocl; /* the other client */ 5429ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 54390e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler if (WARN_ON(!cl || !cl->dev)) 54490e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler return false; 54590e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler 54690e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler dev = cl->dev; 54790e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler 54831f88f5739e966cb3c524083e2d19b423ece3585Tomas Winkler list_for_each_entry(ocl, &dev->file_list, link) { 54931f88f5739e966cb3c524083e2d19b423ece3585Tomas Winkler if (ocl->state == MEI_FILE_CONNECTING && 55031f88f5739e966cb3c524083e2d19b423ece3585Tomas Winkler ocl != cl && 55131f88f5739e966cb3c524083e2d19b423ece3585Tomas Winkler cl->me_client_id == ocl->me_client_id) 55290e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler return true; 5539ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 5549ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler } 55590e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler 55690e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler return false; 5579ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler} 5589ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 5599ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/** 56083ce07411dc2316aaaf95a0f193fa2fd76e2e739Alexander Usyskin * mei_cl_connect - connect host client to the me one 5619f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler * 5629f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler * @cl: host client 5639f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler * 5649f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler * Locking: called under "dev->device_lock" lock 5659f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler * 5669f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler * returns 0 on success, <0 on failure. 5679f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler */ 5689f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winklerint mei_cl_connect(struct mei_cl *cl, struct file *file) 5699f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler{ 5709f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler struct mei_device *dev; 5719f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler struct mei_cl_cb *cb; 5729f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler int rets; 5739f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler 5749f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler if (WARN_ON(!cl || !cl->dev)) 5759f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler return -ENODEV; 5769f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler 5779f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler dev = cl->dev; 5789f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler 57904bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler rets = pm_runtime_get(&dev->pdev->dev); 58004bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler if (rets < 0 && rets != -EINPROGRESS) { 58104bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler pm_runtime_put_noidle(&dev->pdev->dev); 58204bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler cl_err(dev, cl, "rpm: get failed %d\n", rets); 58304bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler return rets; 58404bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler } 58504bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler 5869f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler cb = mei_io_cb_init(cl, file); 5879f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler if (!cb) { 5889f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler rets = -ENOMEM; 5899f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler goto out; 5909f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler } 5919f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler 59202a7eecc6ee565f5f3af836d56fe25bafcc49c98Tomas Winkler cb->fop_type = MEI_FOP_CONNECT; 5939f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler 5946aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler /* run hbuf acquire last so we don't have to undo */ 5956aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler if (!mei_cl_is_other_connecting(cl) && mei_hbuf_acquire(dev)) { 596e4d8270e604c3202131bac607969605ac397b893Alexander Usyskin cl->state = MEI_FILE_CONNECTING; 5979f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler if (mei_hbm_cl_connect_req(dev, cl)) { 5989f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler rets = -ENODEV; 5999f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler goto out; 6009f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler } 6019f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler cl->timer_count = MEI_CONNECT_TIMEOUT; 6029f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler list_add_tail(&cb->list, &dev->ctrl_rd_list.list); 6039f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler } else { 60473ab4232388b7a08f17c8d08141ff2099fa0b161Alexander Usyskin cl->state = MEI_FILE_INITIALIZING; 6059f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler list_add_tail(&cb->list, &dev->ctrl_wr_list.list); 6069f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler } 6079f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler 6089f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler mutex_unlock(&dev->device_lock); 609285e2996655b7bbfb5eb83076a7d7e6f03e2f5c2Alexander Usyskin wait_event_timeout(dev->wait_recvd_msg, 610285e2996655b7bbfb5eb83076a7d7e6f03e2f5c2Alexander Usyskin (cl->state == MEI_FILE_CONNECTED || 611285e2996655b7bbfb5eb83076a7d7e6f03e2f5c2Alexander Usyskin cl->state == MEI_FILE_DISCONNECTED), 612285e2996655b7bbfb5eb83076a7d7e6f03e2f5c2Alexander Usyskin mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT)); 6139f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler mutex_lock(&dev->device_lock); 6149f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler 6159f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler if (cl->state != MEI_FILE_CONNECTED) { 6163e37ebb7183f0c4eb92a88c60657ac319c01b3e9Alexander Usyskin cl->state = MEI_FILE_DISCONNECTED; 617285e2996655b7bbfb5eb83076a7d7e6f03e2f5c2Alexander Usyskin /* something went really wrong */ 618285e2996655b7bbfb5eb83076a7d7e6f03e2f5c2Alexander Usyskin if (!cl->status) 619285e2996655b7bbfb5eb83076a7d7e6f03e2f5c2Alexander Usyskin cl->status = -EFAULT; 6209f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler 6219f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler mei_io_list_flush(&dev->ctrl_rd_list, cl); 6229f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler mei_io_list_flush(&dev->ctrl_wr_list, cl); 6239f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler } 6249f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler 6259f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler rets = cl->status; 6269f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler 6279f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winklerout: 62804bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler cl_dbg(dev, cl, "rpm: autosuspend\n"); 62904bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler pm_runtime_mark_last_busy(&dev->pdev->dev); 63004bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler pm_runtime_put_autosuspend(&dev->pdev->dev); 63104bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler 6329f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler mei_io_cb_free(cb); 6339f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler return rets; 6349f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler} 6359f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler 6369f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler/** 63790e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler * mei_cl_flow_ctrl_creds - checks flow_control credits for cl. 6389ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * 6399ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * @cl: private data of the file object 6409ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * 6419ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * returns 1 if mei_flow_ctrl_creds >0, 0 - otherwise. 6429ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * -ENOENT if mei_cl is not present 6439ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * -EINVAL if single_recv_buf == 0 6449ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */ 64590e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winklerint mei_cl_flow_ctrl_creds(struct mei_cl *cl) 6469ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{ 64790e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler struct mei_device *dev; 64812d0066526f386538de80b4d86d2008461b36674Alexander Usyskin struct mei_me_client *me_cl; 64912d0066526f386538de80b4d86d2008461b36674Alexander Usyskin int id; 6509ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 65190e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler if (WARN_ON(!cl || !cl->dev)) 65290e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler return -EINVAL; 65390e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler 65490e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler dev = cl->dev; 65590e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler 6569ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler if (!dev->me_clients_num) 6579ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler return 0; 6589ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 6599ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler if (cl->mei_flow_ctrl_creds > 0) 6609ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler return 1; 6619ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 66212d0066526f386538de80b4d86d2008461b36674Alexander Usyskin id = mei_me_cl_by_id(dev, cl->me_client_id); 66312d0066526f386538de80b4d86d2008461b36674Alexander Usyskin if (id < 0) { 66412d0066526f386538de80b4d86d2008461b36674Alexander Usyskin cl_err(dev, cl, "no such me client %d\n", cl->me_client_id); 66512d0066526f386538de80b4d86d2008461b36674Alexander Usyskin return id; 6669ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler } 66712d0066526f386538de80b4d86d2008461b36674Alexander Usyskin 66812d0066526f386538de80b4d86d2008461b36674Alexander Usyskin me_cl = &dev->me_clients[id]; 66912d0066526f386538de80b4d86d2008461b36674Alexander Usyskin if (me_cl->mei_flow_ctrl_creds) { 67012d0066526f386538de80b4d86d2008461b36674Alexander Usyskin if (WARN_ON(me_cl->props.single_recv_buf == 0)) 67112d0066526f386538de80b4d86d2008461b36674Alexander Usyskin return -EINVAL; 67212d0066526f386538de80b4d86d2008461b36674Alexander Usyskin return 1; 67312d0066526f386538de80b4d86d2008461b36674Alexander Usyskin } 67412d0066526f386538de80b4d86d2008461b36674Alexander Usyskin return 0; 6759ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler} 6769ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 6779ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/** 67890e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler * mei_cl_flow_ctrl_reduce - reduces flow_control. 6799ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * 6809ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * @cl: private data of the file object 681393b148f9d0e70cfcb0096985bb0f0742802929eMasanari Iida * 6829ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * @returns 6839ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * 0 on success 6849ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * -ENOENT when me client is not found 6859ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * -EINVAL when ctrl credits are <= 0 6869ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */ 68790e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winklerint mei_cl_flow_ctrl_reduce(struct mei_cl *cl) 6889ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{ 68990e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler struct mei_device *dev; 69012d0066526f386538de80b4d86d2008461b36674Alexander Usyskin struct mei_me_client *me_cl; 69112d0066526f386538de80b4d86d2008461b36674Alexander Usyskin int id; 6929ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 69390e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler if (WARN_ON(!cl || !cl->dev)) 69490e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler return -EINVAL; 69590e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler 69690e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler dev = cl->dev; 69790e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler 69812d0066526f386538de80b4d86d2008461b36674Alexander Usyskin id = mei_me_cl_by_id(dev, cl->me_client_id); 69912d0066526f386538de80b4d86d2008461b36674Alexander Usyskin if (id < 0) { 70012d0066526f386538de80b4d86d2008461b36674Alexander Usyskin cl_err(dev, cl, "no such me client %d\n", cl->me_client_id); 70112d0066526f386538de80b4d86d2008461b36674Alexander Usyskin return id; 70212d0066526f386538de80b4d86d2008461b36674Alexander Usyskin } 7039ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 70412d0066526f386538de80b4d86d2008461b36674Alexander Usyskin me_cl = &dev->me_clients[id]; 70512d0066526f386538de80b4d86d2008461b36674Alexander Usyskin if (me_cl->props.single_recv_buf != 0) { 70612d0066526f386538de80b4d86d2008461b36674Alexander Usyskin if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0)) 70712d0066526f386538de80b4d86d2008461b36674Alexander Usyskin return -EINVAL; 70812d0066526f386538de80b4d86d2008461b36674Alexander Usyskin me_cl->mei_flow_ctrl_creds--; 70912d0066526f386538de80b4d86d2008461b36674Alexander Usyskin } else { 71012d0066526f386538de80b4d86d2008461b36674Alexander Usyskin if (WARN_ON(cl->mei_flow_ctrl_creds <= 0)) 71112d0066526f386538de80b4d86d2008461b36674Alexander Usyskin return -EINVAL; 71212d0066526f386538de80b4d86d2008461b36674Alexander Usyskin cl->mei_flow_ctrl_creds--; 7139ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler } 71412d0066526f386538de80b4d86d2008461b36674Alexander Usyskin return 0; 7159ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler} 7169ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 7179ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/** 718393b148f9d0e70cfcb0096985bb0f0742802929eMasanari Iida * mei_cl_read_start - the start read client message function. 7199ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * 72090e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler * @cl: host client 7219ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * 7229ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * returns 0 on success, <0 on failure. 7239ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */ 724fcb136e1ac5774909e0d85189f721b8dfa800e0fTomas Winklerint mei_cl_read_start(struct mei_cl *cl, size_t length) 7259ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{ 72690e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler struct mei_device *dev; 7279ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler struct mei_cl_cb *cb; 7289ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler int rets; 7299ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler int i; 7309ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 73190e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler if (WARN_ON(!cl || !cl->dev)) 73290e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler return -ENODEV; 73390e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler 73490e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler dev = cl->dev; 73590e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler 736b950ac1dabfcbf97b99f26fa75f86087e1960aefTomas Winkler if (!mei_cl_is_connected(cl)) 7379ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler return -ENODEV; 7389ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 739d91aaed30a938c5daae2641e6758dfab8727862eTomas Winkler if (cl->read_cb) { 740c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin cl_dbg(dev, cl, "read is pending.\n"); 7419ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler return -EBUSY; 7429ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler } 7439ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler i = mei_me_cl_by_id(dev, cl->me_client_id); 7449ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler if (i < 0) { 745c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin cl_err(dev, cl, "no such me client %d\n", cl->me_client_id); 7467ca96aa278f8b9983184e318b06a0ed9ad0297b8Alexander Usyskin return -ENOTTY; 7479ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler } 7489ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 74904bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler rets = pm_runtime_get(&dev->pdev->dev); 75004bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler if (rets < 0 && rets != -EINPROGRESS) { 75104bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler pm_runtime_put_noidle(&dev->pdev->dev); 75204bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler cl_err(dev, cl, "rpm: get failed %d\n", rets); 75304bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler return rets; 75404bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler } 75504bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler 7569ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler cb = mei_io_cb_init(cl, NULL); 75704bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler if (!cb) { 75804bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler rets = -ENOMEM; 75904bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler goto out; 76004bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler } 7619ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 762fcb136e1ac5774909e0d85189f721b8dfa800e0fTomas Winkler /* always allocate at least client max message */ 763fcb136e1ac5774909e0d85189f721b8dfa800e0fTomas Winkler length = max_t(size_t, length, dev->me_clients[i].props.max_msg_length); 764fcb136e1ac5774909e0d85189f721b8dfa800e0fTomas Winkler rets = mei_io_cb_alloc_resp_buf(cb, length); 7659ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler if (rets) 76604bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler goto out; 7679ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 7689ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler cb->fop_type = MEI_FOP_READ; 7696aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler if (mei_hbuf_acquire(dev)) { 77086113500c060bccb0f08bdcadcecc0bd267fd25aAlexander Usyskin rets = mei_hbm_cl_flow_control_req(dev, cl); 77186113500c060bccb0f08bdcadcecc0bd267fd25aAlexander Usyskin if (rets < 0) 77204bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler goto out; 77304bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler 7749ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler list_add_tail(&cb->list, &dev->read_list.list); 7759ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler } else { 7769ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler list_add_tail(&cb->list, &dev->ctrl_wr_list.list); 7779ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler } 778accb884b32e82f943340688c9cd30290531e73e0Chao Bi 779accb884b32e82f943340688c9cd30290531e73e0Chao Bi cl->read_cb = cb; 780accb884b32e82f943340688c9cd30290531e73e0Chao Bi 78104bb139a071fef549892718f8965a7c61b1924e0Tomas Winklerout: 78204bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler cl_dbg(dev, cl, "rpm: autosuspend\n"); 78304bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler pm_runtime_mark_last_busy(&dev->pdev->dev); 78404bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler pm_runtime_put_autosuspend(&dev->pdev->dev); 78504bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler 78604bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler if (rets) 78704bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler mei_io_cb_free(cb); 78804bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler 7899ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler return rets; 7909ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler} 7919ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler 792074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler/** 7939d098192c3d45ab6dd90ae87d649950a9ef70ccbTomas Winkler * mei_cl_irq_write - write a message to device 79421767546e955c3c1705387ca4548db812382fe08Tomas Winkler * from the interrupt thread context 79521767546e955c3c1705387ca4548db812382fe08Tomas Winkler * 79621767546e955c3c1705387ca4548db812382fe08Tomas Winkler * @cl: client 79721767546e955c3c1705387ca4548db812382fe08Tomas Winkler * @cb: callback block. 79821767546e955c3c1705387ca4548db812382fe08Tomas Winkler * @cmpl_list: complete list. 79921767546e955c3c1705387ca4548db812382fe08Tomas Winkler * 80021767546e955c3c1705387ca4548db812382fe08Tomas Winkler * returns 0, OK; otherwise error. 80121767546e955c3c1705387ca4548db812382fe08Tomas Winkler */ 8029d098192c3d45ab6dd90ae87d649950a9ef70ccbTomas Winklerint mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, 8039d098192c3d45ab6dd90ae87d649950a9ef70ccbTomas Winkler struct mei_cl_cb *cmpl_list) 80421767546e955c3c1705387ca4548db812382fe08Tomas Winkler{ 805136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler struct mei_device *dev; 806136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler struct mei_msg_data *buf; 80721767546e955c3c1705387ca4548db812382fe08Tomas Winkler struct mei_msg_hdr mei_hdr; 808136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler size_t len; 809136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler u32 msg_slots; 8109d098192c3d45ab6dd90ae87d649950a9ef70ccbTomas Winkler int slots; 8112ebf8c94d431078d93599ba56efa58bf850078a1Tomas Winkler int rets; 81221767546e955c3c1705387ca4548db812382fe08Tomas Winkler 813136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler if (WARN_ON(!cl || !cl->dev)) 814136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler return -ENODEV; 815136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler 816136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler dev = cl->dev; 817136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler 818136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler buf = &cb->request_buffer; 819136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler 820136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler rets = mei_cl_flow_ctrl_creds(cl); 821136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler if (rets < 0) 822136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler return rets; 823136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler 824136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler if (rets == 0) { 82504bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler cl_dbg(dev, cl, "No flow control credentials: not sending.\n"); 826136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler return 0; 827136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler } 828136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler 8299d098192c3d45ab6dd90ae87d649950a9ef70ccbTomas Winkler slots = mei_hbuf_empty_slots(dev); 830136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler len = buf->size - cb->buf_idx; 831136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler msg_slots = mei_data2slots(len); 832136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler 83321767546e955c3c1705387ca4548db812382fe08Tomas Winkler mei_hdr.host_addr = cl->host_client_id; 83421767546e955c3c1705387ca4548db812382fe08Tomas Winkler mei_hdr.me_addr = cl->me_client_id; 83521767546e955c3c1705387ca4548db812382fe08Tomas Winkler mei_hdr.reserved = 0; 836479327fc42737234a1f76f20010334c99110d256Tomas Winkler mei_hdr.internal = cb->internal; 83721767546e955c3c1705387ca4548db812382fe08Tomas Winkler 8389d098192c3d45ab6dd90ae87d649950a9ef70ccbTomas Winkler if (slots >= msg_slots) { 83921767546e955c3c1705387ca4548db812382fe08Tomas Winkler mei_hdr.length = len; 84021767546e955c3c1705387ca4548db812382fe08Tomas Winkler mei_hdr.msg_complete = 1; 84121767546e955c3c1705387ca4548db812382fe08Tomas Winkler /* Split the message only if we can write the whole host buffer */ 8429d098192c3d45ab6dd90ae87d649950a9ef70ccbTomas Winkler } else if (slots == dev->hbuf_depth) { 8439d098192c3d45ab6dd90ae87d649950a9ef70ccbTomas Winkler msg_slots = slots; 8449d098192c3d45ab6dd90ae87d649950a9ef70ccbTomas Winkler len = (slots * sizeof(u32)) - sizeof(struct mei_msg_hdr); 84521767546e955c3c1705387ca4548db812382fe08Tomas Winkler mei_hdr.length = len; 84621767546e955c3c1705387ca4548db812382fe08Tomas Winkler mei_hdr.msg_complete = 0; 84721767546e955c3c1705387ca4548db812382fe08Tomas Winkler } else { 84821767546e955c3c1705387ca4548db812382fe08Tomas Winkler /* wait for next time the host buffer is empty */ 84921767546e955c3c1705387ca4548db812382fe08Tomas Winkler return 0; 85021767546e955c3c1705387ca4548db812382fe08Tomas Winkler } 85121767546e955c3c1705387ca4548db812382fe08Tomas Winkler 852c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin cl_dbg(dev, cl, "buf: size = %d idx = %lu\n", 85321767546e955c3c1705387ca4548db812382fe08Tomas Winkler cb->request_buffer.size, cb->buf_idx); 85421767546e955c3c1705387ca4548db812382fe08Tomas Winkler 855136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler rets = mei_write_message(dev, &mei_hdr, buf->data + cb->buf_idx); 8562ebf8c94d431078d93599ba56efa58bf850078a1Tomas Winkler if (rets) { 8572ebf8c94d431078d93599ba56efa58bf850078a1Tomas Winkler cl->status = rets; 85821767546e955c3c1705387ca4548db812382fe08Tomas Winkler list_move_tail(&cb->list, &cmpl_list->list); 8592ebf8c94d431078d93599ba56efa58bf850078a1Tomas Winkler return rets; 86021767546e955c3c1705387ca4548db812382fe08Tomas Winkler } 86121767546e955c3c1705387ca4548db812382fe08Tomas Winkler 86221767546e955c3c1705387ca4548db812382fe08Tomas Winkler cl->status = 0; 8634dfaa9f7020b1ff4bf87899f4797d2efd76e80fdTomas Winkler cl->writing_state = MEI_WRITING; 86421767546e955c3c1705387ca4548db812382fe08Tomas Winkler cb->buf_idx += mei_hdr.length; 8654dfaa9f7020b1ff4bf87899f4797d2efd76e80fdTomas Winkler 86621767546e955c3c1705387ca4548db812382fe08Tomas Winkler if (mei_hdr.msg_complete) { 86721767546e955c3c1705387ca4548db812382fe08Tomas Winkler if (mei_cl_flow_ctrl_reduce(cl)) 8682ebf8c94d431078d93599ba56efa58bf850078a1Tomas Winkler return -EIO; 86921767546e955c3c1705387ca4548db812382fe08Tomas Winkler list_move_tail(&cb->list, &dev->write_waiting_list.list); 87021767546e955c3c1705387ca4548db812382fe08Tomas Winkler } 87121767546e955c3c1705387ca4548db812382fe08Tomas Winkler 87221767546e955c3c1705387ca4548db812382fe08Tomas Winkler return 0; 87321767546e955c3c1705387ca4548db812382fe08Tomas Winkler} 87421767546e955c3c1705387ca4548db812382fe08Tomas Winkler 87521767546e955c3c1705387ca4548db812382fe08Tomas Winkler/** 8764234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler * mei_cl_write - submit a write cb to mei device 8774234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler assumes device_lock is locked 8784234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler * 8794234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler * @cl: host client 8804234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler * @cl: write callback with filled data 8814234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler * 88283ce07411dc2316aaaf95a0f193fa2fd76e2e739Alexander Usyskin * returns number of bytes sent on success, <0 on failure. 8834234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler */ 8844234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winklerint mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking) 8854234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler{ 8864234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler struct mei_device *dev; 8874234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler struct mei_msg_data *buf; 8884234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler struct mei_msg_hdr mei_hdr; 8894234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler int rets; 8904234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler 8914234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler 8924234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler if (WARN_ON(!cl || !cl->dev)) 8934234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler return -ENODEV; 8944234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler 8954234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler if (WARN_ON(!cb)) 8964234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler return -EINVAL; 8974234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler 8984234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler dev = cl->dev; 8994234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler 9004234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler 9014234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler buf = &cb->request_buffer; 9024234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler 903c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin cl_dbg(dev, cl, "mei_cl_write %d\n", buf->size); 9044234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler 90504bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler rets = pm_runtime_get(&dev->pdev->dev); 90604bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler if (rets < 0 && rets != -EINPROGRESS) { 90704bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler pm_runtime_put_noidle(&dev->pdev->dev); 90804bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler cl_err(dev, cl, "rpm: get failed %d\n", rets); 90904bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler return rets; 91004bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler } 9114234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler 9124234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler cb->fop_type = MEI_FOP_WRITE; 9136aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler cb->buf_idx = 0; 9146aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler cl->writing_state = MEI_IDLE; 9156aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler 9166aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler mei_hdr.host_addr = cl->host_client_id; 9176aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler mei_hdr.me_addr = cl->me_client_id; 9186aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler mei_hdr.reserved = 0; 9196aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler mei_hdr.msg_complete = 0; 9206aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler mei_hdr.internal = cb->internal; 9214234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler 9224234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler rets = mei_cl_flow_ctrl_creds(cl); 9234234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler if (rets < 0) 9244234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler goto err; 9254234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler 9266aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler if (rets == 0) { 9276aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler cl_dbg(dev, cl, "No flow control credentials: not sending.\n"); 9286aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler rets = buf->size; 9296aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler goto out; 9306aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler } 9316aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler if (!mei_hbuf_acquire(dev)) { 9326aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler cl_dbg(dev, cl, "Cannot acquire the host buffer: not sending.\n"); 9334234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler rets = buf->size; 9344234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler goto out; 9354234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler } 9364234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler 9374234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler /* Check for a maximum length */ 9384234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler if (buf->size > mei_hbuf_max_len(dev)) { 9394234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler mei_hdr.length = mei_hbuf_max_len(dev); 9404234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler mei_hdr.msg_complete = 0; 9414234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler } else { 9424234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler mei_hdr.length = buf->size; 9434234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler mei_hdr.msg_complete = 1; 9444234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler } 9454234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler 9462ebf8c94d431078d93599ba56efa58bf850078a1Tomas Winkler rets = mei_write_message(dev, &mei_hdr, buf->data); 9472ebf8c94d431078d93599ba56efa58bf850078a1Tomas Winkler if (rets) 9484234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler goto err; 9494234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler 9504234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler cl->writing_state = MEI_WRITING; 9514234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler cb->buf_idx = mei_hdr.length; 9524234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler 9534234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winklerout: 9544234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler if (mei_hdr.msg_complete) { 9557ca96aa278f8b9983184e318b06a0ed9ad0297b8Alexander Usyskin rets = mei_cl_flow_ctrl_reduce(cl); 9567ca96aa278f8b9983184e318b06a0ed9ad0297b8Alexander Usyskin if (rets < 0) 9574234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler goto err; 9587ca96aa278f8b9983184e318b06a0ed9ad0297b8Alexander Usyskin 9594234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler list_add_tail(&cb->list, &dev->write_waiting_list.list); 9604234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler } else { 9614234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler list_add_tail(&cb->list, &dev->write_list.list); 9624234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler } 9634234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler 9644234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler 9654234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler if (blocking && cl->writing_state != MEI_WRITE_COMPLETE) { 9664234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler 9674234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler mutex_unlock(&dev->device_lock); 9687ca96aa278f8b9983184e318b06a0ed9ad0297b8Alexander Usyskin rets = wait_event_interruptible(cl->tx_wait, 9697ca96aa278f8b9983184e318b06a0ed9ad0297b8Alexander Usyskin cl->writing_state == MEI_WRITE_COMPLETE); 9704234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler mutex_lock(&dev->device_lock); 9717ca96aa278f8b9983184e318b06a0ed9ad0297b8Alexander Usyskin /* wait_event_interruptible returns -ERESTARTSYS */ 9727ca96aa278f8b9983184e318b06a0ed9ad0297b8Alexander Usyskin if (rets) { 9737ca96aa278f8b9983184e318b06a0ed9ad0297b8Alexander Usyskin if (signal_pending(current)) 9747ca96aa278f8b9983184e318b06a0ed9ad0297b8Alexander Usyskin rets = -EINTR; 9757ca96aa278f8b9983184e318b06a0ed9ad0297b8Alexander Usyskin goto err; 9767ca96aa278f8b9983184e318b06a0ed9ad0297b8Alexander Usyskin } 9774234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler } 9787ca96aa278f8b9983184e318b06a0ed9ad0297b8Alexander Usyskin 9797ca96aa278f8b9983184e318b06a0ed9ad0297b8Alexander Usyskin rets = buf->size; 9804234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winklererr: 98104bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler cl_dbg(dev, cl, "rpm: autosuspend\n"); 98204bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler pm_runtime_mark_last_busy(&dev->pdev->dev); 98304bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler pm_runtime_put_autosuspend(&dev->pdev->dev); 98404bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler 9854234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler return rets; 9864234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler} 9874234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler 9884234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler 989db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler/** 990db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler * mei_cl_complete - processes completed operation for a client 991db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler * 992db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler * @cl: private data of the file object. 993db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler * @cb: callback block. 994db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler */ 995db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winklervoid mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb) 996db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler{ 997db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler if (cb->fop_type == MEI_FOP_WRITE) { 998db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler mei_io_cb_free(cb); 999db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler cb = NULL; 1000db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler cl->writing_state = MEI_WRITE_COMPLETE; 1001db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler if (waitqueue_active(&cl->tx_wait)) 1002db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler wake_up_interruptible(&cl->tx_wait); 1003db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler 1004db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler } else if (cb->fop_type == MEI_FOP_READ && 1005db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler MEI_READING == cl->reading_state) { 1006db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler cl->reading_state = MEI_READ_COMPLETE; 1007db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler if (waitqueue_active(&cl->rx_wait)) 1008db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler wake_up_interruptible(&cl->rx_wait); 1009db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler else 1010db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler mei_cl_bus_rx_event(cl); 1011db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler 1012db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler } 1013db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler} 1014db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler 10154234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler 10164234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler/** 1017074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler * mei_cl_all_disconnect - disconnect forcefully all connected clients 1018074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler * 1019074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler * @dev - mei device 1020074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler */ 1021074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler 1022074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winklervoid mei_cl_all_disconnect(struct mei_device *dev) 1023074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler{ 102431f88f5739e966cb3c524083e2d19b423ece3585Tomas Winkler struct mei_cl *cl; 1025074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler 102631f88f5739e966cb3c524083e2d19b423ece3585Tomas Winkler list_for_each_entry(cl, &dev->file_list, link) { 1027074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler cl->state = MEI_FILE_DISCONNECTED; 1028074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler cl->mei_flow_ctrl_creds = 0; 1029074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler cl->timer_count = 0; 1030074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler } 1031074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler} 1032074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler 1033074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler 1034074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler/** 10355290801c23231c8e192943d3beb01fdbeb536395Tomas Winkler * mei_cl_all_wakeup - wake up all readers and writers they can be interrupted 1036074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler * 1037074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler * @dev - mei device 1038074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler */ 10395290801c23231c8e192943d3beb01fdbeb536395Tomas Winklervoid mei_cl_all_wakeup(struct mei_device *dev) 1040074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler{ 104131f88f5739e966cb3c524083e2d19b423ece3585Tomas Winkler struct mei_cl *cl; 104231f88f5739e966cb3c524083e2d19b423ece3585Tomas Winkler list_for_each_entry(cl, &dev->file_list, link) { 1043074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler if (waitqueue_active(&cl->rx_wait)) { 1044c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin cl_dbg(dev, cl, "Waking up reading client!\n"); 1045074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler wake_up_interruptible(&cl->rx_wait); 1046074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler } 10475290801c23231c8e192943d3beb01fdbeb536395Tomas Winkler if (waitqueue_active(&cl->tx_wait)) { 1048c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin cl_dbg(dev, cl, "Waking up writing client!\n"); 10495290801c23231c8e192943d3beb01fdbeb536395Tomas Winkler wake_up_interruptible(&cl->tx_wait); 10505290801c23231c8e192943d3beb01fdbeb536395Tomas Winkler } 1051074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler } 1052074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler} 1053074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler 1054074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler/** 1055074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler * mei_cl_all_write_clear - clear all pending writes 1056074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler 1057074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler * @dev - mei device 1058074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler */ 1059074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winklervoid mei_cl_all_write_clear(struct mei_device *dev) 1060074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler{ 1061cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler mei_io_list_free(&dev->write_list, NULL); 1062cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler mei_io_list_free(&dev->write_waiting_list, NULL); 1063074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler} 1064074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler 1065074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler 1066