aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/mei
diff options
context:
space:
mode:
authorTomas Winkler <tomas.winkler@intel.com>2014-03-18 16:51:59 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-05-03 19:20:24 -0400
commit964a2331e9a207fc15ef9eef833212347498bea1 (patch)
tree1c444ed7f440d280c84140ec7e142c7713bb7896 /drivers/misc/mei
parentee7e5afd2c369b64ffcf419d38ce7ad1c709a53e (diff)
mei: expose hardware power gating state to mei layer
Since the runtime pm and the internal power gating cannot be in complete sync in regards to I/O operations, we need to expose the device hardware internal power gating state to mei layer 2. We add pg_state handler that translate the hw internal pg state to mei layer 2. We add power gating event variable to keep power track of power gating transitions Signed-off-by: Tomas Winkler <tomas.winkler@intel.com> Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com> Reviewed-by: Alexander Usyskin <alexander.usyskin@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/misc/mei')
-rw-r--r--drivers/misc/mei/hw-me.c15
-rw-r--r--drivers/misc/mei/hw-txe.c43
-rw-r--r--drivers/misc/mei/hw-txe.h14
-rw-r--r--drivers/misc/mei/init.c2
-rw-r--r--drivers/misc/mei/mei_dev.h38
5 files changed, 93 insertions, 19 deletions
diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c
index 7a7e66250dfd..02f3b0c3a2a3 100644
--- a/drivers/misc/mei/hw-me.c
+++ b/drivers/misc/mei/hw-me.c
@@ -113,6 +113,19 @@ static void mei_me_hw_config(struct mei_device *dev)
113 /* Doesn't change in runtime */ 113 /* Doesn't change in runtime */
114 dev->hbuf_depth = (hcsr & H_CBD) >> 24; 114 dev->hbuf_depth = (hcsr & H_CBD) >> 24;
115} 115}
116
117/**
118 * mei_me_pg_state - translate internal pg state
119 * to the mei power gating state
120 *
121 * @hw - me hardware
122 * returns: MEI_PG_OFF if aliveness is on and MEI_PG_ON otherwise
123 */
124static inline enum mei_pg_state mei_me_pg_state(struct mei_device *dev)
125{
126 return MEI_PG_OFF;
127}
128
116/** 129/**
117 * mei_clear_interrupts - clear and stop interrupts 130 * mei_clear_interrupts - clear and stop interrupts
118 * 131 *
@@ -601,6 +614,8 @@ end:
601} 614}
602static const struct mei_hw_ops mei_me_hw_ops = { 615static const struct mei_hw_ops mei_me_hw_ops = {
603 616
617 .pg_state = mei_me_pg_state,
618
604 .host_is_ready = mei_me_host_is_ready, 619 .host_is_ready = mei_me_host_is_ready,
605 620
606 .hw_is_ready = mei_me_hw_is_ready, 621 .hw_is_ready = mei_me_hw_is_ready,
diff --git a/drivers/misc/mei/hw-txe.c b/drivers/misc/mei/hw-txe.c
index 49f197a956c9..4a6f567f4f80 100644
--- a/drivers/misc/mei/hw-txe.c
+++ b/drivers/misc/mei/hw-txe.c
@@ -158,7 +158,7 @@ static bool mei_txe_aliveness_set(struct mei_device *dev, u32 req)
158 dev_dbg(&dev->pdev->dev, "Aliveness current=%d request=%d\n", 158 dev_dbg(&dev->pdev->dev, "Aliveness current=%d request=%d\n",
159 hw->aliveness, req); 159 hw->aliveness, req);
160 if (do_req) { 160 if (do_req) {
161 hw->recvd_aliveness = false; 161 dev->pg_event = MEI_PG_EVENT_WAIT;
162 mei_txe_br_reg_write(hw, SICR_HOST_ALIVENESS_REQ_REG, req); 162 mei_txe_br_reg_write(hw, SICR_HOST_ALIVENESS_REQ_REG, req);
163 } 163 }
164 return do_req; 164 return do_req;
@@ -213,6 +213,7 @@ static int mei_txe_aliveness_poll(struct mei_device *dev, u32 expected)
213 do { 213 do {
214 hw->aliveness = mei_txe_aliveness_get(dev); 214 hw->aliveness = mei_txe_aliveness_get(dev);
215 if (hw->aliveness == expected) { 215 if (hw->aliveness == expected) {
216 dev->pg_event = MEI_PG_EVENT_IDLE;
216 dev_dbg(&dev->pdev->dev, 217 dev_dbg(&dev->pdev->dev,
217 "aliveness settled after %d msecs\n", t); 218 "aliveness settled after %d msecs\n", t);
218 return t; 219 return t;
@@ -223,6 +224,7 @@ static int mei_txe_aliveness_poll(struct mei_device *dev, u32 expected)
223 t += MSEC_PER_SEC / 5; 224 t += MSEC_PER_SEC / 5;
224 } while (t < SEC_ALIVENESS_WAIT_TIMEOUT); 225 } while (t < SEC_ALIVENESS_WAIT_TIMEOUT);
225 226
227 dev->pg_event = MEI_PG_EVENT_IDLE;
226 dev_err(&dev->pdev->dev, "aliveness timed out\n"); 228 dev_err(&dev->pdev->dev, "aliveness timed out\n");
227 return -ETIME; 229 return -ETIME;
228} 230}
@@ -249,19 +251,22 @@ static int mei_txe_aliveness_wait(struct mei_device *dev, u32 expected)
249 return 0; 251 return 0;
250 252
251 mutex_unlock(&dev->device_lock); 253 mutex_unlock(&dev->device_lock);
252 err = wait_event_timeout(hw->wait_aliveness, 254 err = wait_event_timeout(hw->wait_aliveness_resp,
253 hw->recvd_aliveness, timeout); 255 dev->pg_event == MEI_PG_EVENT_RECEIVED, timeout);
254 mutex_lock(&dev->device_lock); 256 mutex_lock(&dev->device_lock);
255 257
256 hw->aliveness = mei_txe_aliveness_get(dev); 258 hw->aliveness = mei_txe_aliveness_get(dev);
257 ret = hw->aliveness == expected ? 0 : -ETIME; 259 ret = hw->aliveness == expected ? 0 : -ETIME;
258 260
259 if (ret) 261 if (ret)
260 dev_err(&dev->pdev->dev, "aliveness timed out"); 262 dev_warn(&dev->pdev->dev, "aliveness timed out = %ld aliveness = %d event = %d\n",
263 err, hw->aliveness, dev->pg_event);
261 else 264 else
262 dev_dbg(&dev->pdev->dev, "aliveness settled after %d msecs\n", 265 dev_dbg(&dev->pdev->dev, "aliveness settled after = %d msec aliveness = %d event = %d\n",
263 jiffies_to_msecs(timeout - err)); 266 jiffies_to_msecs(timeout - err),
264 hw->recvd_aliveness = false; 267 hw->aliveness, dev->pg_event);
268
269 dev->pg_event = MEI_PG_EVENT_IDLE;
265 return ret; 270 return ret;
266} 271}
267 272
@@ -292,6 +297,20 @@ static bool mei_txe_pg_is_enabled(struct mei_device *dev)
292} 297}
293 298
294/** 299/**
300 * mei_txe_pg_state - translate aliveness register value
301 * to the mei power gating state
302 *
303 * @dev: the device structure
304 *
305 * returns: MEI_PG_OFF if aliveness is on and MEI_PG_ON otherwise
306 */
307static inline enum mei_pg_state mei_txe_pg_state(struct mei_device *dev)
308{
309 struct mei_txe_hw *hw = to_txe_hw(dev);
310 return hw->aliveness ? MEI_PG_OFF : MEI_PG_ON;
311}
312
313/**
295 * mei_txe_input_ready_interrupt_enable - sets the Input Ready Interrupt 314 * mei_txe_input_ready_interrupt_enable - sets the Input Ready Interrupt
296 * 315 *
297 * @dev: the device structure 316 * @dev: the device structure
@@ -972,9 +991,9 @@ irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id)
972 /* Clear the interrupt cause */ 991 /* Clear the interrupt cause */
973 dev_dbg(&dev->pdev->dev, 992 dev_dbg(&dev->pdev->dev,
974 "Aliveness Interrupt: Status: %d\n", hw->aliveness); 993 "Aliveness Interrupt: Status: %d\n", hw->aliveness);
975 hw->recvd_aliveness = true; 994 dev->pg_event = MEI_PG_EVENT_RECEIVED;
976 if (waitqueue_active(&hw->wait_aliveness)) 995 if (waitqueue_active(&hw->wait_aliveness_resp))
977 wake_up(&hw->wait_aliveness); 996 wake_up(&hw->wait_aliveness_resp);
978 } 997 }
979 998
980 999
@@ -1024,6 +1043,8 @@ static const struct mei_hw_ops mei_txe_hw_ops = {
1024 1043
1025 .host_is_ready = mei_txe_host_is_ready, 1044 .host_is_ready = mei_txe_host_is_ready,
1026 1045
1046 .pg_state = mei_txe_pg_state,
1047
1027 .hw_is_ready = mei_txe_hw_is_ready, 1048 .hw_is_ready = mei_txe_hw_is_ready,
1028 .hw_reset = mei_txe_hw_reset, 1049 .hw_reset = mei_txe_hw_reset,
1029 .hw_config = mei_txe_hw_config, 1050 .hw_config = mei_txe_hw_config,
@@ -1069,7 +1090,7 @@ struct mei_device *mei_txe_dev_init(struct pci_dev *pdev)
1069 1090
1070 hw = to_txe_hw(dev); 1091 hw = to_txe_hw(dev);
1071 1092
1072 init_waitqueue_head(&hw->wait_aliveness); 1093 init_waitqueue_head(&hw->wait_aliveness_resp);
1073 1094
1074 dev->ops = &mei_txe_hw_ops; 1095 dev->ops = &mei_txe_hw_ops;
1075 1096
diff --git a/drivers/misc/mei/hw-txe.h b/drivers/misc/mei/hw-txe.h
index 0812d98633a4..799f9f25f424 100644
--- a/drivers/misc/mei/hw-txe.h
+++ b/drivers/misc/mei/hw-txe.h
@@ -35,12 +35,11 @@
35/** 35/**
36 * struct mei_txe_hw - txe hardware specifics 36 * struct mei_txe_hw - txe hardware specifics
37 * 37 *
38 * @mem_addr: SeC and BRIDGE bars 38 * @mem_addr: SeC and BRIDGE bars
39 * @aliveness: aliveness (power gating) state of the hardware 39 * @aliveness: aliveness (power gating) state of the hardware
40 * @readiness: readiness state of the hardware 40 * @readiness: readiness state of the hardware
41 * @wait_aliveness: aliveness wait queue 41 * @wait_aliveness_resp: aliveness wait queue
42 * @recvd_aliveness: aliveness interrupt was recived 42 * @intr_cause: translated interrupt cause
43 * @intr_cause: translated interrupt cause
44 */ 43 */
45struct mei_txe_hw { 44struct mei_txe_hw {
46 void __iomem *mem_addr[NUM_OF_MEM_BARS]; 45 void __iomem *mem_addr[NUM_OF_MEM_BARS];
@@ -48,8 +47,7 @@ struct mei_txe_hw {
48 u32 readiness; 47 u32 readiness;
49 u32 slots; 48 u32 slots;
50 49
51 wait_queue_head_t wait_aliveness; 50 wait_queue_head_t wait_aliveness_resp;
52 bool recvd_aliveness;
53 51
54 unsigned long intr_cause; 52 unsigned long intr_cause;
55}; 53};
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c
index cc604e1d9457..4b1eb37344cb 100644
--- a/drivers/misc/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -341,6 +341,8 @@ void mei_device_init(struct mei_device *dev)
341 * 0: Reserved for MEI Bus Message communications 341 * 0: Reserved for MEI Bus Message communications
342 */ 342 */
343 bitmap_set(dev->host_clients_map, 0, 1); 343 bitmap_set(dev->host_clients_map, 0, 1);
344
345 dev->pg_event = MEI_PG_EVENT_IDLE;
344} 346}
345EXPORT_SYMBOL_GPL(mei_device_init); 347EXPORT_SYMBOL_GPL(mei_device_init);
346 348
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index ca7581ce0722..bec6adef68bd 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -220,6 +220,7 @@ struct mei_cl {
220 * @hw_start - start hw after reset 220 * @hw_start - start hw after reset
221 * @hw_config - configure hw 221 * @hw_config - configure hw
222 222
223 * @pg_state - power gating state of the device
223 * @pg_is_enabled - is power gating enabled 224 * @pg_is_enabled - is power gating enabled
224 225
225 * @intr_clear - clear pending interrupts 226 * @intr_clear - clear pending interrupts
@@ -246,6 +247,7 @@ struct mei_hw_ops {
246 int (*hw_start)(struct mei_device *dev); 247 int (*hw_start)(struct mei_device *dev);
247 void (*hw_config)(struct mei_device *dev); 248 void (*hw_config)(struct mei_device *dev);
248 249
250 enum mei_pg_state (*pg_state)(struct mei_device *dev);
249 bool (*pg_is_enabled)(struct mei_device *dev); 251 bool (*pg_is_enabled)(struct mei_device *dev);
250 252
251 void (*intr_clear)(struct mei_device *dev); 253 void (*intr_clear)(struct mei_device *dev);
@@ -335,11 +337,37 @@ struct mei_cl_device {
335 void *priv_data; 337 void *priv_data;
336}; 338};
337 339
340
341 /**
342 * enum mei_pg_event - power gating transition events
343 *
344 * @MEI_PG_EVENT_IDLE: the driver is not in power gating transition
345 * @MEI_PG_EVENT_WAIT: the driver is waiting for a pg event to complete
346 * @MEI_PG_EVENT_RECEIVED: the driver received pg event
347 */
348enum mei_pg_event {
349 MEI_PG_EVENT_IDLE,
350 MEI_PG_EVENT_WAIT,
351 MEI_PG_EVENT_RECEIVED,
352};
353
354/**
355 * enum mei_pg_state - device internal power gating state
356 *
357 * @MEI_PG_OFF: device is not power gated - it is active
358 * @MEI_PG_ON: device is power gated - it is in lower power state
359 */
360enum mei_pg_state {
361 MEI_PG_OFF = 0,
362 MEI_PG_ON = 1,
363};
364
338/** 365/**
339 * struct mei_device - MEI private device struct 366 * struct mei_device - MEI private device struct
340 367
341 * @reset_count - limits the number of consecutive resets 368 * @reset_count - limits the number of consecutive resets
342 * @hbm_state - state of host bus message protocol 369 * @hbm_state - state of host bus message protocol
370 * @pg_event - power gating event
343 * @mem_addr - mem mapped base register address 371 * @mem_addr - mem mapped base register address
344 372
345 * @hbuf_depth - depth of hardware host/write buffer is slots 373 * @hbuf_depth - depth of hardware host/write buffer is slots
@@ -387,6 +415,11 @@ struct mei_device {
387 enum mei_hbm_state hbm_state; 415 enum mei_hbm_state hbm_state;
388 u16 init_clients_timer; 416 u16 init_clients_timer;
389 417
418 /*
419 * Power Gating support
420 */
421 enum mei_pg_event pg_event;
422
390 unsigned char rd_msg_buf[MEI_RD_MSG_BUF_SIZE]; /* control messages */ 423 unsigned char rd_msg_buf[MEI_RD_MSG_BUF_SIZE]; /* control messages */
391 u32 rd_msg_hdr; 424 u32 rd_msg_hdr;
392 425
@@ -563,6 +596,11 @@ static inline void mei_hw_config(struct mei_device *dev)
563 dev->ops->hw_config(dev); 596 dev->ops->hw_config(dev);
564} 597}
565 598
599static inline enum mei_pg_state mei_pg_state(struct mei_device *dev)
600{
601 return dev->ops->pg_state(dev);
602}
603
566static inline bool mei_pg_is_enabled(struct mei_device *dev) 604static inline bool mei_pg_is_enabled(struct mei_device *dev)
567{ 605{
568 return dev->ops->pg_is_enabled(dev); 606 return dev->ops->pg_is_enabled(dev);