Commit c23c2234 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'char-misc-3.12-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc

Pull char/misc driver fixes from Greg KH:
 "Here are some HyperV and MEI driver fixes for 3.12-rc3.  They resolve
  some issues that people have been reporting for them"

* tag 'char-misc-3.12-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc:
  Drivers: hv: vmbus: Terminate vmbus version negotiation on timeout
  Drivers: hv: util: Correctly support ws2008R2 and earlier
  mei: cancel stall timers in mei_reset
  mei: bus: stop wait for read during cl state transition
  mei: make me client counters less error prone
parents cac66535 8bbf9f44
...@@ -195,7 +195,7 @@ int vmbus_connect(void) ...@@ -195,7 +195,7 @@ int vmbus_connect(void)
do { do {
ret = vmbus_negotiate_version(msginfo, version); ret = vmbus_negotiate_version(msginfo, version);
if (ret) if (ret == -ETIMEDOUT)
goto cleanup; goto cleanup;
if (vmbus_connection.conn_state == CONNECTED) if (vmbus_connection.conn_state == CONNECTED)
......
...@@ -32,13 +32,17 @@ ...@@ -32,13 +32,17 @@
/* /*
* Pre win8 version numbers used in ws2008 and ws 2008 r2 (win7) * Pre win8 version numbers used in ws2008 and ws 2008 r2 (win7)
*/ */
#define WS2008_SRV_MAJOR 1
#define WS2008_SRV_MINOR 0
#define WS2008_SRV_VERSION (WS2008_SRV_MAJOR << 16 | WS2008_SRV_MINOR)
#define WIN7_SRV_MAJOR 3 #define WIN7_SRV_MAJOR 3
#define WIN7_SRV_MINOR 0 #define WIN7_SRV_MINOR 0
#define WIN7_SRV_MAJOR_MINOR (WIN7_SRV_MAJOR << 16 | WIN7_SRV_MINOR) #define WIN7_SRV_VERSION (WIN7_SRV_MAJOR << 16 | WIN7_SRV_MINOR)
#define WIN8_SRV_MAJOR 4 #define WIN8_SRV_MAJOR 4
#define WIN8_SRV_MINOR 0 #define WIN8_SRV_MINOR 0
#define WIN8_SRV_MAJOR_MINOR (WIN8_SRV_MAJOR << 16 | WIN8_SRV_MINOR) #define WIN8_SRV_VERSION (WIN8_SRV_MAJOR << 16 | WIN8_SRV_MINOR)
/* /*
* Global state maintained for transaction that is being processed. * Global state maintained for transaction that is being processed.
...@@ -587,6 +591,8 @@ void hv_kvp_onchannelcallback(void *context) ...@@ -587,6 +591,8 @@ void hv_kvp_onchannelcallback(void *context)
struct icmsg_hdr *icmsghdrp; struct icmsg_hdr *icmsghdrp;
struct icmsg_negotiate *negop = NULL; struct icmsg_negotiate *negop = NULL;
int util_fw_version;
int kvp_srv_version;
if (kvp_transaction.active) { if (kvp_transaction.active) {
/* /*
...@@ -606,17 +612,26 @@ void hv_kvp_onchannelcallback(void *context) ...@@ -606,17 +612,26 @@ void hv_kvp_onchannelcallback(void *context)
if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) { if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
/* /*
* We start with win8 version and if the host cannot * Based on the host, select appropriate
* support that we use the previous version. * framework and service versions we will
*/ * negotiate.
if (vmbus_prep_negotiate_resp(icmsghdrp, negop, */
recv_buffer, UTIL_FW_MAJOR_MINOR, switch (vmbus_proto_version) {
WIN8_SRV_MAJOR_MINOR)) case (VERSION_WS2008):
goto done; util_fw_version = UTIL_WS2K8_FW_VERSION;
kvp_srv_version = WS2008_SRV_VERSION;
break;
case (VERSION_WIN7):
util_fw_version = UTIL_FW_VERSION;
kvp_srv_version = WIN7_SRV_VERSION;
break;
default:
util_fw_version = UTIL_FW_VERSION;
kvp_srv_version = WIN8_SRV_VERSION;
}
vmbus_prep_negotiate_resp(icmsghdrp, negop, vmbus_prep_negotiate_resp(icmsghdrp, negop,
recv_buffer, UTIL_FW_MAJOR_MINOR, recv_buffer, util_fw_version,
WIN7_SRV_MAJOR_MINOR); kvp_srv_version);
} else { } else {
kvp_msg = (struct hv_kvp_msg *)&recv_buffer[ kvp_msg = (struct hv_kvp_msg *)&recv_buffer[
...@@ -649,7 +664,6 @@ void hv_kvp_onchannelcallback(void *context) ...@@ -649,7 +664,6 @@ void hv_kvp_onchannelcallback(void *context)
return; return;
} }
done:
icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
| ICMSGHDRFLAG_RESPONSE; | ICMSGHDRFLAG_RESPONSE;
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#define VSS_MAJOR 5 #define VSS_MAJOR 5
#define VSS_MINOR 0 #define VSS_MINOR 0
#define VSS_MAJOR_MINOR (VSS_MAJOR << 16 | VSS_MINOR) #define VSS_VERSION (VSS_MAJOR << 16 | VSS_MINOR)
...@@ -190,8 +190,8 @@ void hv_vss_onchannelcallback(void *context) ...@@ -190,8 +190,8 @@ void hv_vss_onchannelcallback(void *context)
if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) { if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
vmbus_prep_negotiate_resp(icmsghdrp, negop, vmbus_prep_negotiate_resp(icmsghdrp, negop,
recv_buffer, UTIL_FW_MAJOR_MINOR, recv_buffer, UTIL_FW_VERSION,
VSS_MAJOR_MINOR); VSS_VERSION);
} else { } else {
vss_msg = (struct hv_vss_msg *)&recv_buffer[ vss_msg = (struct hv_vss_msg *)&recv_buffer[
sizeof(struct vmbuspipe_hdr) + sizeof(struct vmbuspipe_hdr) +
......
...@@ -28,17 +28,32 @@ ...@@ -28,17 +28,32 @@
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/hyperv.h> #include <linux/hyperv.h>
#define SHUTDOWN_MAJOR 3
#define SHUTDOWN_MINOR 0
#define SHUTDOWN_MAJOR_MINOR (SHUTDOWN_MAJOR << 16 | SHUTDOWN_MINOR)
#define TIMESYNCH_MAJOR 3 #define SD_MAJOR 3
#define TIMESYNCH_MINOR 0 #define SD_MINOR 0
#define TIMESYNCH_MAJOR_MINOR (TIMESYNCH_MAJOR << 16 | TIMESYNCH_MINOR) #define SD_VERSION (SD_MAJOR << 16 | SD_MINOR)
#define HEARTBEAT_MAJOR 3 #define SD_WS2008_MAJOR 1
#define HEARTBEAT_MINOR 0 #define SD_WS2008_VERSION (SD_WS2008_MAJOR << 16 | SD_MINOR)
#define HEARTBEAT_MAJOR_MINOR (HEARTBEAT_MAJOR << 16 | HEARTBEAT_MINOR)
#define TS_MAJOR 3
#define TS_MINOR 0
#define TS_VERSION (TS_MAJOR << 16 | TS_MINOR)
#define TS_WS2008_MAJOR 1
#define TS_WS2008_VERSION (TS_WS2008_MAJOR << 16 | TS_MINOR)
#define HB_MAJOR 3
#define HB_MINOR 0
#define HB_VERSION (HB_MAJOR << 16 | HB_MINOR)
#define HB_WS2008_MAJOR 1
#define HB_WS2008_VERSION (HB_WS2008_MAJOR << 16 | HB_MINOR)
static int sd_srv_version;
static int ts_srv_version;
static int hb_srv_version;
static int util_fw_version;
static void shutdown_onchannelcallback(void *context); static void shutdown_onchannelcallback(void *context);
static struct hv_util_service util_shutdown = { static struct hv_util_service util_shutdown = {
...@@ -99,8 +114,8 @@ static void shutdown_onchannelcallback(void *context) ...@@ -99,8 +114,8 @@ static void shutdown_onchannelcallback(void *context)
if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) { if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
vmbus_prep_negotiate_resp(icmsghdrp, negop, vmbus_prep_negotiate_resp(icmsghdrp, negop,
shut_txf_buf, UTIL_FW_MAJOR_MINOR, shut_txf_buf, util_fw_version,
SHUTDOWN_MAJOR_MINOR); sd_srv_version);
} else { } else {
shutdown_msg = shutdown_msg =
(struct shutdown_msg_data *)&shut_txf_buf[ (struct shutdown_msg_data *)&shut_txf_buf[
...@@ -216,6 +231,7 @@ static void timesync_onchannelcallback(void *context) ...@@ -216,6 +231,7 @@ static void timesync_onchannelcallback(void *context)
struct icmsg_hdr *icmsghdrp; struct icmsg_hdr *icmsghdrp;
struct ictimesync_data *timedatap; struct ictimesync_data *timedatap;
u8 *time_txf_buf = util_timesynch.recv_buffer; u8 *time_txf_buf = util_timesynch.recv_buffer;
struct icmsg_negotiate *negop = NULL;
vmbus_recvpacket(channel, time_txf_buf, vmbus_recvpacket(channel, time_txf_buf,
PAGE_SIZE, &recvlen, &requestid); PAGE_SIZE, &recvlen, &requestid);
...@@ -225,9 +241,10 @@ static void timesync_onchannelcallback(void *context) ...@@ -225,9 +241,10 @@ static void timesync_onchannelcallback(void *context)
sizeof(struct vmbuspipe_hdr)]; sizeof(struct vmbuspipe_hdr)];
if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) { if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
vmbus_prep_negotiate_resp(icmsghdrp, NULL, time_txf_buf, vmbus_prep_negotiate_resp(icmsghdrp, negop,
UTIL_FW_MAJOR_MINOR, time_txf_buf,
TIMESYNCH_MAJOR_MINOR); util_fw_version,
ts_srv_version);
} else { } else {
timedatap = (struct ictimesync_data *)&time_txf_buf[ timedatap = (struct ictimesync_data *)&time_txf_buf[
sizeof(struct vmbuspipe_hdr) + sizeof(struct vmbuspipe_hdr) +
...@@ -257,6 +274,7 @@ static void heartbeat_onchannelcallback(void *context) ...@@ -257,6 +274,7 @@ static void heartbeat_onchannelcallback(void *context)
struct icmsg_hdr *icmsghdrp; struct icmsg_hdr *icmsghdrp;
struct heartbeat_msg_data *heartbeat_msg; struct heartbeat_msg_data *heartbeat_msg;
u8 *hbeat_txf_buf = util_heartbeat.recv_buffer; u8 *hbeat_txf_buf = util_heartbeat.recv_buffer;
struct icmsg_negotiate *negop = NULL;
vmbus_recvpacket(channel, hbeat_txf_buf, vmbus_recvpacket(channel, hbeat_txf_buf,
PAGE_SIZE, &recvlen, &requestid); PAGE_SIZE, &recvlen, &requestid);
...@@ -266,9 +284,9 @@ static void heartbeat_onchannelcallback(void *context) ...@@ -266,9 +284,9 @@ static void heartbeat_onchannelcallback(void *context)
sizeof(struct vmbuspipe_hdr)]; sizeof(struct vmbuspipe_hdr)];
if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) { if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
vmbus_prep_negotiate_resp(icmsghdrp, NULL, vmbus_prep_negotiate_resp(icmsghdrp, negop,
hbeat_txf_buf, UTIL_FW_MAJOR_MINOR, hbeat_txf_buf, util_fw_version,
HEARTBEAT_MAJOR_MINOR); hb_srv_version);
} else { } else {
heartbeat_msg = heartbeat_msg =
(struct heartbeat_msg_data *)&hbeat_txf_buf[ (struct heartbeat_msg_data *)&hbeat_txf_buf[
...@@ -321,6 +339,25 @@ static int util_probe(struct hv_device *dev, ...@@ -321,6 +339,25 @@ static int util_probe(struct hv_device *dev,
goto error; goto error;
hv_set_drvdata(dev, srv); hv_set_drvdata(dev, srv);
/*
* Based on the host; initialize the framework and
* service version numbers we will negotiate.
*/
switch (vmbus_proto_version) {
case (VERSION_WS2008):
util_fw_version = UTIL_WS2K8_FW_VERSION;
sd_srv_version = SD_WS2008_VERSION;
ts_srv_version = TS_WS2008_VERSION;
hb_srv_version = HB_WS2008_VERSION;
break;
default:
util_fw_version = UTIL_FW_VERSION;
sd_srv_version = SD_VERSION;
ts_srv_version = TS_VERSION;
hb_srv_version = HB_VERSION;
}
return 0; return 0;
error: error:
......
...@@ -57,6 +57,7 @@ void mei_amthif_reset_params(struct mei_device *dev) ...@@ -57,6 +57,7 @@ void mei_amthif_reset_params(struct mei_device *dev)
dev->iamthif_ioctl = false; dev->iamthif_ioctl = false;
dev->iamthif_state = MEI_IAMTHIF_IDLE; dev->iamthif_state = MEI_IAMTHIF_IDLE;
dev->iamthif_timer = 0; dev->iamthif_timer = 0;
dev->iamthif_stall_timer = 0;
} }
/** /**
......
...@@ -297,10 +297,13 @@ int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length) ...@@ -297,10 +297,13 @@ int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
if (cl->reading_state != MEI_READ_COMPLETE && if (cl->reading_state != MEI_READ_COMPLETE &&
!waitqueue_active(&cl->rx_wait)) { !waitqueue_active(&cl->rx_wait)) {
mutex_unlock(&dev->device_lock); mutex_unlock(&dev->device_lock);
if (wait_event_interruptible(cl->rx_wait, if (wait_event_interruptible(cl->rx_wait,
(MEI_READ_COMPLETE == cl->reading_state))) { cl->reading_state == MEI_READ_COMPLETE ||
mei_cl_is_transitioning(cl))) {
if (signal_pending(current)) if (signal_pending(current))
return -EINTR; return -EINTR;
return -ERESTARTSYS; return -ERESTARTSYS;
......
...@@ -90,6 +90,12 @@ static inline bool mei_cl_is_connected(struct mei_cl *cl) ...@@ -90,6 +90,12 @@ static inline bool mei_cl_is_connected(struct mei_cl *cl)
cl->dev->dev_state == MEI_DEV_ENABLED && cl->dev->dev_state == MEI_DEV_ENABLED &&
cl->state == MEI_FILE_CONNECTED); cl->state == MEI_FILE_CONNECTED);
} }
static inline bool mei_cl_is_transitioning(struct mei_cl *cl)
{
return (MEI_FILE_INITIALIZING == cl->state ||
MEI_FILE_DISCONNECTED == cl->state ||
MEI_FILE_DISCONNECTING == cl->state);
}
bool mei_cl_is_other_connecting(struct mei_cl *cl); bool mei_cl_is_other_connecting(struct mei_cl *cl);
int mei_cl_disconnect(struct mei_cl *cl); int mei_cl_disconnect(struct mei_cl *cl);
......
...@@ -35,11 +35,15 @@ static void mei_hbm_me_cl_allocate(struct mei_device *dev) ...@@ -35,11 +35,15 @@ static void mei_hbm_me_cl_allocate(struct mei_device *dev)
struct mei_me_client *clients; struct mei_me_client *clients;
int b; int b;
dev->me_clients_num = 0;
dev->me_client_presentation_num = 0;
dev->me_client_index = 0;
/* count how many ME clients we have */ /* count how many ME clients we have */
for_each_set_bit(b, dev->me_clients_map, MEI_CLIENTS_MAX) for_each_set_bit(b, dev->me_clients_map, MEI_CLIENTS_MAX)
dev->me_clients_num++; dev->me_clients_num++;
if (dev->me_clients_num <= 0) if (dev->me_clients_num == 0)
return; return;
kfree(dev->me_clients); kfree(dev->me_clients);
...@@ -221,7 +225,7 @@ static int mei_hbm_prop_req(struct mei_device *dev) ...@@ -221,7 +225,7 @@ static int mei_hbm_prop_req(struct mei_device *dev)
struct hbm_props_request *prop_req; struct hbm_props_request *prop_req;
const size_t len = sizeof(struct hbm_props_request); const size_t len = sizeof(struct hbm_props_request);
unsigned long next_client_index; unsigned long next_client_index;
u8 client_num; unsigned long client_num;
client_num = dev->me_client_presentation_num; client_num = dev->me_client_presentation_num;
...@@ -677,8 +681,6 @@ void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) ...@@ -677,8 +681,6 @@ void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
if (dev->dev_state == MEI_DEV_INIT_CLIENTS && if (dev->dev_state == MEI_DEV_INIT_CLIENTS &&
dev->hbm_state == MEI_HBM_ENUM_CLIENTS) { dev->hbm_state == MEI_HBM_ENUM_CLIENTS) {
dev->init_clients_timer = 0; dev->init_clients_timer = 0;
dev->me_client_presentation_num = 0;
dev->me_client_index = 0;
mei_hbm_me_cl_allocate(dev); mei_hbm_me_cl_allocate(dev);
dev->hbm_state = MEI_HBM_CLIENT_PROPERTIES; dev->hbm_state = MEI_HBM_CLIENT_PROPERTIES;
......
...@@ -175,6 +175,9 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled) ...@@ -175,6 +175,9 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled)
memset(&dev->wr_ext_msg, 0, sizeof(dev->wr_ext_msg)); memset(&dev->wr_ext_msg, 0, sizeof(dev->wr_ext_msg));
} }
/* we're already in reset, cancel the init timer */
dev->init_clients_timer = 0;
dev->me_clients_num = 0; dev->me_clients_num = 0;
dev->rd_msg_hdr = 0; dev->rd_msg_hdr = 0;
dev->wd_pending = false; dev->wd_pending = false;
......
...@@ -249,19 +249,16 @@ static ssize_t mei_read(struct file *file, char __user *ubuf, ...@@ -249,19 +249,16 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
mutex_unlock(&dev->device_lock); mutex_unlock(&dev->device_lock);
if (wait_event_interruptible(cl->rx_wait, if (wait_event_interruptible(cl->rx_wait,
(MEI_READ_COMPLETE == cl->reading_state || MEI_READ_COMPLETE == cl->reading_state ||
MEI_FILE_INITIALIZING == cl->state || mei_cl_is_transitioning(cl))) {
MEI_FILE_DISCONNECTED == cl->state ||
MEI_FILE_DISCONNECTING == cl->state))) {
if (signal_pending(current)) if (signal_pending(current))
return -EINTR; return -EINTR;
return -ERESTARTSYS; return -ERESTARTSYS;
} }
mutex_lock(&dev->device_lock); mutex_lock(&dev->device_lock);
if (MEI_FILE_INITIALIZING == cl->state || if (mei_cl_is_transitioning(cl)) {
MEI_FILE_DISCONNECTED == cl->state ||
MEI_FILE_DISCONNECTING == cl->state) {
rets = -EBUSY; rets = -EBUSY;
goto out; goto out;
} }
......
...@@ -396,9 +396,9 @@ struct mei_device { ...@@ -396,9 +396,9 @@ struct mei_device {
struct mei_me_client *me_clients; /* Note: memory has to be allocated */ struct mei_me_client *me_clients; /* Note: memory has to be allocated */
DECLARE_BITMAP(me_clients_map, MEI_CLIENTS_MAX); DECLARE_BITMAP(me_clients_map, MEI_CLIENTS_MAX);
DECLARE_BITMAP(host_clients_map, MEI_CLIENTS_MAX); DECLARE_BITMAP(host_clients_map, MEI_CLIENTS_MAX);
u8 me_clients_num; unsigned long me_clients_num;
u8 me_client_presentation_num; unsigned long me_client_presentation_num;
u8 me_client_index; unsigned long me_client_index;
struct mei_cl wd_cl; struct mei_cl wd_cl;
enum mei_wd_states wd_state; enum mei_wd_states wd_state;
......
...@@ -30,10 +30,13 @@ ...@@ -30,10 +30,13 @@
/* /*
* Framework version for util services. * Framework version for util services.
*/ */
#define UTIL_FW_MINOR 0
#define UTIL_WS2K8_FW_MAJOR 1
#define UTIL_WS2K8_FW_VERSION (UTIL_WS2K8_FW_MAJOR << 16 | UTIL_FW_MINOR)
#define UTIL_FW_MAJOR 3 #define UTIL_FW_MAJOR 3
#define UTIL_FW_MINOR 0 #define UTIL_FW_VERSION (UTIL_FW_MAJOR << 16 | UTIL_FW_MINOR)
#define UTIL_FW_MAJOR_MINOR (UTIL_FW_MAJOR << 16 | UTIL_FW_MINOR)
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment