Commit ad914a3e authored by Dongxiao Xu's avatar Dongxiao Xu Committed by Greg Kroah-Hartman

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: default avatarDongxiao Xu <dongxiao.xu@intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 52b85560
...@@ -249,7 +249,7 @@ int heci_hw_init(struct iamt_heci_device *dev) ...@@ -249,7 +249,7 @@ int heci_hw_init(struct iamt_heci_device *dev)
if ((dev->host_hw_state & H_IS) == H_IS) { if ((dev->host_hw_state & H_IS) == H_IS) {
/* acknowledge interrupt and stop interupts */ /* acknowledge interrupt and stop interupts */
heci_set_csr_register(dev); heci_csr_clear_his(dev);
} }
dev->recvd_msg = 0; dev->recvd_msg = 0;
DBG("reset in start the heci device.\n"); DBG("reset in start the heci device.\n");
...@@ -354,7 +354,7 @@ void heci_reset(struct iamt_heci_device *dev, int interrupts) ...@@ -354,7 +354,7 @@ void heci_reset(struct iamt_heci_device *dev, int interrupts)
dev->host_hw_state &= ~H_RST; dev->host_hw_state &= ~H_RST;
dev->host_hw_state |= H_IG; dev->host_hw_state |= H_IG;
write_heci_register(dev, H_CSR, dev->host_hw_state); heci_set_csr_register(dev);
DBG("currently saved host_hw_state = 0x%08x.\n", DBG("currently saved host_hw_state = 0x%08x.\n",
dev->host_hw_state); dev->host_hw_state);
......
...@@ -44,12 +44,15 @@ ...@@ -44,12 +44,15 @@
/** /**
* heci_set_csr_register - write H_CSR register to the heci device * heci_set_csr_register - write H_CSR register to the heci device,
* and ignore the H_IS bit for it is write-one-to-zero.
* *
* @dev: device object for our driver * @dev: device object for our driver
*/ */
void heci_set_csr_register(struct iamt_heci_device *dev) void heci_set_csr_register(struct iamt_heci_device *dev)
{ {
if ((dev->host_hw_state & H_IS) == H_IS)
dev->host_hw_state &= ~H_IS;
write_heci_register(dev, H_CSR, dev->host_hw_state); write_heci_register(dev, H_CSR, dev->host_hw_state);
dev->host_hw_state = read_heci_register(dev, H_CSR); dev->host_hw_state = read_heci_register(dev, H_CSR);
} }
...@@ -76,6 +79,16 @@ void heci_csr_disable_interrupts(struct iamt_heci_device *dev) ...@@ -76,6 +79,16 @@ void heci_csr_disable_interrupts(struct iamt_heci_device *dev)
heci_set_csr_register(dev); heci_set_csr_register(dev);
} }
/**
* heci_csr_clear_his - clear H_IS bit in H_CSR
*
* @dev: device object for our driver
*/
void heci_csr_clear_his(struct iamt_heci_device *dev)
{
write_heci_register(dev, H_CSR, dev->host_hw_state);
dev->host_hw_state = read_heci_register(dev, H_CSR);
}
/** /**
* _host_get_filled_slots - get number of device filled buffer slots * _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,7 +198,7 @@ int heci_write_message(struct iamt_heci_device *dev,
} }
dev->host_hw_state |= H_IG; dev->host_hw_state |= H_IG;
write_heci_register(dev, H_CSR, dev->host_hw_state); heci_set_csr_register(dev);
dev->me_hw_state = read_heci_register(dev, ME_CSR_HA); dev->me_hw_state = read_heci_register(dev, ME_CSR_HA);
if ((dev->me_hw_state & ME_RDY_HRA) != ME_RDY_HRA) if ((dev->me_hw_state & ME_RDY_HRA) != ME_RDY_HRA)
return 0; return 0;
......
...@@ -133,6 +133,7 @@ enum client_disconnect_status_types{ ...@@ -133,6 +133,7 @@ enum client_disconnect_status_types{
void heci_set_csr_register(struct iamt_heci_device *dev); void heci_set_csr_register(struct iamt_heci_device *dev);
void heci_csr_enable_interrupts(struct iamt_heci_device *dev); void heci_csr_enable_interrupts(struct iamt_heci_device *dev);
void heci_csr_disable_interrupts(struct iamt_heci_device *dev); void heci_csr_disable_interrupts(struct iamt_heci_device *dev);
void heci_csr_clear_his(struct iamt_heci_device *dev);
void heci_read_slots(struct iamt_heci_device *dev, void heci_read_slots(struct iamt_heci_device *dev,
unsigned char *buffer, unsigned long buffer_length); unsigned char *buffer, unsigned long buffer_length);
......
...@@ -92,6 +92,9 @@ irqreturn_t heci_isr_interrupt(int irq, void *dev_id) ...@@ -92,6 +92,9 @@ irqreturn_t heci_isr_interrupt(int irq, void *dev_id)
/* disable interrupts */ /* disable interrupts */
heci_csr_disable_interrupts(dev); heci_csr_disable_interrupts(dev);
/* clear H_IS bit in H_CSR */
heci_csr_clear_his(dev);
/* /*
* Our device interrupted, schedule work the heci_bh_handler * Our device interrupted, schedule work the heci_bh_handler
* to handle the interrupt processing. This needs to be a * to handle the interrupt processing. This needs to be a
...@@ -251,6 +254,9 @@ static void heci_bh_handler(struct work_struct *work) ...@@ -251,6 +254,9 @@ static void heci_bh_handler(struct work_struct *work)
/* acknowledge interrupt and disable interrupts */ /* acknowledge interrupt and disable interrupts */
heci_csr_disable_interrupts(dev); heci_csr_disable_interrupts(dev);
/* clear H_IS bit in H_CSR */
heci_csr_clear_his(dev);
PREPARE_WORK(&dev->work, heci_bh_handler); PREPARE_WORK(&dev->work, heci_bh_handler);
DBG("schedule work the heci_bh_handler.\n"); DBG("schedule work the heci_bh_handler.\n");
rets = schedule_work(&dev->work); rets = schedule_work(&dev->work);
......
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