aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDongxiao Xu <dongxiao.xu@intel.com>2009-05-31 02:43:55 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2009-06-19 14:00:55 -0400
commitad914a3ec5f1b8c4f97a00f94e11bb20f99a901b (patch)
treed6356f54d46b846557dbb224b30ec8a11800d4d2
parent52b855600c5c16c13b6f288f3536d01c2603e78d (diff)
Staging: heci: fix setting h_is bit in h_csr register
Host software could issue interrupts to ME firmware, using H_IG bit. While Setting H_IG bit, host software should preserve all the other bits in H_CSR unchanged. In the original function which sets H_CSR register, they first read the register, then set some bits, and write the whole 32bits back to the register. And that the special behavior of H_IS (write-one-to-zero) causes problem. This patch fixes the issue in the following ways: - Modify heci_set_csr_register() function so that it doesn't change H_IS bit. - Add interface heci_csr_clear_his() to clear H_IS bit. This function is called after H_IS checking (dev->host_hw_state & H_IS == H_IS). - In original heci_csr_disable_interrupts() function, it not only clears H_IE bit, sometimes it also clears H_IS bit. This patch separates the two parts. - Avoid calling write_heci_register() function to set H_CSR register directly, and instead using heci_set_csr_register() function Signed-off-by: Dongxiao Xu <dongxiao.xu@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/staging/heci/heci_init.c4
-rw-r--r--drivers/staging/heci/heci_interface.c17
-rw-r--r--drivers/staging/heci/heci_interface.h1
-rw-r--r--drivers/staging/heci/interrupt.c6
4 files changed, 24 insertions, 4 deletions
diff --git a/drivers/staging/heci/heci_init.c b/drivers/staging/heci/heci_init.c
index 06ea1967e0e3..427f55d7b262 100644
--- a/drivers/staging/heci/heci_init.c
+++ b/drivers/staging/heci/heci_init.c
@@ -249,7 +249,7 @@ int heci_hw_init(struct iamt_heci_device *dev)
249 249
250 if ((dev->host_hw_state & H_IS) == H_IS) { 250 if ((dev->host_hw_state & H_IS) == H_IS) {
251 /* acknowledge interrupt and stop interupts */ 251 /* acknowledge interrupt and stop interupts */
252 heci_set_csr_register(dev); 252 heci_csr_clear_his(dev);
253 } 253 }
254 dev->recvd_msg = 0; 254 dev->recvd_msg = 0;
255 DBG("reset in start the heci device.\n"); 255 DBG("reset in start the heci device.\n");
@@ -354,7 +354,7 @@ void heci_reset(struct iamt_heci_device *dev, int interrupts)
354 dev->host_hw_state &= ~H_RST; 354 dev->host_hw_state &= ~H_RST;
355 dev->host_hw_state |= H_IG; 355 dev->host_hw_state |= H_IG;
356 356
357 write_heci_register(dev, H_CSR, dev->host_hw_state); 357 heci_set_csr_register(dev);
358 358
359 DBG("currently saved host_hw_state = 0x%08x.\n", 359 DBG("currently saved host_hw_state = 0x%08x.\n",
360 dev->host_hw_state); 360 dev->host_hw_state);
diff --git a/drivers/staging/heci/heci_interface.c b/drivers/staging/heci/heci_interface.c
index c5f51a7ddf2c..03e1df1a88a0 100644
--- a/drivers/staging/heci/heci_interface.c
+++ b/drivers/staging/heci/heci_interface.c
@@ -44,12 +44,15 @@
44 44
45 45
46/** 46/**
47 * heci_set_csr_register - write H_CSR register to the heci device 47 * heci_set_csr_register - write H_CSR register to the heci device,
48 * and ignore the H_IS bit for it is write-one-to-zero.
48 * 49 *
49 * @dev: device object for our driver 50 * @dev: device object for our driver
50 */ 51 */
51void heci_set_csr_register(struct iamt_heci_device *dev) 52void heci_set_csr_register(struct iamt_heci_device *dev)
52{ 53{
54 if ((dev->host_hw_state & H_IS) == H_IS)
55 dev->host_hw_state &= ~H_IS;
53 write_heci_register(dev, H_CSR, dev->host_hw_state); 56 write_heci_register(dev, H_CSR, dev->host_hw_state);
54 dev->host_hw_state = read_heci_register(dev, H_CSR); 57 dev->host_hw_state = read_heci_register(dev, H_CSR);
55} 58}
@@ -76,6 +79,16 @@ void heci_csr_disable_interrupts(struct iamt_heci_device *dev)
76 heci_set_csr_register(dev); 79 heci_set_csr_register(dev);
77} 80}
78 81
82/**
83 * heci_csr_clear_his - clear H_IS bit in H_CSR
84 *
85 * @dev: device object for our driver
86 */
87void heci_csr_clear_his(struct iamt_heci_device *dev)
88{
89 write_heci_register(dev, H_CSR, dev->host_hw_state);
90 dev->host_hw_state = read_heci_register(dev, H_CSR);
91}
79 92
80/** 93/**
81 * _host_get_filled_slots - get number of device filled buffer slots 94 * _host_get_filled_slots - get number of device filled buffer slots
@@ -185,7 +198,7 @@ int heci_write_message(struct iamt_heci_device *dev,
185 } 198 }
186 199
187 dev->host_hw_state |= H_IG; 200 dev->host_hw_state |= H_IG;
188 write_heci_register(dev, H_CSR, dev->host_hw_state); 201 heci_set_csr_register(dev);
189 dev->me_hw_state = read_heci_register(dev, ME_CSR_HA); 202 dev->me_hw_state = read_heci_register(dev, ME_CSR_HA);
190 if ((dev->me_hw_state & ME_RDY_HRA) != ME_RDY_HRA) 203 if ((dev->me_hw_state & ME_RDY_HRA) != ME_RDY_HRA)
191 return 0; 204 return 0;
diff --git a/drivers/staging/heci/heci_interface.h b/drivers/staging/heci/heci_interface.h
index d9193cf6d9e9..34db7e52b8ef 100644
--- a/drivers/staging/heci/heci_interface.h
+++ b/drivers/staging/heci/heci_interface.h
@@ -133,6 +133,7 @@ enum client_disconnect_status_types{
133void heci_set_csr_register(struct iamt_heci_device *dev); 133void heci_set_csr_register(struct iamt_heci_device *dev);
134void heci_csr_enable_interrupts(struct iamt_heci_device *dev); 134void heci_csr_enable_interrupts(struct iamt_heci_device *dev);
135void heci_csr_disable_interrupts(struct iamt_heci_device *dev); 135void heci_csr_disable_interrupts(struct iamt_heci_device *dev);
136void heci_csr_clear_his(struct iamt_heci_device *dev);
136 137
137void heci_read_slots(struct iamt_heci_device *dev, 138void heci_read_slots(struct iamt_heci_device *dev,
138 unsigned char *buffer, unsigned long buffer_length); 139 unsigned char *buffer, unsigned long buffer_length);
diff --git a/drivers/staging/heci/interrupt.c b/drivers/staging/heci/interrupt.c
index b7ce73be8265..3a510ed3a3d2 100644
--- a/drivers/staging/heci/interrupt.c
+++ b/drivers/staging/heci/interrupt.c
@@ -92,6 +92,9 @@ irqreturn_t heci_isr_interrupt(int irq, void *dev_id)
92 /* disable interrupts */ 92 /* disable interrupts */
93 heci_csr_disable_interrupts(dev); 93 heci_csr_disable_interrupts(dev);
94 94
95 /* clear H_IS bit in H_CSR */
96 heci_csr_clear_his(dev);
97
95 /* 98 /*
96 * Our device interrupted, schedule work the heci_bh_handler 99 * Our device interrupted, schedule work the heci_bh_handler
97 * to handle the interrupt processing. This needs to be a 100 * to handle the interrupt processing. This needs to be a
@@ -251,6 +254,9 @@ end:
251 /* acknowledge interrupt and disable interrupts */ 254 /* acknowledge interrupt and disable interrupts */
252 heci_csr_disable_interrupts(dev); 255 heci_csr_disable_interrupts(dev);
253 256
257 /* clear H_IS bit in H_CSR */
258 heci_csr_clear_his(dev);
259
254 PREPARE_WORK(&dev->work, heci_bh_handler); 260 PREPARE_WORK(&dev->work, heci_bh_handler);
255 DBG("schedule work the heci_bh_handler.\n"); 261 DBG("schedule work the heci_bh_handler.\n");
256 rets = schedule_work(&dev->work); 262 rets = schedule_work(&dev->work);