diff options
Diffstat (limited to 'drivers/misc')
-rw-r--r-- | drivers/misc/mei/hbm.c | 19 | ||||
-rw-r--r-- | drivers/misc/mei/hbm.h | 1 | ||||
-rw-r--r-- | drivers/misc/mei/init.c | 12 | ||||
-rw-r--r-- | drivers/misc/mei/interrupt.c | 25 |
4 files changed, 43 insertions, 14 deletions
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c index 8109b9a98cc3..836f92db7983 100644 --- a/drivers/misc/mei/hbm.c +++ b/drivers/misc/mei/hbm.c | |||
@@ -126,6 +126,17 @@ static bool is_treat_specially_client(struct mei_cl *cl, | |||
126 | return false; | 126 | return false; |
127 | } | 127 | } |
128 | 128 | ||
129 | /** | ||
130 | * mei_hbm_idle - set hbm to idle state | ||
131 | * | ||
132 | * @dev: the device structure | ||
133 | */ | ||
134 | void mei_hbm_idle(struct mei_device *dev) | ||
135 | { | ||
136 | dev->init_clients_timer = 0; | ||
137 | dev->hbm_state = MEI_HBM_IDLE; | ||
138 | } | ||
139 | |||
129 | int mei_hbm_start_wait(struct mei_device *dev) | 140 | int mei_hbm_start_wait(struct mei_device *dev) |
130 | { | 141 | { |
131 | int ret; | 142 | int ret; |
@@ -583,6 +594,14 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) | |||
583 | mei_read_slots(dev, dev->rd_msg_buf, hdr->length); | 594 | mei_read_slots(dev, dev->rd_msg_buf, hdr->length); |
584 | mei_msg = (struct mei_bus_message *)dev->rd_msg_buf; | 595 | mei_msg = (struct mei_bus_message *)dev->rd_msg_buf; |
585 | 596 | ||
597 | /* ignore spurious message and prevent reset nesting | ||
598 | * hbm is put to idle during system reset | ||
599 | */ | ||
600 | if (dev->hbm_state == MEI_HBM_IDLE) { | ||
601 | dev_dbg(&dev->pdev->dev, "hbm: state is idle ignore spurious messages\n"); | ||
602 | return 0; | ||
603 | } | ||
604 | |||
586 | switch (mei_msg->hbm_cmd) { | 605 | switch (mei_msg->hbm_cmd) { |
587 | case HOST_START_RES_CMD: | 606 | case HOST_START_RES_CMD: |
588 | dev_dbg(&dev->pdev->dev, "hbm: start: response message received.\n"); | 607 | dev_dbg(&dev->pdev->dev, "hbm: start: response message received.\n"); |
diff --git a/drivers/misc/mei/hbm.h b/drivers/misc/mei/hbm.h index f2540fff7080..5f92188a5cd7 100644 --- a/drivers/misc/mei/hbm.h +++ b/drivers/misc/mei/hbm.h | |||
@@ -49,6 +49,7 @@ static inline void mei_hbm_hdr(struct mei_msg_hdr *hdr, size_t length) | |||
49 | hdr->reserved = 0; | 49 | hdr->reserved = 0; |
50 | } | 50 | } |
51 | 51 | ||
52 | void mei_hbm_idle(struct mei_device *dev); | ||
52 | int mei_hbm_start_req(struct mei_device *dev); | 53 | int mei_hbm_start_req(struct mei_device *dev); |
53 | int mei_hbm_start_wait(struct mei_device *dev); | 54 | int mei_hbm_start_wait(struct mei_device *dev); |
54 | int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl); | 55 | int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl); |
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index 87c077bae5d8..c47fa273879e 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c | |||
@@ -129,14 +129,19 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled) | |||
129 | dev_warn(&dev->pdev->dev, "unexpected reset: dev_state = %s\n", | 129 | dev_warn(&dev->pdev->dev, "unexpected reset: dev_state = %s\n", |
130 | mei_dev_state_str(dev->dev_state)); | 130 | mei_dev_state_str(dev->dev_state)); |
131 | 131 | ||
132 | /* we're already in reset, cancel the init timer | ||
133 | * if the reset was called due the hbm protocol error | ||
134 | * we need to call it before hw start | ||
135 | * so the hbm watchdog won't kick in | ||
136 | */ | ||
137 | mei_hbm_idle(dev); | ||
138 | |||
132 | ret = mei_hw_reset(dev, interrupts_enabled); | 139 | ret = mei_hw_reset(dev, interrupts_enabled); |
133 | if (ret) { | 140 | if (ret) { |
134 | dev_err(&dev->pdev->dev, "hw reset failed disabling the device\n"); | 141 | dev_err(&dev->pdev->dev, "hw reset failed disabling the device\n"); |
135 | interrupts_enabled = false; | 142 | interrupts_enabled = false; |
136 | dev->dev_state = MEI_DEV_DISABLED; | ||
137 | } | 143 | } |
138 | 144 | ||
139 | dev->hbm_state = MEI_HBM_IDLE; | ||
140 | 145 | ||
141 | if (dev->dev_state != MEI_DEV_INITIALIZING && | 146 | if (dev->dev_state != MEI_DEV_INITIALIZING && |
142 | dev->dev_state != MEI_DEV_POWER_UP) { | 147 | dev->dev_state != MEI_DEV_POWER_UP) { |
@@ -160,8 +165,6 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled) | |||
160 | memset(&dev->wr_ext_msg, 0, sizeof(dev->wr_ext_msg)); | 165 | memset(&dev->wr_ext_msg, 0, sizeof(dev->wr_ext_msg)); |
161 | } | 166 | } |
162 | 167 | ||
163 | /* we're already in reset, cancel the init timer */ | ||
164 | dev->init_clients_timer = 0; | ||
165 | 168 | ||
166 | dev->me_clients_num = 0; | 169 | dev->me_clients_num = 0; |
167 | dev->rd_msg_hdr = 0; | 170 | dev->rd_msg_hdr = 0; |
@@ -169,6 +172,7 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled) | |||
169 | 172 | ||
170 | if (!interrupts_enabled) { | 173 | if (!interrupts_enabled) { |
171 | dev_dbg(&dev->pdev->dev, "intr not enabled end of reset\n"); | 174 | dev_dbg(&dev->pdev->dev, "intr not enabled end of reset\n"); |
175 | dev->dev_state = MEI_DEV_DISABLED; | ||
172 | return; | 176 | return; |
173 | } | 177 | } |
174 | 178 | ||
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index bbb61bec863b..206dbe99bedd 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c | |||
@@ -537,7 +537,6 @@ EXPORT_SYMBOL_GPL(mei_irq_write_handler); | |||
537 | * | 537 | * |
538 | * @work: pointer to the work_struct structure | 538 | * @work: pointer to the work_struct structure |
539 | * | 539 | * |
540 | * NOTE: This function is called by timer interrupt work | ||
541 | */ | 540 | */ |
542 | void mei_timer(struct work_struct *work) | 541 | void mei_timer(struct work_struct *work) |
543 | { | 542 | { |
@@ -552,18 +551,24 @@ void mei_timer(struct work_struct *work) | |||
552 | 551 | ||
553 | 552 | ||
554 | mutex_lock(&dev->device_lock); | 553 | mutex_lock(&dev->device_lock); |
555 | if (dev->dev_state != MEI_DEV_ENABLED) { | 554 | |
556 | if (dev->dev_state == MEI_DEV_INIT_CLIENTS) { | 555 | /* Catch interrupt stalls during HBM init handshake */ |
557 | if (dev->init_clients_timer) { | 556 | if (dev->dev_state == MEI_DEV_INIT_CLIENTS && |
558 | if (--dev->init_clients_timer == 0) { | 557 | dev->hbm_state != MEI_HBM_IDLE) { |
559 | dev_err(&dev->pdev->dev, "reset: init clients timeout hbm_state = %d.\n", | 558 | |
560 | dev->hbm_state); | 559 | if (dev->init_clients_timer) { |
561 | mei_reset(dev, 1); | 560 | if (--dev->init_clients_timer == 0) { |
562 | } | 561 | dev_err(&dev->pdev->dev, "timer: init clients timeout hbm_state = %d.\n", |
562 | dev->hbm_state); | ||
563 | mei_reset(dev, 1); | ||
564 | goto out; | ||
563 | } | 565 | } |
564 | } | 566 | } |
565 | goto out; | ||
566 | } | 567 | } |
568 | |||
569 | if (dev->dev_state != MEI_DEV_ENABLED) | ||
570 | goto out; | ||
571 | |||
567 | /*** connect/disconnect timeouts ***/ | 572 | /*** connect/disconnect timeouts ***/ |
568 | list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) { | 573 | list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) { |
569 | if (cl_pos->timer_count) { | 574 | if (cl_pos->timer_count) { |