unplugged-kernel/drivers/misc/mediatek/eccci/fsm/ccci_fsm_poller.c

179 lines
5.4 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2016 MediaTek Inc.
*/
#include "ccci_fsm_internal.h"
#define POLLING_INTERVAL_TIME 15000
#define POLLING_TIMEOUT 15
#define FORCE_ASSERT_TIMEOUT 15000
static int fsm_get_no_response_assert_type(struct ccci_fsm_poller *poller_ctl)
{
unsigned long long traffic_info[3] = {0};
u64 latest_isr_time = 0;
u64 latest_q0_isr_time = 0;
u64 latest_q0_rx_time = 0;
unsigned long long last_poll_time = 0;
int md_id = 0, ret = 0;
unsigned long rem_nsec0 = 0, rem_nsec1 = 0, rem_nsec2 = 0, rem_nsec3 = 0;
if (!poller_ctl)
return MD_FORCE_ASSERT_BY_MD_NO_RESPONSE;
ret = ccci_hif_dump_status(1 << MD1_NORMAL_HIF, DUMP_FLAG_GET_TRAFFIC,
traffic_info, sizeof(traffic_info));
if (!ret) {
latest_isr_time = traffic_info[0];
latest_q0_isr_time = traffic_info[1];
latest_q0_rx_time = traffic_info[2];
}
last_poll_time = poller_ctl->latest_poll_start_time;
md_id = poller_ctl->md_id;
rem_nsec0 = (last_poll_time == 0 ?
0 : do_div(last_poll_time, NSEC_PER_SEC));
rem_nsec1 = (latest_isr_time == 0 ?
0 : do_div(latest_isr_time, NSEC_PER_SEC));
rem_nsec2 = (latest_q0_isr_time == 0 ?
0 : do_div(latest_q0_isr_time, NSEC_PER_SEC));
rem_nsec3 = (latest_q0_rx_time == 0 ?
0 : do_div(latest_q0_rx_time, NSEC_PER_SEC));
CCCI_ERROR_LOG(md_id, FSM,
"polling: start=%llu.%06lu, isr=%llu.%06lu,q0_isr=%llu.%06lu, q0_rx=%llu.%06lu\n",
last_poll_time, rem_nsec0 / 1000,
latest_isr_time, rem_nsec1 / 1000,
latest_q0_isr_time, rem_nsec2 / 1000,
latest_q0_rx_time, rem_nsec3 / 1000);
/* Check whether ap received polling queue irq, after polling start */
/* send status > last q0 isr time */
if (poller_ctl->latest_poll_start_time > traffic_info[1]) {
/* send status < last isr time */
if (poller_ctl->latest_poll_start_time < traffic_info[0])
CCCI_ERROR_LOG(md_id, FSM,
"After polling start, have isr but no polling isr, maybe md no response\n");
else {
CCCI_ERROR_LOG(md_id, FSM,
"After polling start, no any irq, check ap irq status and md side send or no\n");
}
return MD_FORCE_ASSERT_BY_MD_NO_RESPONSE;
}
/* send status > last wq time, < last isr time */
if (poller_ctl->latest_poll_start_time > traffic_info[2]) {
CCCI_ERROR_LOG(md_id, FSM,
"no work after poll but isr, rx queue maybe blocked\n");
return MD_FORCE_ASSERT_BY_AP_Q0_BLOCKED;
}
CCCI_ERROR_LOG(md_id, FSM,
"AP polling isr & rx queue & kthread normally after polling start, MD may not response\n");
return MD_FORCE_ASSERT_BY_MD_NO_RESPONSE;
}
static int fsm_poll_main(void *data)
{
struct ccci_fsm_poller *poller_ctl = (struct ccci_fsm_poller *)data;
struct ccci_fsm_ctl *ctl = container_of(poller_ctl,
struct ccci_fsm_ctl, poller_ctl);
int ret, assert_md_type, count;
enum MD_STATE md_state;
while (1) {
md_state = ccci_fsm_get_md_state(poller_ctl->md_id);
if (md_state != READY
||
ccci_port_get_critical_user(poller_ctl->md_id,
CRIT_USR_MDLOG) != 1)
goto next;
poller_ctl->poller_state = FSM_POLLER_WAITING_RESPONSE;
poller_ctl->latest_poll_start_time = local_clock();
ret = ccci_port_send_msg_to_md(poller_ctl->md_id,
CCCI_STATUS_TX, 0, 0, 1);
CCCI_NORMAL_LOG(poller_ctl->md_id, FSM,
"poll MD status send msg %d\n", ret);
ret = wait_event_timeout(poller_ctl->status_rx_wq,
poller_ctl->poller_state == FSM_POLLER_RECEIVED_RESPONSE,
POLLING_TIMEOUT * HZ);
CCCI_NORMAL_LOG(poller_ctl->md_id, FSM,
"poll MD status wait done %d\n", ret);
if (!ret) { /* timeout */
md_state = ccci_fsm_get_md_state(poller_ctl->md_id);
if (md_state == READY) {
CCCI_ERROR_LOG(poller_ctl->md_id, FSM,
"poll MD status timeout, force assert\n");
assert_md_type =
fsm_get_no_response_assert_type(poller_ctl);
if (assert_md_type
== MD_FORCE_ASSERT_BY_MD_NO_RESPONSE)
ccci_md_dump_info(poller_ctl->md_id,
DUMP_FLAG_IRQ_STATUS, NULL, 0);
ccci_md_dump_info(poller_ctl->md_id,
DUMP_FLAG_QUEUE_0, NULL, 0);
ccci_md_force_assert(poller_ctl->md_id,
assert_md_type, NULL, 0);
count = 0;
while (count < FORCE_ASSERT_TIMEOUT / 200) {
if (ccci_fsm_get_md_state(
poller_ctl->md_id)
== EXCEPTION) {
count = 0;
break;
}
count++;
msleep(200);
}
if (count) {
CCCI_ERROR_LOG(poller_ctl->md_id, FSM,
"MD long time no response\n");
ccci_md_dump_info(poller_ctl->md_id,
DUMP_FLAG_QUEUE_0, NULL, 0);
fsm_append_command(ctl,
CCCI_COMMAND_MD_HANG, 0);
}
}
}
next:
msleep(POLLING_INTERVAL_TIME);
}
return 0;
}
int fsm_poller_init(struct ccci_fsm_poller *poller_ctl)
{
struct ccci_fsm_ctl *ctl = container_of(poller_ctl,
struct ccci_fsm_ctl, poller_ctl);
init_waitqueue_head(&poller_ctl->status_rx_wq);
poller_ctl->md_id = ctl->md_id;
poller_ctl->poll_thread = kthread_run(fsm_poll_main, poller_ctl,
"ccci_poll%d", poller_ctl->md_id + 1);
return 0;
}
int ccci_fsm_recv_status_packet(int md_id, struct sk_buff *skb)
{
struct ccci_fsm_ctl *ctl = fsm_get_entity_by_md_id(md_id);
struct ccci_fsm_poller *poller_ctl;
if (!ctl)
return -CCCI_ERR_INVALID_PARAM;
poller_ctl = &ctl->poller_ctl;
CCCI_NORMAL_LOG(poller_ctl->md_id, FSM,
"received MD status response %x\n", *(((u32 *)skb->data) + 2));
/*
* ccci_util_cmpt_mem_dump(poller_ctl->md_id,
* CCCI_DUMP_REPEAT, skb->data, skb->len);
*/
poller_ctl->poller_state = FSM_POLLER_RECEIVED_RESPONSE;
wake_up(&poller_ctl->status_rx_wq);
ccci_free_skb(skb);
return 0;
}