2012-12-25 21:06:07 +04:00
/*
*
* Intel Management Engine Interface ( Intel MEI ) Linux driver
* Copyright ( c ) 2003 - 2012 , Intel Corporation .
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms and conditions of the GNU General Public License ,
* version 2 , as published by the Free Software Foundation .
*
* This program is distributed in the hope it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License for
* more details .
*
*/
# include <linux/pci.h>
# include <linux/sched.h>
# include <linux/wait.h>
# include <linux/mei.h>
# include "mei_dev.h"
2013-01-09 01:07:12 +04:00
# include "hbm.h"
2013-01-09 01:07:17 +04:00
# include "hw-me.h"
2012-12-25 21:06:07 +04:00
2013-01-09 01:07:19 +04:00
/**
* mei_hbm_me_cl_allocate - allocates storage for me clients
*
* @ dev : the device structure
*
* returns none .
*/
static void mei_hbm_me_cl_allocate ( struct mei_device * dev )
{
struct mei_me_client * clients ;
int b ;
/* count how many ME clients we have */
for_each_set_bit ( b , dev - > me_clients_map , MEI_CLIENTS_MAX )
dev - > me_clients_num + + ;
if ( dev - > me_clients_num < = 0 )
return ;
kfree ( dev - > me_clients ) ;
dev - > me_clients = NULL ;
dev_dbg ( & dev - > pdev - > dev , " memory allocation for ME clients size=%zd. \n " ,
dev - > me_clients_num * sizeof ( struct mei_me_client ) ) ;
/* allocate storage for ME clients representation */
clients = kcalloc ( dev - > me_clients_num ,
sizeof ( struct mei_me_client ) , GFP_KERNEL ) ;
if ( ! clients ) {
dev_err ( & dev - > pdev - > dev , " memory allocation for ME clients failed. \n " ) ;
dev - > dev_state = MEI_DEV_RESETING ;
mei_reset ( dev , 1 ) ;
return ;
}
dev - > me_clients = clients ;
return ;
}
2012-12-25 21:06:09 +04:00
/**
* mei_hbm_cl_hdr - construct client hbm header
* @ cl : - client
* @ hbm_cmd : host bus message command
* @ buf : buffer for cl header
* @ len : buffer length
*/
static inline
void mei_hbm_cl_hdr ( struct mei_cl * cl , u8 hbm_cmd , void * buf , size_t len )
{
struct mei_hbm_cl_cmd * cmd = buf ;
memset ( cmd , 0 , len ) ;
cmd - > hbm_cmd = hbm_cmd ;
cmd - > host_addr = cl - > host_client_id ;
cmd - > me_addr = cl - > me_client_id ;
}
/**
* same_disconn_addr - tells if they have the same address
*
* @ file : private data of the file object .
* @ disconn : disconnection request .
*
* returns true if addres are same
*/
static inline
bool mei_hbm_cl_addr_equal ( struct mei_cl * cl , void * buf )
{
struct mei_hbm_cl_cmd * cmd = buf ;
return cl - > host_client_id = = cmd - > host_addr & &
cl - > me_client_id = = cmd - > me_addr ;
}
2012-12-25 21:06:12 +04:00
/**
* is_treat_specially_client - checks if the message belongs
* to the file private data .
*
* @ cl : private data of the file object
* @ rs : connect response bus message
*
*/
static bool is_treat_specially_client ( struct mei_cl * cl ,
struct hbm_client_connect_response * rs )
{
if ( mei_hbm_cl_addr_equal ( cl , rs ) ) {
if ( ! rs - > status ) {
cl - > state = MEI_FILE_CONNECTED ;
cl - > status = 0 ;
} else {
cl - > state = MEI_FILE_DISCONNECTED ;
cl - > status = - ENODEV ;
}
cl - > timer_count = 0 ;
return true ;
}
return false ;
}
2012-12-25 21:06:07 +04:00
/**
2012-12-25 21:06:11 +04:00
* mei_hbm_start_req - sends start request message .
2012-12-25 21:06:07 +04:00
*
* @ dev : the device structure
*/
2012-12-25 21:06:11 +04:00
void mei_hbm_start_req ( struct mei_device * dev )
2012-12-25 21:06:07 +04:00
{
2012-12-25 21:06:10 +04:00
struct mei_msg_hdr * mei_hdr = & dev - > wr_msg . hdr ;
2012-12-25 21:06:07 +04:00
struct hbm_host_version_request * start_req ;
const size_t len = sizeof ( struct hbm_host_version_request ) ;
2012-12-25 21:06:10 +04:00
mei_hbm_hdr ( mei_hdr , len ) ;
2012-12-25 21:06:07 +04:00
/* host start message */
2012-12-25 21:06:10 +04:00
start_req = ( struct hbm_host_version_request * ) dev - > wr_msg . data ;
2012-12-25 21:06:07 +04:00
memset ( start_req , 0 , len ) ;
start_req - > hbm_cmd = HOST_START_REQ_CMD ;
start_req - > host_version . major_version = HBM_MAJOR_VERSION ;
start_req - > host_version . minor_version = HBM_MINOR_VERSION ;
dev - > recvd_msg = false ;
2012-12-25 21:06:10 +04:00
if ( mei_write_message ( dev , mei_hdr , dev - > wr_msg . data ) ) {
2012-12-25 21:06:07 +04:00
dev_dbg ( & dev - > pdev - > dev , " write send version message to FW fail. \n " ) ;
dev - > dev_state = MEI_DEV_RESETING ;
mei_reset ( dev , 1 ) ;
}
dev - > init_clients_state = MEI_START_MESSAGE ;
dev - > init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT ;
return ;
}
/**
2012-12-25 21:06:11 +04:00
* mei_hbm_enum_clients_req - sends enumeration client request message .
2012-12-25 21:06:07 +04:00
*
* @ dev : the device structure
*
* returns none .
*/
2012-12-25 21:06:11 +04:00
static void mei_hbm_enum_clients_req ( struct mei_device * dev )
2012-12-25 21:06:07 +04:00
{
2012-12-25 21:06:10 +04:00
struct mei_msg_hdr * mei_hdr = & dev - > wr_msg . hdr ;
2012-12-25 21:06:07 +04:00
struct hbm_host_enum_request * enum_req ;
const size_t len = sizeof ( struct hbm_host_enum_request ) ;
/* enumerate clients */
2012-12-25 21:06:10 +04:00
mei_hbm_hdr ( mei_hdr , len ) ;
2012-12-25 21:06:07 +04:00
2012-12-25 21:06:10 +04:00
enum_req = ( struct hbm_host_enum_request * ) dev - > wr_msg . data ;
memset ( enum_req , 0 , len ) ;
2012-12-25 21:06:07 +04:00
enum_req - > hbm_cmd = HOST_ENUM_REQ_CMD ;
2012-12-25 21:06:10 +04:00
if ( mei_write_message ( dev , mei_hdr , dev - > wr_msg . data ) ) {
2012-12-25 21:06:07 +04:00
dev - > dev_state = MEI_DEV_RESETING ;
dev_dbg ( & dev - > pdev - > dev , " write send enumeration request message to FW fail. \n " ) ;
mei_reset ( dev , 1 ) ;
}
dev - > init_clients_state = MEI_ENUM_CLIENTS_MESSAGE ;
dev - > init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT ;
return ;
}
2012-12-25 21:06:11 +04:00
/**
* mei_hbm_prop_requsest - request property for a single client
*
* @ dev : the device structure
*
* returns none .
*/
2012-12-25 21:06:07 +04:00
2012-12-25 21:06:11 +04:00
static int mei_hbm_prop_req ( struct mei_device * dev )
2012-12-25 21:06:07 +04:00
{
2012-12-25 21:06:10 +04:00
struct mei_msg_hdr * mei_hdr = & dev - > wr_msg . hdr ;
2012-12-25 21:06:07 +04:00
struct hbm_props_request * prop_req ;
const size_t len = sizeof ( struct hbm_props_request ) ;
unsigned long next_client_index ;
u8 client_num ;
client_num = dev - > me_client_presentation_num ;
next_client_index = find_next_bit ( dev - > me_clients_map , MEI_CLIENTS_MAX ,
dev - > me_client_index ) ;
/* We got all client properties */
if ( next_client_index = = MEI_CLIENTS_MAX ) {
schedule_work ( & dev - > init_work ) ;
return 0 ;
}
dev - > me_clients [ client_num ] . client_id = next_client_index ;
dev - > me_clients [ client_num ] . mei_flow_ctrl_creds = 0 ;
2012-12-25 21:06:10 +04:00
mei_hbm_hdr ( mei_hdr , len ) ;
prop_req = ( struct hbm_props_request * ) dev - > wr_msg . data ;
2012-12-25 21:06:07 +04:00
memset ( prop_req , 0 , sizeof ( struct hbm_props_request ) ) ;
prop_req - > hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD ;
prop_req - > address = next_client_index ;
2012-12-25 21:06:10 +04:00
if ( mei_write_message ( dev , mei_hdr , dev - > wr_msg . data ) ) {
2012-12-25 21:06:07 +04:00
dev - > dev_state = MEI_DEV_RESETING ;
dev_err ( & dev - > pdev - > dev , " Properties request command failed \n " ) ;
mei_reset ( dev , 1 ) ;
return - EIO ;
}
dev - > init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT ;
dev - > me_client_index = next_client_index ;
return 0 ;
}
2012-12-25 21:06:10 +04:00
/**
* mei_hbm_stop_req_prepare - perpare stop request message
*
* @ dev - mei device
* @ mei_hdr - mei message header
* @ data - hbm message body buffer
*/
static void mei_hbm_stop_req_prepare ( struct mei_device * dev ,
struct mei_msg_hdr * mei_hdr , unsigned char * data )
{
struct hbm_host_stop_request * req =
( struct hbm_host_stop_request * ) data ;
const size_t len = sizeof ( struct hbm_host_stop_request ) ;
mei_hbm_hdr ( mei_hdr , len ) ;
memset ( req , 0 , len ) ;
req - > hbm_cmd = HOST_STOP_REQ_CMD ;
req - > reason = DRIVER_STOP_REQUEST ;
}
2012-12-25 21:06:07 +04:00
/**
2012-12-25 21:06:11 +04:00
* mei_hbm_cl_flow_control_req - sends flow control requst .
2012-12-25 21:06:07 +04:00
*
* @ dev : the device structure
2012-12-25 21:06:11 +04:00
* @ cl : client info
2012-12-25 21:06:07 +04:00
*
* This function returns - EIO on write failure
*/
2012-12-25 21:06:11 +04:00
int mei_hbm_cl_flow_control_req ( struct mei_device * dev , struct mei_cl * cl )
2012-12-25 21:06:07 +04:00
{
2012-12-25 21:06:10 +04:00
struct mei_msg_hdr * mei_hdr = & dev - > wr_msg . hdr ;
2012-12-25 21:06:07 +04:00
const size_t len = sizeof ( struct hbm_flow_control ) ;
2012-12-25 21:06:10 +04:00
mei_hbm_hdr ( mei_hdr , len ) ;
mei_hbm_cl_hdr ( cl , MEI_FLOW_CONTROL_CMD , dev - > wr_msg . data , len ) ;
2012-12-25 21:06:07 +04:00
dev_dbg ( & dev - > pdev - > dev , " sending flow control host client = %d, ME client = %d \n " ,
cl - > host_client_id , cl - > me_client_id ) ;
2012-12-25 21:06:10 +04:00
return mei_write_message ( dev , mei_hdr , dev - > wr_msg . data ) ;
2012-12-25 21:06:07 +04:00
}
2012-12-25 21:06:12 +04:00
/**
* add_single_flow_creds - adds single buffer credentials .
*
* @ file : private data ot the file object .
* @ flow : flow control .
*/
static void mei_hbm_add_single_flow_creds ( struct mei_device * dev ,
struct hbm_flow_control * flow )
{
struct mei_me_client * client ;
int i ;
for ( i = 0 ; i < dev - > me_clients_num ; i + + ) {
client = & dev - > me_clients [ i ] ;
if ( client & & flow - > me_addr = = client - > client_id ) {
if ( client - > props . single_recv_buf ) {
client - > mei_flow_ctrl_creds + + ;
dev_dbg ( & dev - > pdev - > dev , " recv flow ctrl msg ME %d (single). \n " ,
flow - > me_addr ) ;
dev_dbg ( & dev - > pdev - > dev , " flow control credentials =%d. \n " ,
client - > mei_flow_ctrl_creds ) ;
} else {
BUG ( ) ; /* error in flow control */
}
}
}
}
/**
* mei_hbm_cl_flow_control_res - flow control response from me
*
* @ dev : the device structure
* @ flow_control : flow control response bus message
*/
static void mei_hbm_cl_flow_control_res ( struct mei_device * dev ,
struct hbm_flow_control * flow_control )
{
struct mei_cl * cl = NULL ;
struct mei_cl * next = NULL ;
if ( ! flow_control - > host_addr ) {
/* single receive buffer */
mei_hbm_add_single_flow_creds ( dev , flow_control ) ;
return ;
}
/* normal connection */
list_for_each_entry_safe ( cl , next , & dev - > file_list , link ) {
if ( mei_hbm_cl_addr_equal ( cl , flow_control ) ) {
cl - > mei_flow_ctrl_creds + + ;
dev_dbg ( & dev - > pdev - > dev , " flow ctrl msg for host %d ME %d. \n " ,
flow_control - > host_addr , flow_control - > me_addr ) ;
dev_dbg ( & dev - > pdev - > dev , " flow control credentials = %d. \n " ,
cl - > mei_flow_ctrl_creds ) ;
break ;
}
}
}
2012-12-25 21:06:07 +04:00
/**
2012-12-25 21:06:11 +04:00
* mei_hbm_cl_disconnect_req - sends disconnect message to fw .
2012-12-25 21:06:07 +04:00
*
* @ dev : the device structure
2012-12-25 21:06:11 +04:00
* @ cl : a client to disconnect from
2012-12-25 21:06:07 +04:00
*
* This function returns - EIO on write failure
*/
2012-12-25 21:06:11 +04:00
int mei_hbm_cl_disconnect_req ( struct mei_device * dev , struct mei_cl * cl )
2012-12-25 21:06:07 +04:00
{
2012-12-25 21:06:10 +04:00
struct mei_msg_hdr * mei_hdr = & dev - > wr_msg . hdr ;
2012-12-25 21:06:07 +04:00
const size_t len = sizeof ( struct hbm_client_connect_request ) ;
2012-12-25 21:06:10 +04:00
mei_hbm_hdr ( mei_hdr , len ) ;
mei_hbm_cl_hdr ( cl , CLIENT_DISCONNECT_REQ_CMD , dev - > wr_msg . data , len ) ;
2012-12-25 21:06:07 +04:00
2012-12-25 21:06:10 +04:00
return mei_write_message ( dev , mei_hdr , dev - > wr_msg . data ) ;
2012-12-25 21:06:07 +04:00
}
2012-12-25 21:06:12 +04:00
/**
* mei_hbm_cl_disconnect_res - disconnect response from ME
*
* @ dev : the device structure
* @ rs : disconnect response bus message
*/
static void mei_hbm_cl_disconnect_res ( struct mei_device * dev ,
struct hbm_client_connect_response * rs )
{
struct mei_cl * cl ;
struct mei_cl_cb * pos = NULL , * next = NULL ;
dev_dbg ( & dev - > pdev - > dev ,
" disconnect_response: \n "
" ME Client = %d \n "
" Host Client = %d \n "
" Status = %d \n " ,
rs - > me_addr ,
rs - > host_addr ,
rs - > status ) ;
list_for_each_entry_safe ( pos , next , & dev - > ctrl_rd_list . list , list ) {
cl = pos - > cl ;
if ( ! cl ) {
list_del ( & pos - > list ) ;
return ;
}
dev_dbg ( & dev - > pdev - > dev , " list_for_each_entry_safe in ctrl_rd_list. \n " ) ;
if ( mei_hbm_cl_addr_equal ( cl , rs ) ) {
list_del ( & pos - > list ) ;
if ( ! rs - > status )
cl - > state = MEI_FILE_DISCONNECTED ;
cl - > status = 0 ;
cl - > timer_count = 0 ;
break ;
}
}
}
2012-12-25 21:06:07 +04:00
/**
2012-12-25 21:06:11 +04:00
* mei_hbm_cl_connect_req - send connection request to specific me client
2012-12-25 21:06:07 +04:00
*
* @ dev : the device structure
2012-12-25 21:06:11 +04:00
* @ cl : a client to connect to
2012-12-25 21:06:07 +04:00
*
2012-12-25 21:06:11 +04:00
* returns - EIO on write failure
2012-12-25 21:06:07 +04:00
*/
2012-12-25 21:06:11 +04:00
int mei_hbm_cl_connect_req ( struct mei_device * dev , struct mei_cl * cl )
2012-12-25 21:06:07 +04:00
{
2012-12-25 21:06:10 +04:00
struct mei_msg_hdr * mei_hdr = & dev - > wr_msg . hdr ;
2012-12-25 21:06:07 +04:00
const size_t len = sizeof ( struct hbm_client_connect_request ) ;
2012-12-25 21:06:10 +04:00
mei_hbm_hdr ( mei_hdr , len ) ;
mei_hbm_cl_hdr ( cl , CLIENT_CONNECT_REQ_CMD , dev - > wr_msg . data , len ) ;
2012-12-25 21:06:07 +04:00
2012-12-25 21:06:10 +04:00
return mei_write_message ( dev , mei_hdr , dev - > wr_msg . data ) ;
2012-12-25 21:06:07 +04:00
}
2012-12-25 21:06:12 +04:00
/**
* mei_hbm_cl_connect_res - connect resposne from the ME
*
* @ dev : the device structure
* @ rs : connect response bus message
*/
static void mei_hbm_cl_connect_res ( struct mei_device * dev ,
struct hbm_client_connect_response * rs )
{
struct mei_cl * cl ;
struct mei_cl_cb * pos = NULL , * next = NULL ;
dev_dbg ( & dev - > pdev - > dev ,
" connect_response: \n "
" ME Client = %d \n "
" Host Client = %d \n "
" Status = %d \n " ,
rs - > me_addr ,
rs - > host_addr ,
rs - > status ) ;
/* if WD or iamthif client treat specially */
if ( is_treat_specially_client ( & dev - > wd_cl , rs ) ) {
dev_dbg ( & dev - > pdev - > dev , " successfully connected to WD client. \n " ) ;
mei_watchdog_register ( dev ) ;
return ;
}
if ( is_treat_specially_client ( & dev - > iamthif_cl , rs ) ) {
dev - > iamthif_state = MEI_IAMTHIF_IDLE ;
return ;
}
list_for_each_entry_safe ( pos , next , & dev - > ctrl_rd_list . list , list ) {
cl = pos - > cl ;
if ( ! cl ) {
list_del ( & pos - > list ) ;
return ;
}
if ( pos - > fop_type = = MEI_FOP_IOCTL ) {
if ( is_treat_specially_client ( cl , rs ) ) {
list_del ( & pos - > list ) ;
cl - > status = 0 ;
cl - > timer_count = 0 ;
break ;
}
}
}
}
2012-12-25 21:06:07 +04:00
/**
2012-12-25 21:06:11 +04:00
* mei_client_disconnect_request - disconnect request initiated by me
* host sends disoconnect response
2012-12-25 21:06:07 +04:00
*
* @ dev : the device structure .
2012-12-25 21:06:11 +04:00
* @ disconnect_req : disconnect request bus message from the me
2012-12-25 21:06:07 +04:00
*/
2012-12-25 21:06:11 +04:00
static void mei_hbm_fw_disconnect_req ( struct mei_device * dev ,
2012-12-25 21:06:07 +04:00
struct hbm_client_connect_request * disconnect_req )
{
2012-12-25 21:06:09 +04:00
struct mei_cl * cl , * next ;
2012-12-25 21:06:07 +04:00
const size_t len = sizeof ( struct hbm_client_connect_response ) ;
2012-12-25 21:06:09 +04:00
list_for_each_entry_safe ( cl , next , & dev - > file_list , link ) {
if ( mei_hbm_cl_addr_equal ( cl , disconnect_req ) ) {
2012-12-25 21:06:07 +04:00
dev_dbg ( & dev - > pdev - > dev , " disconnect request host client %d ME client %d. \n " ,
disconnect_req - > host_addr ,
disconnect_req - > me_addr ) ;
2012-12-25 21:06:09 +04:00
cl - > state = MEI_FILE_DISCONNECTED ;
cl - > timer_count = 0 ;
if ( cl = = & dev - > wd_cl )
2012-12-25 21:06:07 +04:00
dev - > wd_pending = false ;
2012-12-25 21:06:09 +04:00
else if ( cl = = & dev - > iamthif_cl )
2012-12-25 21:06:07 +04:00
dev - > iamthif_timer = 0 ;
/* prepare disconnect response */
2012-12-25 21:06:10 +04:00
mei_hbm_hdr ( & dev - > wr_ext_msg . hdr , len ) ;
2012-12-25 21:06:09 +04:00
mei_hbm_cl_hdr ( cl , CLIENT_DISCONNECT_RES_CMD ,
2012-12-25 21:06:10 +04:00
dev - > wr_ext_msg . data , len ) ;
2012-12-25 21:06:07 +04:00
break ;
}
}
}
/**
* mei_hbm_dispatch - bottom half read routine after ISR to
* handle the read bus message cmd processing .
*
* @ dev : the device structure
* @ mei_hdr : header of bus message
*/
void mei_hbm_dispatch ( struct mei_device * dev , struct mei_msg_hdr * hdr )
{
struct mei_bus_message * mei_msg ;
struct mei_me_client * me_client ;
struct hbm_host_version_response * version_res ;
struct hbm_client_connect_response * connect_res ;
struct hbm_client_connect_response * disconnect_res ;
struct hbm_client_connect_request * disconnect_req ;
struct hbm_flow_control * flow_control ;
struct hbm_props_response * props_res ;
struct hbm_host_enum_response * enum_res ;
/* read the message to our buffer */
BUG_ON ( hdr - > length > = sizeof ( dev - > rd_msg_buf ) ) ;
mei_read_slots ( dev , dev - > rd_msg_buf , hdr - > length ) ;
mei_msg = ( struct mei_bus_message * ) dev - > rd_msg_buf ;
switch ( mei_msg - > hbm_cmd ) {
case HOST_START_RES_CMD :
version_res = ( struct hbm_host_version_response * ) mei_msg ;
2012-12-25 21:06:10 +04:00
if ( ! version_res - > host_version_supported ) {
2012-12-25 21:06:07 +04:00
dev - > version = version_res - > me_max_version ;
2012-12-25 21:06:10 +04:00
dev_dbg ( & dev - > pdev - > dev , " version mismatch. \n " ) ;
2012-12-25 21:06:07 +04:00
2012-12-25 21:06:10 +04:00
mei_hbm_stop_req_prepare ( dev , & dev - > wr_msg . hdr ,
dev - > wr_msg . data ) ;
mei_write_message ( dev , & dev - > wr_msg . hdr ,
dev - > wr_msg . data ) ;
return ;
}
2012-12-25 21:06:07 +04:00
2012-12-25 21:06:10 +04:00
dev - > version . major_version = HBM_MAJOR_VERSION ;
dev - > version . minor_version = HBM_MINOR_VERSION ;
if ( dev - > dev_state = = MEI_DEV_INIT_CLIENTS & &
dev - > init_clients_state = = MEI_START_MESSAGE ) {
dev - > init_clients_timer = 0 ;
2012-12-25 21:06:11 +04:00
mei_hbm_enum_clients_req ( dev ) ;
2012-12-25 21:06:10 +04:00
} else {
dev - > recvd_msg = false ;
dev_dbg ( & dev - > pdev - > dev , " reset due to received hbm: host start \n " ) ;
mei_reset ( dev , 1 ) ;
2012-12-25 21:06:07 +04:00
return ;
}
dev - > recvd_msg = true ;
dev_dbg ( & dev - > pdev - > dev , " host start response message received. \n " ) ;
break ;
case CLIENT_CONNECT_RES_CMD :
connect_res = ( struct hbm_client_connect_response * ) mei_msg ;
2012-12-25 21:06:12 +04:00
mei_hbm_cl_connect_res ( dev , connect_res ) ;
2012-12-25 21:06:07 +04:00
dev_dbg ( & dev - > pdev - > dev , " client connect response message received. \n " ) ;
wake_up ( & dev - > wait_recvd_msg ) ;
break ;
case CLIENT_DISCONNECT_RES_CMD :
disconnect_res = ( struct hbm_client_connect_response * ) mei_msg ;
2012-12-25 21:06:12 +04:00
mei_hbm_cl_disconnect_res ( dev , disconnect_res ) ;
2012-12-25 21:06:07 +04:00
dev_dbg ( & dev - > pdev - > dev , " client disconnect response message received. \n " ) ;
wake_up ( & dev - > wait_recvd_msg ) ;
break ;
case MEI_FLOW_CONTROL_CMD :
flow_control = ( struct hbm_flow_control * ) mei_msg ;
2012-12-25 21:06:12 +04:00
mei_hbm_cl_flow_control_res ( dev , flow_control ) ;
2012-12-25 21:06:07 +04:00
dev_dbg ( & dev - > pdev - > dev , " client flow control response message received. \n " ) ;
break ;
case HOST_CLIENT_PROPERTIES_RES_CMD :
props_res = ( struct hbm_props_response * ) mei_msg ;
me_client = & dev - > me_clients [ dev - > me_client_presentation_num ] ;
if ( props_res - > status | | ! dev - > me_clients ) {
dev_dbg ( & dev - > pdev - > dev , " reset due to received host client properties response bus message wrong status. \n " ) ;
mei_reset ( dev , 1 ) ;
return ;
}
if ( me_client - > client_id ! = props_res - > address ) {
dev_err ( & dev - > pdev - > dev ,
" Host client properties reply mismatch \n " ) ;
mei_reset ( dev , 1 ) ;
return ;
}
if ( dev - > dev_state ! = MEI_DEV_INIT_CLIENTS | |
dev - > init_clients_state ! = MEI_CLIENT_PROPERTIES_MESSAGE ) {
dev_err ( & dev - > pdev - > dev ,
" Unexpected client properties reply \n " ) ;
mei_reset ( dev , 1 ) ;
return ;
}
me_client - > props = props_res - > client_properties ;
dev - > me_client_index + + ;
dev - > me_client_presentation_num + + ;
2012-12-25 21:06:11 +04:00
/* request property for the next client */
mei_hbm_prop_req ( dev ) ;
2012-12-25 21:06:07 +04:00
break ;
case HOST_ENUM_RES_CMD :
enum_res = ( struct hbm_host_enum_response * ) mei_msg ;
memcpy ( dev - > me_clients_map , enum_res - > valid_addresses , 32 ) ;
if ( dev - > dev_state = = MEI_DEV_INIT_CLIENTS & &
dev - > init_clients_state = = MEI_ENUM_CLIENTS_MESSAGE ) {
dev - > init_clients_timer = 0 ;
dev - > me_client_presentation_num = 0 ;
dev - > me_client_index = 0 ;
2013-01-09 01:07:19 +04:00
mei_hbm_me_cl_allocate ( dev ) ;
2012-12-25 21:06:07 +04:00
dev - > init_clients_state =
MEI_CLIENT_PROPERTIES_MESSAGE ;
2012-12-25 21:06:11 +04:00
/* first property reqeust */
mei_hbm_prop_req ( dev ) ;
2012-12-25 21:06:07 +04:00
} else {
dev_dbg ( & dev - > pdev - > dev , " reset due to received host enumeration clients response bus message. \n " ) ;
mei_reset ( dev , 1 ) ;
return ;
}
break ;
case HOST_STOP_RES_CMD :
dev - > dev_state = MEI_DEV_DISABLED ;
dev_dbg ( & dev - > pdev - > dev , " resetting because of FW stop response. \n " ) ;
mei_reset ( dev , 1 ) ;
break ;
case CLIENT_DISCONNECT_REQ_CMD :
/* search for client */
disconnect_req = ( struct hbm_client_connect_request * ) mei_msg ;
2012-12-25 21:06:11 +04:00
mei_hbm_fw_disconnect_req ( dev , disconnect_req ) ;
2012-12-25 21:06:07 +04:00
break ;
case ME_STOP_REQ_CMD :
2012-12-25 21:06:10 +04:00
mei_hbm_stop_req_prepare ( dev , & dev - > wr_ext_msg . hdr ,
dev - > wr_ext_msg . data ) ;
2012-12-25 21:06:07 +04:00
break ;
default :
BUG ( ) ;
break ;
}
}