18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright IBM Corp. 2016 48c2ecf20Sopenharmony_ci * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Adjunct processor bus, queue related code. 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#define KMSG_COMPONENT "ap" 108c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/init.h> 138c2ecf20Sopenharmony_ci#include <linux/slab.h> 148c2ecf20Sopenharmony_ci#include <asm/facility.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include "ap_bus.h" 178c2ecf20Sopenharmony_ci#include "ap_debug.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic void __ap_flush_queue(struct ap_queue *aq); 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/** 228c2ecf20Sopenharmony_ci * ap_queue_enable_irq(): Enable interrupt support on this AP queue. 238c2ecf20Sopenharmony_ci * @qid: The AP queue number 248c2ecf20Sopenharmony_ci * @ind: the notification indicator byte 258c2ecf20Sopenharmony_ci * 268c2ecf20Sopenharmony_ci * Enables interruption on AP queue via ap_aqic(). Based on the return 278c2ecf20Sopenharmony_ci * value it waits a while and tests the AP queue if interrupts 288c2ecf20Sopenharmony_ci * have been switched on using ap_test_queue(). 298c2ecf20Sopenharmony_ci */ 308c2ecf20Sopenharmony_cistatic int ap_queue_enable_irq(struct ap_queue *aq, void *ind) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci struct ap_queue_status status; 338c2ecf20Sopenharmony_ci struct ap_qirq_ctrl qirqctrl = { 0 }; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci qirqctrl.ir = 1; 368c2ecf20Sopenharmony_ci qirqctrl.isc = AP_ISC; 378c2ecf20Sopenharmony_ci status = ap_aqic(aq->qid, qirqctrl, ind); 388c2ecf20Sopenharmony_ci switch (status.response_code) { 398c2ecf20Sopenharmony_ci case AP_RESPONSE_NORMAL: 408c2ecf20Sopenharmony_ci case AP_RESPONSE_OTHERWISE_CHANGED: 418c2ecf20Sopenharmony_ci return 0; 428c2ecf20Sopenharmony_ci case AP_RESPONSE_Q_NOT_AVAIL: 438c2ecf20Sopenharmony_ci case AP_RESPONSE_DECONFIGURED: 448c2ecf20Sopenharmony_ci case AP_RESPONSE_CHECKSTOPPED: 458c2ecf20Sopenharmony_ci case AP_RESPONSE_INVALID_ADDRESS: 468c2ecf20Sopenharmony_ci pr_err("Registering adapter interrupts for AP device %02x.%04x failed\n", 478c2ecf20Sopenharmony_ci AP_QID_CARD(aq->qid), 488c2ecf20Sopenharmony_ci AP_QID_QUEUE(aq->qid)); 498c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 508c2ecf20Sopenharmony_ci case AP_RESPONSE_RESET_IN_PROGRESS: 518c2ecf20Sopenharmony_ci case AP_RESPONSE_BUSY: 528c2ecf20Sopenharmony_ci default: 538c2ecf20Sopenharmony_ci return -EBUSY; 548c2ecf20Sopenharmony_ci } 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci/** 588c2ecf20Sopenharmony_ci * __ap_send(): Send message to adjunct processor queue. 598c2ecf20Sopenharmony_ci * @qid: The AP queue number 608c2ecf20Sopenharmony_ci * @psmid: The program supplied message identifier 618c2ecf20Sopenharmony_ci * @msg: The message text 628c2ecf20Sopenharmony_ci * @length: The message length 638c2ecf20Sopenharmony_ci * @special: Special Bit 648c2ecf20Sopenharmony_ci * 658c2ecf20Sopenharmony_ci * Returns AP queue status structure. 668c2ecf20Sopenharmony_ci * Condition code 1 on NQAP can't happen because the L bit is 1. 678c2ecf20Sopenharmony_ci * Condition code 2 on NQAP also means the send is incomplete, 688c2ecf20Sopenharmony_ci * because a segment boundary was reached. The NQAP is repeated. 698c2ecf20Sopenharmony_ci */ 708c2ecf20Sopenharmony_cistatic inline struct ap_queue_status 718c2ecf20Sopenharmony_ci__ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length, 728c2ecf20Sopenharmony_ci int special) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci if (special) 758c2ecf20Sopenharmony_ci qid |= 0x400000UL; 768c2ecf20Sopenharmony_ci return ap_nqap(qid, psmid, msg, length); 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ciint ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci struct ap_queue_status status; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci status = __ap_send(qid, psmid, msg, length, 0); 848c2ecf20Sopenharmony_ci switch (status.response_code) { 858c2ecf20Sopenharmony_ci case AP_RESPONSE_NORMAL: 868c2ecf20Sopenharmony_ci return 0; 878c2ecf20Sopenharmony_ci case AP_RESPONSE_Q_FULL: 888c2ecf20Sopenharmony_ci case AP_RESPONSE_RESET_IN_PROGRESS: 898c2ecf20Sopenharmony_ci return -EBUSY; 908c2ecf20Sopenharmony_ci case AP_RESPONSE_REQ_FAC_NOT_INST: 918c2ecf20Sopenharmony_ci return -EINVAL; 928c2ecf20Sopenharmony_ci default: /* Device is gone. */ 938c2ecf20Sopenharmony_ci return -ENODEV; 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ap_send); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ciint ap_recv(ap_qid_t qid, unsigned long long *psmid, void *msg, size_t length) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci struct ap_queue_status status; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci if (msg == NULL) 1038c2ecf20Sopenharmony_ci return -EINVAL; 1048c2ecf20Sopenharmony_ci status = ap_dqap(qid, psmid, msg, length); 1058c2ecf20Sopenharmony_ci switch (status.response_code) { 1068c2ecf20Sopenharmony_ci case AP_RESPONSE_NORMAL: 1078c2ecf20Sopenharmony_ci return 0; 1088c2ecf20Sopenharmony_ci case AP_RESPONSE_NO_PENDING_REPLY: 1098c2ecf20Sopenharmony_ci if (status.queue_empty) 1108c2ecf20Sopenharmony_ci return -ENOENT; 1118c2ecf20Sopenharmony_ci return -EBUSY; 1128c2ecf20Sopenharmony_ci case AP_RESPONSE_RESET_IN_PROGRESS: 1138c2ecf20Sopenharmony_ci return -EBUSY; 1148c2ecf20Sopenharmony_ci default: 1158c2ecf20Sopenharmony_ci return -ENODEV; 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ap_recv); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci/* State machine definitions and helpers */ 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic enum ap_sm_wait ap_sm_nop(struct ap_queue *aq) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci return AP_SM_WAIT_NONE; 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci/** 1288c2ecf20Sopenharmony_ci * ap_sm_recv(): Receive pending reply messages from an AP queue but do 1298c2ecf20Sopenharmony_ci * not change the state of the device. 1308c2ecf20Sopenharmony_ci * @aq: pointer to the AP queue 1318c2ecf20Sopenharmony_ci * 1328c2ecf20Sopenharmony_ci * Returns AP_SM_WAIT_NONE, AP_SM_WAIT_AGAIN, or AP_SM_WAIT_INTERRUPT 1338c2ecf20Sopenharmony_ci */ 1348c2ecf20Sopenharmony_cistatic struct ap_queue_status ap_sm_recv(struct ap_queue *aq) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci struct ap_queue_status status; 1378c2ecf20Sopenharmony_ci struct ap_message *ap_msg; 1388c2ecf20Sopenharmony_ci bool found = false; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci status = ap_dqap(aq->qid, &aq->reply->psmid, 1418c2ecf20Sopenharmony_ci aq->reply->msg, aq->reply->len); 1428c2ecf20Sopenharmony_ci switch (status.response_code) { 1438c2ecf20Sopenharmony_ci case AP_RESPONSE_NORMAL: 1448c2ecf20Sopenharmony_ci aq->queue_count = max_t(int, 0, aq->queue_count - 1); 1458c2ecf20Sopenharmony_ci if (!status.queue_empty && !aq->queue_count) 1468c2ecf20Sopenharmony_ci aq->queue_count++; 1478c2ecf20Sopenharmony_ci if (aq->queue_count > 0) 1488c2ecf20Sopenharmony_ci mod_timer(&aq->timeout, 1498c2ecf20Sopenharmony_ci jiffies + aq->request_timeout); 1508c2ecf20Sopenharmony_ci list_for_each_entry(ap_msg, &aq->pendingq, list) { 1518c2ecf20Sopenharmony_ci if (ap_msg->psmid != aq->reply->psmid) 1528c2ecf20Sopenharmony_ci continue; 1538c2ecf20Sopenharmony_ci list_del_init(&ap_msg->list); 1548c2ecf20Sopenharmony_ci aq->pendingq_count--; 1558c2ecf20Sopenharmony_ci ap_msg->receive(aq, ap_msg, aq->reply); 1568c2ecf20Sopenharmony_ci found = true; 1578c2ecf20Sopenharmony_ci break; 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci if (!found) { 1608c2ecf20Sopenharmony_ci AP_DBF_WARN("%s unassociated reply psmid=0x%016llx on 0x%02x.%04x\n", 1618c2ecf20Sopenharmony_ci __func__, aq->reply->psmid, 1628c2ecf20Sopenharmony_ci AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid)); 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci fallthrough; 1658c2ecf20Sopenharmony_ci case AP_RESPONSE_NO_PENDING_REPLY: 1668c2ecf20Sopenharmony_ci if (!status.queue_empty || aq->queue_count <= 0) 1678c2ecf20Sopenharmony_ci break; 1688c2ecf20Sopenharmony_ci /* The card shouldn't forget requests but who knows. */ 1698c2ecf20Sopenharmony_ci aq->queue_count = 0; 1708c2ecf20Sopenharmony_ci list_splice_init(&aq->pendingq, &aq->requestq); 1718c2ecf20Sopenharmony_ci aq->requestq_count += aq->pendingq_count; 1728c2ecf20Sopenharmony_ci aq->pendingq_count = 0; 1738c2ecf20Sopenharmony_ci break; 1748c2ecf20Sopenharmony_ci default: 1758c2ecf20Sopenharmony_ci break; 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci return status; 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci/** 1818c2ecf20Sopenharmony_ci * ap_sm_read(): Receive pending reply messages from an AP queue. 1828c2ecf20Sopenharmony_ci * @aq: pointer to the AP queue 1838c2ecf20Sopenharmony_ci * 1848c2ecf20Sopenharmony_ci * Returns AP_SM_WAIT_NONE, AP_SM_WAIT_AGAIN, or AP_SM_WAIT_INTERRUPT 1858c2ecf20Sopenharmony_ci */ 1868c2ecf20Sopenharmony_cistatic enum ap_sm_wait ap_sm_read(struct ap_queue *aq) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci struct ap_queue_status status; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci if (!aq->reply) 1918c2ecf20Sopenharmony_ci return AP_SM_WAIT_NONE; 1928c2ecf20Sopenharmony_ci status = ap_sm_recv(aq); 1938c2ecf20Sopenharmony_ci switch (status.response_code) { 1948c2ecf20Sopenharmony_ci case AP_RESPONSE_NORMAL: 1958c2ecf20Sopenharmony_ci if (aq->queue_count > 0) { 1968c2ecf20Sopenharmony_ci aq->sm_state = AP_SM_STATE_WORKING; 1978c2ecf20Sopenharmony_ci return AP_SM_WAIT_AGAIN; 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci aq->sm_state = AP_SM_STATE_IDLE; 2008c2ecf20Sopenharmony_ci return AP_SM_WAIT_NONE; 2018c2ecf20Sopenharmony_ci case AP_RESPONSE_NO_PENDING_REPLY: 2028c2ecf20Sopenharmony_ci if (aq->queue_count > 0) 2038c2ecf20Sopenharmony_ci return aq->interrupt ? 2048c2ecf20Sopenharmony_ci AP_SM_WAIT_INTERRUPT : AP_SM_WAIT_TIMEOUT; 2058c2ecf20Sopenharmony_ci aq->sm_state = AP_SM_STATE_IDLE; 2068c2ecf20Sopenharmony_ci return AP_SM_WAIT_NONE; 2078c2ecf20Sopenharmony_ci default: 2088c2ecf20Sopenharmony_ci aq->dev_state = AP_DEV_STATE_ERROR; 2098c2ecf20Sopenharmony_ci aq->last_err_rc = status.response_code; 2108c2ecf20Sopenharmony_ci AP_DBF_WARN("%s RC 0x%02x on 0x%02x.%04x -> AP_DEV_STATE_ERROR\n", 2118c2ecf20Sopenharmony_ci __func__, status.response_code, 2128c2ecf20Sopenharmony_ci AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid)); 2138c2ecf20Sopenharmony_ci return AP_SM_WAIT_NONE; 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci/** 2188c2ecf20Sopenharmony_ci * ap_sm_write(): Send messages from the request queue to an AP queue. 2198c2ecf20Sopenharmony_ci * @aq: pointer to the AP queue 2208c2ecf20Sopenharmony_ci * 2218c2ecf20Sopenharmony_ci * Returns AP_SM_WAIT_NONE, AP_SM_WAIT_AGAIN, or AP_SM_WAIT_INTERRUPT 2228c2ecf20Sopenharmony_ci */ 2238c2ecf20Sopenharmony_cistatic enum ap_sm_wait ap_sm_write(struct ap_queue *aq) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci struct ap_queue_status status; 2268c2ecf20Sopenharmony_ci struct ap_message *ap_msg; 2278c2ecf20Sopenharmony_ci ap_qid_t qid = aq->qid; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci if (aq->requestq_count <= 0) 2308c2ecf20Sopenharmony_ci return AP_SM_WAIT_NONE; 2318c2ecf20Sopenharmony_ci /* Start the next request on the queue. */ 2328c2ecf20Sopenharmony_ci ap_msg = list_entry(aq->requestq.next, struct ap_message, list); 2338c2ecf20Sopenharmony_ci#ifdef CONFIG_ZCRYPT_DEBUG 2348c2ecf20Sopenharmony_ci if (ap_msg->fi.action == AP_FI_ACTION_NQAP_QID_INVAL) { 2358c2ecf20Sopenharmony_ci AP_DBF_WARN("%s fi cmd 0x%04x: forcing invalid qid 0xFF00\n", 2368c2ecf20Sopenharmony_ci __func__, ap_msg->fi.cmd); 2378c2ecf20Sopenharmony_ci qid = 0xFF00; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci#endif 2408c2ecf20Sopenharmony_ci status = __ap_send(qid, ap_msg->psmid, 2418c2ecf20Sopenharmony_ci ap_msg->msg, ap_msg->len, 2428c2ecf20Sopenharmony_ci ap_msg->flags & AP_MSG_FLAG_SPECIAL); 2438c2ecf20Sopenharmony_ci switch (status.response_code) { 2448c2ecf20Sopenharmony_ci case AP_RESPONSE_NORMAL: 2458c2ecf20Sopenharmony_ci aq->queue_count = max_t(int, 1, aq->queue_count + 1); 2468c2ecf20Sopenharmony_ci if (aq->queue_count == 1) 2478c2ecf20Sopenharmony_ci mod_timer(&aq->timeout, jiffies + aq->request_timeout); 2488c2ecf20Sopenharmony_ci list_move_tail(&ap_msg->list, &aq->pendingq); 2498c2ecf20Sopenharmony_ci aq->requestq_count--; 2508c2ecf20Sopenharmony_ci aq->pendingq_count++; 2518c2ecf20Sopenharmony_ci if (aq->queue_count < aq->card->queue_depth) { 2528c2ecf20Sopenharmony_ci aq->sm_state = AP_SM_STATE_WORKING; 2538c2ecf20Sopenharmony_ci return AP_SM_WAIT_AGAIN; 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci fallthrough; 2568c2ecf20Sopenharmony_ci case AP_RESPONSE_Q_FULL: 2578c2ecf20Sopenharmony_ci aq->sm_state = AP_SM_STATE_QUEUE_FULL; 2588c2ecf20Sopenharmony_ci return aq->interrupt ? 2598c2ecf20Sopenharmony_ci AP_SM_WAIT_INTERRUPT : AP_SM_WAIT_TIMEOUT; 2608c2ecf20Sopenharmony_ci case AP_RESPONSE_RESET_IN_PROGRESS: 2618c2ecf20Sopenharmony_ci aq->sm_state = AP_SM_STATE_RESET_WAIT; 2628c2ecf20Sopenharmony_ci return AP_SM_WAIT_TIMEOUT; 2638c2ecf20Sopenharmony_ci case AP_RESPONSE_INVALID_DOMAIN: 2648c2ecf20Sopenharmony_ci AP_DBF(DBF_WARN, "AP_RESPONSE_INVALID_DOMAIN on NQAP\n"); 2658c2ecf20Sopenharmony_ci fallthrough; 2668c2ecf20Sopenharmony_ci case AP_RESPONSE_MESSAGE_TOO_BIG: 2678c2ecf20Sopenharmony_ci case AP_RESPONSE_REQ_FAC_NOT_INST: 2688c2ecf20Sopenharmony_ci list_del_init(&ap_msg->list); 2698c2ecf20Sopenharmony_ci aq->requestq_count--; 2708c2ecf20Sopenharmony_ci ap_msg->rc = -EINVAL; 2718c2ecf20Sopenharmony_ci ap_msg->receive(aq, ap_msg, NULL); 2728c2ecf20Sopenharmony_ci return AP_SM_WAIT_AGAIN; 2738c2ecf20Sopenharmony_ci default: 2748c2ecf20Sopenharmony_ci aq->dev_state = AP_DEV_STATE_ERROR; 2758c2ecf20Sopenharmony_ci aq->last_err_rc = status.response_code; 2768c2ecf20Sopenharmony_ci AP_DBF_WARN("%s RC 0x%02x on 0x%02x.%04x -> AP_DEV_STATE_ERROR\n", 2778c2ecf20Sopenharmony_ci __func__, status.response_code, 2788c2ecf20Sopenharmony_ci AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid)); 2798c2ecf20Sopenharmony_ci return AP_SM_WAIT_NONE; 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci/** 2848c2ecf20Sopenharmony_ci * ap_sm_read_write(): Send and receive messages to/from an AP queue. 2858c2ecf20Sopenharmony_ci * @aq: pointer to the AP queue 2868c2ecf20Sopenharmony_ci * 2878c2ecf20Sopenharmony_ci * Returns AP_SM_WAIT_NONE, AP_SM_WAIT_AGAIN, or AP_SM_WAIT_INTERRUPT 2888c2ecf20Sopenharmony_ci */ 2898c2ecf20Sopenharmony_cistatic enum ap_sm_wait ap_sm_read_write(struct ap_queue *aq) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci return min(ap_sm_read(aq), ap_sm_write(aq)); 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci/** 2958c2ecf20Sopenharmony_ci * ap_sm_reset(): Reset an AP queue. 2968c2ecf20Sopenharmony_ci * @qid: The AP queue number 2978c2ecf20Sopenharmony_ci * 2988c2ecf20Sopenharmony_ci * Submit the Reset command to an AP queue. 2998c2ecf20Sopenharmony_ci */ 3008c2ecf20Sopenharmony_cistatic enum ap_sm_wait ap_sm_reset(struct ap_queue *aq) 3018c2ecf20Sopenharmony_ci{ 3028c2ecf20Sopenharmony_ci struct ap_queue_status status; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci status = ap_rapq(aq->qid); 3058c2ecf20Sopenharmony_ci switch (status.response_code) { 3068c2ecf20Sopenharmony_ci case AP_RESPONSE_NORMAL: 3078c2ecf20Sopenharmony_ci case AP_RESPONSE_RESET_IN_PROGRESS: 3088c2ecf20Sopenharmony_ci aq->sm_state = AP_SM_STATE_RESET_WAIT; 3098c2ecf20Sopenharmony_ci aq->interrupt = false; 3108c2ecf20Sopenharmony_ci return AP_SM_WAIT_TIMEOUT; 3118c2ecf20Sopenharmony_ci default: 3128c2ecf20Sopenharmony_ci aq->dev_state = AP_DEV_STATE_ERROR; 3138c2ecf20Sopenharmony_ci aq->last_err_rc = status.response_code; 3148c2ecf20Sopenharmony_ci AP_DBF_WARN("%s RC 0x%02x on 0x%02x.%04x -> AP_DEV_STATE_ERROR\n", 3158c2ecf20Sopenharmony_ci __func__, status.response_code, 3168c2ecf20Sopenharmony_ci AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid)); 3178c2ecf20Sopenharmony_ci return AP_SM_WAIT_NONE; 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci/** 3228c2ecf20Sopenharmony_ci * ap_sm_reset_wait(): Test queue for completion of the reset operation 3238c2ecf20Sopenharmony_ci * @aq: pointer to the AP queue 3248c2ecf20Sopenharmony_ci * 3258c2ecf20Sopenharmony_ci * Returns AP_POLL_IMMEDIATELY, AP_POLL_AFTER_TIMEROUT or 0. 3268c2ecf20Sopenharmony_ci */ 3278c2ecf20Sopenharmony_cistatic enum ap_sm_wait ap_sm_reset_wait(struct ap_queue *aq) 3288c2ecf20Sopenharmony_ci{ 3298c2ecf20Sopenharmony_ci struct ap_queue_status status; 3308c2ecf20Sopenharmony_ci void *lsi_ptr; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci if (aq->queue_count > 0 && aq->reply) 3338c2ecf20Sopenharmony_ci /* Try to read a completed message and get the status */ 3348c2ecf20Sopenharmony_ci status = ap_sm_recv(aq); 3358c2ecf20Sopenharmony_ci else 3368c2ecf20Sopenharmony_ci /* Get the status with TAPQ */ 3378c2ecf20Sopenharmony_ci status = ap_tapq(aq->qid, NULL); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci switch (status.response_code) { 3408c2ecf20Sopenharmony_ci case AP_RESPONSE_NORMAL: 3418c2ecf20Sopenharmony_ci lsi_ptr = ap_airq_ptr(); 3428c2ecf20Sopenharmony_ci if (lsi_ptr && ap_queue_enable_irq(aq, lsi_ptr) == 0) 3438c2ecf20Sopenharmony_ci aq->sm_state = AP_SM_STATE_SETIRQ_WAIT; 3448c2ecf20Sopenharmony_ci else 3458c2ecf20Sopenharmony_ci aq->sm_state = (aq->queue_count > 0) ? 3468c2ecf20Sopenharmony_ci AP_SM_STATE_WORKING : AP_SM_STATE_IDLE; 3478c2ecf20Sopenharmony_ci return AP_SM_WAIT_AGAIN; 3488c2ecf20Sopenharmony_ci case AP_RESPONSE_BUSY: 3498c2ecf20Sopenharmony_ci case AP_RESPONSE_RESET_IN_PROGRESS: 3508c2ecf20Sopenharmony_ci return AP_SM_WAIT_TIMEOUT; 3518c2ecf20Sopenharmony_ci case AP_RESPONSE_Q_NOT_AVAIL: 3528c2ecf20Sopenharmony_ci case AP_RESPONSE_DECONFIGURED: 3538c2ecf20Sopenharmony_ci case AP_RESPONSE_CHECKSTOPPED: 3548c2ecf20Sopenharmony_ci default: 3558c2ecf20Sopenharmony_ci aq->dev_state = AP_DEV_STATE_ERROR; 3568c2ecf20Sopenharmony_ci aq->last_err_rc = status.response_code; 3578c2ecf20Sopenharmony_ci AP_DBF_WARN("%s RC 0x%02x on 0x%02x.%04x -> AP_DEV_STATE_ERROR\n", 3588c2ecf20Sopenharmony_ci __func__, status.response_code, 3598c2ecf20Sopenharmony_ci AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid)); 3608c2ecf20Sopenharmony_ci return AP_SM_WAIT_NONE; 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci} 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci/** 3658c2ecf20Sopenharmony_ci * ap_sm_setirq_wait(): Test queue for completion of the irq enablement 3668c2ecf20Sopenharmony_ci * @aq: pointer to the AP queue 3678c2ecf20Sopenharmony_ci * 3688c2ecf20Sopenharmony_ci * Returns AP_POLL_IMMEDIATELY, AP_POLL_AFTER_TIMEROUT or 0. 3698c2ecf20Sopenharmony_ci */ 3708c2ecf20Sopenharmony_cistatic enum ap_sm_wait ap_sm_setirq_wait(struct ap_queue *aq) 3718c2ecf20Sopenharmony_ci{ 3728c2ecf20Sopenharmony_ci struct ap_queue_status status; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci if (aq->queue_count > 0 && aq->reply) 3758c2ecf20Sopenharmony_ci /* Try to read a completed message and get the status */ 3768c2ecf20Sopenharmony_ci status = ap_sm_recv(aq); 3778c2ecf20Sopenharmony_ci else 3788c2ecf20Sopenharmony_ci /* Get the status with TAPQ */ 3798c2ecf20Sopenharmony_ci status = ap_tapq(aq->qid, NULL); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci if (status.irq_enabled == 1) { 3828c2ecf20Sopenharmony_ci /* Irqs are now enabled */ 3838c2ecf20Sopenharmony_ci aq->interrupt = true; 3848c2ecf20Sopenharmony_ci aq->sm_state = (aq->queue_count > 0) ? 3858c2ecf20Sopenharmony_ci AP_SM_STATE_WORKING : AP_SM_STATE_IDLE; 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci switch (status.response_code) { 3898c2ecf20Sopenharmony_ci case AP_RESPONSE_NORMAL: 3908c2ecf20Sopenharmony_ci if (aq->queue_count > 0) 3918c2ecf20Sopenharmony_ci return AP_SM_WAIT_AGAIN; 3928c2ecf20Sopenharmony_ci fallthrough; 3938c2ecf20Sopenharmony_ci case AP_RESPONSE_NO_PENDING_REPLY: 3948c2ecf20Sopenharmony_ci return AP_SM_WAIT_TIMEOUT; 3958c2ecf20Sopenharmony_ci default: 3968c2ecf20Sopenharmony_ci aq->dev_state = AP_DEV_STATE_ERROR; 3978c2ecf20Sopenharmony_ci aq->last_err_rc = status.response_code; 3988c2ecf20Sopenharmony_ci AP_DBF_WARN("%s RC 0x%02x on 0x%02x.%04x -> AP_DEV_STATE_ERROR\n", 3998c2ecf20Sopenharmony_ci __func__, status.response_code, 4008c2ecf20Sopenharmony_ci AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid)); 4018c2ecf20Sopenharmony_ci return AP_SM_WAIT_NONE; 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci/* 4068c2ecf20Sopenharmony_ci * AP state machine jump table 4078c2ecf20Sopenharmony_ci */ 4088c2ecf20Sopenharmony_cistatic ap_func_t *ap_jumptable[NR_AP_SM_STATES][NR_AP_SM_EVENTS] = { 4098c2ecf20Sopenharmony_ci [AP_SM_STATE_RESET_START] = { 4108c2ecf20Sopenharmony_ci [AP_SM_EVENT_POLL] = ap_sm_reset, 4118c2ecf20Sopenharmony_ci [AP_SM_EVENT_TIMEOUT] = ap_sm_nop, 4128c2ecf20Sopenharmony_ci }, 4138c2ecf20Sopenharmony_ci [AP_SM_STATE_RESET_WAIT] = { 4148c2ecf20Sopenharmony_ci [AP_SM_EVENT_POLL] = ap_sm_reset_wait, 4158c2ecf20Sopenharmony_ci [AP_SM_EVENT_TIMEOUT] = ap_sm_nop, 4168c2ecf20Sopenharmony_ci }, 4178c2ecf20Sopenharmony_ci [AP_SM_STATE_SETIRQ_WAIT] = { 4188c2ecf20Sopenharmony_ci [AP_SM_EVENT_POLL] = ap_sm_setirq_wait, 4198c2ecf20Sopenharmony_ci [AP_SM_EVENT_TIMEOUT] = ap_sm_nop, 4208c2ecf20Sopenharmony_ci }, 4218c2ecf20Sopenharmony_ci [AP_SM_STATE_IDLE] = { 4228c2ecf20Sopenharmony_ci [AP_SM_EVENT_POLL] = ap_sm_write, 4238c2ecf20Sopenharmony_ci [AP_SM_EVENT_TIMEOUT] = ap_sm_nop, 4248c2ecf20Sopenharmony_ci }, 4258c2ecf20Sopenharmony_ci [AP_SM_STATE_WORKING] = { 4268c2ecf20Sopenharmony_ci [AP_SM_EVENT_POLL] = ap_sm_read_write, 4278c2ecf20Sopenharmony_ci [AP_SM_EVENT_TIMEOUT] = ap_sm_reset, 4288c2ecf20Sopenharmony_ci }, 4298c2ecf20Sopenharmony_ci [AP_SM_STATE_QUEUE_FULL] = { 4308c2ecf20Sopenharmony_ci [AP_SM_EVENT_POLL] = ap_sm_read, 4318c2ecf20Sopenharmony_ci [AP_SM_EVENT_TIMEOUT] = ap_sm_reset, 4328c2ecf20Sopenharmony_ci }, 4338c2ecf20Sopenharmony_ci}; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_cienum ap_sm_wait ap_sm_event(struct ap_queue *aq, enum ap_sm_event event) 4368c2ecf20Sopenharmony_ci{ 4378c2ecf20Sopenharmony_ci if (aq->dev_state > AP_DEV_STATE_UNINITIATED) 4388c2ecf20Sopenharmony_ci return ap_jumptable[aq->sm_state][event](aq); 4398c2ecf20Sopenharmony_ci else 4408c2ecf20Sopenharmony_ci return AP_SM_WAIT_NONE; 4418c2ecf20Sopenharmony_ci} 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_cienum ap_sm_wait ap_sm_event_loop(struct ap_queue *aq, enum ap_sm_event event) 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci enum ap_sm_wait wait; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci while ((wait = ap_sm_event(aq, event)) == AP_SM_WAIT_AGAIN) 4488c2ecf20Sopenharmony_ci ; 4498c2ecf20Sopenharmony_ci return wait; 4508c2ecf20Sopenharmony_ci} 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci/* 4538c2ecf20Sopenharmony_ci * AP queue related attributes. 4548c2ecf20Sopenharmony_ci */ 4558c2ecf20Sopenharmony_cistatic ssize_t request_count_show(struct device *dev, 4568c2ecf20Sopenharmony_ci struct device_attribute *attr, 4578c2ecf20Sopenharmony_ci char *buf) 4588c2ecf20Sopenharmony_ci{ 4598c2ecf20Sopenharmony_ci struct ap_queue *aq = to_ap_queue(dev); 4608c2ecf20Sopenharmony_ci bool valid = false; 4618c2ecf20Sopenharmony_ci u64 req_cnt; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci spin_lock_bh(&aq->lock); 4648c2ecf20Sopenharmony_ci if (aq->dev_state > AP_DEV_STATE_UNINITIATED) { 4658c2ecf20Sopenharmony_ci req_cnt = aq->total_request_count; 4668c2ecf20Sopenharmony_ci valid = true; 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci spin_unlock_bh(&aq->lock); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci if (valid) 4718c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%llu\n", req_cnt); 4728c2ecf20Sopenharmony_ci else 4738c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "-\n"); 4748c2ecf20Sopenharmony_ci} 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_cistatic ssize_t request_count_store(struct device *dev, 4778c2ecf20Sopenharmony_ci struct device_attribute *attr, 4788c2ecf20Sopenharmony_ci const char *buf, size_t count) 4798c2ecf20Sopenharmony_ci{ 4808c2ecf20Sopenharmony_ci struct ap_queue *aq = to_ap_queue(dev); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci spin_lock_bh(&aq->lock); 4838c2ecf20Sopenharmony_ci aq->total_request_count = 0; 4848c2ecf20Sopenharmony_ci spin_unlock_bh(&aq->lock); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci return count; 4878c2ecf20Sopenharmony_ci} 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(request_count); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_cistatic ssize_t requestq_count_show(struct device *dev, 4928c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 4938c2ecf20Sopenharmony_ci{ 4948c2ecf20Sopenharmony_ci struct ap_queue *aq = to_ap_queue(dev); 4958c2ecf20Sopenharmony_ci unsigned int reqq_cnt = 0; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci spin_lock_bh(&aq->lock); 4988c2ecf20Sopenharmony_ci if (aq->dev_state > AP_DEV_STATE_UNINITIATED) 4998c2ecf20Sopenharmony_ci reqq_cnt = aq->requestq_count; 5008c2ecf20Sopenharmony_ci spin_unlock_bh(&aq->lock); 5018c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%d\n", reqq_cnt); 5028c2ecf20Sopenharmony_ci} 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(requestq_count); 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_cistatic ssize_t pendingq_count_show(struct device *dev, 5078c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 5088c2ecf20Sopenharmony_ci{ 5098c2ecf20Sopenharmony_ci struct ap_queue *aq = to_ap_queue(dev); 5108c2ecf20Sopenharmony_ci unsigned int penq_cnt = 0; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci spin_lock_bh(&aq->lock); 5138c2ecf20Sopenharmony_ci if (aq->dev_state > AP_DEV_STATE_UNINITIATED) 5148c2ecf20Sopenharmony_ci penq_cnt = aq->pendingq_count; 5158c2ecf20Sopenharmony_ci spin_unlock_bh(&aq->lock); 5168c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%d\n", penq_cnt); 5178c2ecf20Sopenharmony_ci} 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(pendingq_count); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_cistatic ssize_t reset_show(struct device *dev, 5228c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 5238c2ecf20Sopenharmony_ci{ 5248c2ecf20Sopenharmony_ci struct ap_queue *aq = to_ap_queue(dev); 5258c2ecf20Sopenharmony_ci int rc = 0; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci spin_lock_bh(&aq->lock); 5288c2ecf20Sopenharmony_ci switch (aq->sm_state) { 5298c2ecf20Sopenharmony_ci case AP_SM_STATE_RESET_START: 5308c2ecf20Sopenharmony_ci case AP_SM_STATE_RESET_WAIT: 5318c2ecf20Sopenharmony_ci rc = scnprintf(buf, PAGE_SIZE, "Reset in progress.\n"); 5328c2ecf20Sopenharmony_ci break; 5338c2ecf20Sopenharmony_ci case AP_SM_STATE_WORKING: 5348c2ecf20Sopenharmony_ci case AP_SM_STATE_QUEUE_FULL: 5358c2ecf20Sopenharmony_ci rc = scnprintf(buf, PAGE_SIZE, "Reset Timer armed.\n"); 5368c2ecf20Sopenharmony_ci break; 5378c2ecf20Sopenharmony_ci default: 5388c2ecf20Sopenharmony_ci rc = scnprintf(buf, PAGE_SIZE, "No Reset Timer set.\n"); 5398c2ecf20Sopenharmony_ci } 5408c2ecf20Sopenharmony_ci spin_unlock_bh(&aq->lock); 5418c2ecf20Sopenharmony_ci return rc; 5428c2ecf20Sopenharmony_ci} 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_cistatic ssize_t reset_store(struct device *dev, 5458c2ecf20Sopenharmony_ci struct device_attribute *attr, 5468c2ecf20Sopenharmony_ci const char *buf, size_t count) 5478c2ecf20Sopenharmony_ci{ 5488c2ecf20Sopenharmony_ci struct ap_queue *aq = to_ap_queue(dev); 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci spin_lock_bh(&aq->lock); 5518c2ecf20Sopenharmony_ci __ap_flush_queue(aq); 5528c2ecf20Sopenharmony_ci aq->sm_state = AP_SM_STATE_RESET_START; 5538c2ecf20Sopenharmony_ci ap_wait(ap_sm_event(aq, AP_SM_EVENT_POLL)); 5548c2ecf20Sopenharmony_ci spin_unlock_bh(&aq->lock); 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci AP_DBF(DBF_INFO, "reset queue=%02x.%04x triggered by user\n", 5578c2ecf20Sopenharmony_ci AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid)); 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci return count; 5608c2ecf20Sopenharmony_ci} 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(reset); 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_cistatic ssize_t interrupt_show(struct device *dev, 5658c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 5668c2ecf20Sopenharmony_ci{ 5678c2ecf20Sopenharmony_ci struct ap_queue *aq = to_ap_queue(dev); 5688c2ecf20Sopenharmony_ci int rc = 0; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci spin_lock_bh(&aq->lock); 5718c2ecf20Sopenharmony_ci if (aq->sm_state == AP_SM_STATE_SETIRQ_WAIT) 5728c2ecf20Sopenharmony_ci rc = scnprintf(buf, PAGE_SIZE, "Enable Interrupt pending.\n"); 5738c2ecf20Sopenharmony_ci else if (aq->interrupt) 5748c2ecf20Sopenharmony_ci rc = scnprintf(buf, PAGE_SIZE, "Interrupts enabled.\n"); 5758c2ecf20Sopenharmony_ci else 5768c2ecf20Sopenharmony_ci rc = scnprintf(buf, PAGE_SIZE, "Interrupts disabled.\n"); 5778c2ecf20Sopenharmony_ci spin_unlock_bh(&aq->lock); 5788c2ecf20Sopenharmony_ci return rc; 5798c2ecf20Sopenharmony_ci} 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(interrupt); 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_cistatic ssize_t config_show(struct device *dev, 5848c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 5858c2ecf20Sopenharmony_ci{ 5868c2ecf20Sopenharmony_ci struct ap_queue *aq = to_ap_queue(dev); 5878c2ecf20Sopenharmony_ci int rc; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci spin_lock_bh(&aq->lock); 5908c2ecf20Sopenharmony_ci rc = scnprintf(buf, PAGE_SIZE, "%d\n", aq->config ? 1 : 0); 5918c2ecf20Sopenharmony_ci spin_unlock_bh(&aq->lock); 5928c2ecf20Sopenharmony_ci return rc; 5938c2ecf20Sopenharmony_ci} 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(config); 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci#ifdef CONFIG_ZCRYPT_DEBUG 5988c2ecf20Sopenharmony_cistatic ssize_t states_show(struct device *dev, 5998c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 6008c2ecf20Sopenharmony_ci{ 6018c2ecf20Sopenharmony_ci struct ap_queue *aq = to_ap_queue(dev); 6028c2ecf20Sopenharmony_ci int rc = 0; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci spin_lock_bh(&aq->lock); 6058c2ecf20Sopenharmony_ci /* queue device state */ 6068c2ecf20Sopenharmony_ci switch (aq->dev_state) { 6078c2ecf20Sopenharmony_ci case AP_DEV_STATE_UNINITIATED: 6088c2ecf20Sopenharmony_ci rc = scnprintf(buf, PAGE_SIZE, "UNINITIATED\n"); 6098c2ecf20Sopenharmony_ci break; 6108c2ecf20Sopenharmony_ci case AP_DEV_STATE_OPERATING: 6118c2ecf20Sopenharmony_ci rc = scnprintf(buf, PAGE_SIZE, "OPERATING"); 6128c2ecf20Sopenharmony_ci break; 6138c2ecf20Sopenharmony_ci case AP_DEV_STATE_SHUTDOWN: 6148c2ecf20Sopenharmony_ci rc = scnprintf(buf, PAGE_SIZE, "SHUTDOWN"); 6158c2ecf20Sopenharmony_ci break; 6168c2ecf20Sopenharmony_ci case AP_DEV_STATE_ERROR: 6178c2ecf20Sopenharmony_ci rc = scnprintf(buf, PAGE_SIZE, "ERROR"); 6188c2ecf20Sopenharmony_ci break; 6198c2ecf20Sopenharmony_ci default: 6208c2ecf20Sopenharmony_ci rc = scnprintf(buf, PAGE_SIZE, "UNKNOWN"); 6218c2ecf20Sopenharmony_ci } 6228c2ecf20Sopenharmony_ci /* state machine state */ 6238c2ecf20Sopenharmony_ci if (aq->dev_state) { 6248c2ecf20Sopenharmony_ci switch (aq->sm_state) { 6258c2ecf20Sopenharmony_ci case AP_SM_STATE_RESET_START: 6268c2ecf20Sopenharmony_ci rc += scnprintf(buf + rc, PAGE_SIZE - rc, 6278c2ecf20Sopenharmony_ci " [RESET_START]\n"); 6288c2ecf20Sopenharmony_ci break; 6298c2ecf20Sopenharmony_ci case AP_SM_STATE_RESET_WAIT: 6308c2ecf20Sopenharmony_ci rc += scnprintf(buf + rc, PAGE_SIZE - rc, 6318c2ecf20Sopenharmony_ci " [RESET_WAIT]\n"); 6328c2ecf20Sopenharmony_ci break; 6338c2ecf20Sopenharmony_ci case AP_SM_STATE_SETIRQ_WAIT: 6348c2ecf20Sopenharmony_ci rc += scnprintf(buf + rc, PAGE_SIZE - rc, 6358c2ecf20Sopenharmony_ci " [SETIRQ_WAIT]\n"); 6368c2ecf20Sopenharmony_ci break; 6378c2ecf20Sopenharmony_ci case AP_SM_STATE_IDLE: 6388c2ecf20Sopenharmony_ci rc += scnprintf(buf + rc, PAGE_SIZE - rc, 6398c2ecf20Sopenharmony_ci " [IDLE]\n"); 6408c2ecf20Sopenharmony_ci break; 6418c2ecf20Sopenharmony_ci case AP_SM_STATE_WORKING: 6428c2ecf20Sopenharmony_ci rc += scnprintf(buf + rc, PAGE_SIZE - rc, 6438c2ecf20Sopenharmony_ci " [WORKING]\n"); 6448c2ecf20Sopenharmony_ci break; 6458c2ecf20Sopenharmony_ci case AP_SM_STATE_QUEUE_FULL: 6468c2ecf20Sopenharmony_ci rc += scnprintf(buf + rc, PAGE_SIZE - rc, 6478c2ecf20Sopenharmony_ci " [FULL]\n"); 6488c2ecf20Sopenharmony_ci break; 6498c2ecf20Sopenharmony_ci default: 6508c2ecf20Sopenharmony_ci rc += scnprintf(buf + rc, PAGE_SIZE - rc, 6518c2ecf20Sopenharmony_ci " [UNKNOWN]\n"); 6528c2ecf20Sopenharmony_ci } 6538c2ecf20Sopenharmony_ci } 6548c2ecf20Sopenharmony_ci spin_unlock_bh(&aq->lock); 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci return rc; 6578c2ecf20Sopenharmony_ci} 6588c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(states); 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_cistatic ssize_t last_err_rc_show(struct device *dev, 6618c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 6628c2ecf20Sopenharmony_ci{ 6638c2ecf20Sopenharmony_ci struct ap_queue *aq = to_ap_queue(dev); 6648c2ecf20Sopenharmony_ci int rc; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci spin_lock_bh(&aq->lock); 6678c2ecf20Sopenharmony_ci rc = aq->last_err_rc; 6688c2ecf20Sopenharmony_ci spin_unlock_bh(&aq->lock); 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci switch (rc) { 6718c2ecf20Sopenharmony_ci case AP_RESPONSE_NORMAL: 6728c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "NORMAL\n"); 6738c2ecf20Sopenharmony_ci case AP_RESPONSE_Q_NOT_AVAIL: 6748c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "Q_NOT_AVAIL\n"); 6758c2ecf20Sopenharmony_ci case AP_RESPONSE_RESET_IN_PROGRESS: 6768c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "RESET_IN_PROGRESS\n"); 6778c2ecf20Sopenharmony_ci case AP_RESPONSE_DECONFIGURED: 6788c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "DECONFIGURED\n"); 6798c2ecf20Sopenharmony_ci case AP_RESPONSE_CHECKSTOPPED: 6808c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "CHECKSTOPPED\n"); 6818c2ecf20Sopenharmony_ci case AP_RESPONSE_BUSY: 6828c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "BUSY\n"); 6838c2ecf20Sopenharmony_ci case AP_RESPONSE_INVALID_ADDRESS: 6848c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "INVALID_ADDRESS\n"); 6858c2ecf20Sopenharmony_ci case AP_RESPONSE_OTHERWISE_CHANGED: 6868c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "OTHERWISE_CHANGED\n"); 6878c2ecf20Sopenharmony_ci case AP_RESPONSE_Q_FULL: 6888c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "Q_FULL/NO_PENDING_REPLY\n"); 6898c2ecf20Sopenharmony_ci case AP_RESPONSE_INDEX_TOO_BIG: 6908c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "INDEX_TOO_BIG\n"); 6918c2ecf20Sopenharmony_ci case AP_RESPONSE_NO_FIRST_PART: 6928c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "NO_FIRST_PART\n"); 6938c2ecf20Sopenharmony_ci case AP_RESPONSE_MESSAGE_TOO_BIG: 6948c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "MESSAGE_TOO_BIG\n"); 6958c2ecf20Sopenharmony_ci case AP_RESPONSE_REQ_FAC_NOT_INST: 6968c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "REQ_FAC_NOT_INST\n"); 6978c2ecf20Sopenharmony_ci default: 6988c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "response code %d\n", rc); 6998c2ecf20Sopenharmony_ci } 7008c2ecf20Sopenharmony_ci} 7018c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(last_err_rc); 7028c2ecf20Sopenharmony_ci#endif 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_cistatic struct attribute *ap_queue_dev_attrs[] = { 7058c2ecf20Sopenharmony_ci &dev_attr_request_count.attr, 7068c2ecf20Sopenharmony_ci &dev_attr_requestq_count.attr, 7078c2ecf20Sopenharmony_ci &dev_attr_pendingq_count.attr, 7088c2ecf20Sopenharmony_ci &dev_attr_reset.attr, 7098c2ecf20Sopenharmony_ci &dev_attr_interrupt.attr, 7108c2ecf20Sopenharmony_ci &dev_attr_config.attr, 7118c2ecf20Sopenharmony_ci#ifdef CONFIG_ZCRYPT_DEBUG 7128c2ecf20Sopenharmony_ci &dev_attr_states.attr, 7138c2ecf20Sopenharmony_ci &dev_attr_last_err_rc.attr, 7148c2ecf20Sopenharmony_ci#endif 7158c2ecf20Sopenharmony_ci NULL 7168c2ecf20Sopenharmony_ci}; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_cistatic struct attribute_group ap_queue_dev_attr_group = { 7198c2ecf20Sopenharmony_ci .attrs = ap_queue_dev_attrs 7208c2ecf20Sopenharmony_ci}; 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_cistatic const struct attribute_group *ap_queue_dev_attr_groups[] = { 7238c2ecf20Sopenharmony_ci &ap_queue_dev_attr_group, 7248c2ecf20Sopenharmony_ci NULL 7258c2ecf20Sopenharmony_ci}; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_cistatic struct device_type ap_queue_type = { 7288c2ecf20Sopenharmony_ci .name = "ap_queue", 7298c2ecf20Sopenharmony_ci .groups = ap_queue_dev_attr_groups, 7308c2ecf20Sopenharmony_ci}; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_cistatic void ap_queue_device_release(struct device *dev) 7338c2ecf20Sopenharmony_ci{ 7348c2ecf20Sopenharmony_ci struct ap_queue *aq = to_ap_queue(dev); 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci spin_lock_bh(&ap_queues_lock); 7378c2ecf20Sopenharmony_ci hash_del(&aq->hnode); 7388c2ecf20Sopenharmony_ci spin_unlock_bh(&ap_queues_lock); 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci kfree(aq); 7418c2ecf20Sopenharmony_ci} 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_cistruct ap_queue *ap_queue_create(ap_qid_t qid, int device_type) 7448c2ecf20Sopenharmony_ci{ 7458c2ecf20Sopenharmony_ci struct ap_queue *aq; 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci aq = kzalloc(sizeof(*aq), GFP_KERNEL); 7488c2ecf20Sopenharmony_ci if (!aq) 7498c2ecf20Sopenharmony_ci return NULL; 7508c2ecf20Sopenharmony_ci aq->ap_dev.device.release = ap_queue_device_release; 7518c2ecf20Sopenharmony_ci aq->ap_dev.device.type = &ap_queue_type; 7528c2ecf20Sopenharmony_ci aq->ap_dev.device_type = device_type; 7538c2ecf20Sopenharmony_ci aq->qid = qid; 7548c2ecf20Sopenharmony_ci aq->interrupt = false; 7558c2ecf20Sopenharmony_ci spin_lock_init(&aq->lock); 7568c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&aq->pendingq); 7578c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&aq->requestq); 7588c2ecf20Sopenharmony_ci timer_setup(&aq->timeout, ap_request_timeout, 0); 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci return aq; 7618c2ecf20Sopenharmony_ci} 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_civoid ap_queue_init_reply(struct ap_queue *aq, struct ap_message *reply) 7648c2ecf20Sopenharmony_ci{ 7658c2ecf20Sopenharmony_ci aq->reply = reply; 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci spin_lock_bh(&aq->lock); 7688c2ecf20Sopenharmony_ci ap_wait(ap_sm_event(aq, AP_SM_EVENT_POLL)); 7698c2ecf20Sopenharmony_ci spin_unlock_bh(&aq->lock); 7708c2ecf20Sopenharmony_ci} 7718c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ap_queue_init_reply); 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci/** 7748c2ecf20Sopenharmony_ci * ap_queue_message(): Queue a request to an AP device. 7758c2ecf20Sopenharmony_ci * @aq: The AP device to queue the message to 7768c2ecf20Sopenharmony_ci * @ap_msg: The message that is to be added 7778c2ecf20Sopenharmony_ci */ 7788c2ecf20Sopenharmony_ciint ap_queue_message(struct ap_queue *aq, struct ap_message *ap_msg) 7798c2ecf20Sopenharmony_ci{ 7808c2ecf20Sopenharmony_ci int rc = 0; 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci /* msg needs to have a valid receive-callback */ 7838c2ecf20Sopenharmony_ci BUG_ON(!ap_msg->receive); 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci spin_lock_bh(&aq->lock); 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci /* only allow to queue new messages if device state is ok */ 7888c2ecf20Sopenharmony_ci if (aq->dev_state == AP_DEV_STATE_OPERATING) { 7898c2ecf20Sopenharmony_ci list_add_tail(&ap_msg->list, &aq->requestq); 7908c2ecf20Sopenharmony_ci aq->requestq_count++; 7918c2ecf20Sopenharmony_ci aq->total_request_count++; 7928c2ecf20Sopenharmony_ci atomic64_inc(&aq->card->total_request_count); 7938c2ecf20Sopenharmony_ci } else 7948c2ecf20Sopenharmony_ci rc = -ENODEV; 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci /* Send/receive as many request from the queue as possible. */ 7978c2ecf20Sopenharmony_ci ap_wait(ap_sm_event_loop(aq, AP_SM_EVENT_POLL)); 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci spin_unlock_bh(&aq->lock); 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci return rc; 8028c2ecf20Sopenharmony_ci} 8038c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ap_queue_message); 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci/** 8068c2ecf20Sopenharmony_ci * ap_cancel_message(): Cancel a crypto request. 8078c2ecf20Sopenharmony_ci * @aq: The AP device that has the message queued 8088c2ecf20Sopenharmony_ci * @ap_msg: The message that is to be removed 8098c2ecf20Sopenharmony_ci * 8108c2ecf20Sopenharmony_ci * Cancel a crypto request. This is done by removing the request 8118c2ecf20Sopenharmony_ci * from the device pending or request queue. Note that the 8128c2ecf20Sopenharmony_ci * request stays on the AP queue. When it finishes the message 8138c2ecf20Sopenharmony_ci * reply will be discarded because the psmid can't be found. 8148c2ecf20Sopenharmony_ci */ 8158c2ecf20Sopenharmony_civoid ap_cancel_message(struct ap_queue *aq, struct ap_message *ap_msg) 8168c2ecf20Sopenharmony_ci{ 8178c2ecf20Sopenharmony_ci struct ap_message *tmp; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci spin_lock_bh(&aq->lock); 8208c2ecf20Sopenharmony_ci if (!list_empty(&ap_msg->list)) { 8218c2ecf20Sopenharmony_ci list_for_each_entry(tmp, &aq->pendingq, list) 8228c2ecf20Sopenharmony_ci if (tmp->psmid == ap_msg->psmid) { 8238c2ecf20Sopenharmony_ci aq->pendingq_count--; 8248c2ecf20Sopenharmony_ci goto found; 8258c2ecf20Sopenharmony_ci } 8268c2ecf20Sopenharmony_ci aq->requestq_count--; 8278c2ecf20Sopenharmony_cifound: 8288c2ecf20Sopenharmony_ci list_del_init(&ap_msg->list); 8298c2ecf20Sopenharmony_ci } 8308c2ecf20Sopenharmony_ci spin_unlock_bh(&aq->lock); 8318c2ecf20Sopenharmony_ci} 8328c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ap_cancel_message); 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci/** 8358c2ecf20Sopenharmony_ci * __ap_flush_queue(): Flush requests. 8368c2ecf20Sopenharmony_ci * @aq: Pointer to the AP queue 8378c2ecf20Sopenharmony_ci * 8388c2ecf20Sopenharmony_ci * Flush all requests from the request/pending queue of an AP device. 8398c2ecf20Sopenharmony_ci */ 8408c2ecf20Sopenharmony_cistatic void __ap_flush_queue(struct ap_queue *aq) 8418c2ecf20Sopenharmony_ci{ 8428c2ecf20Sopenharmony_ci struct ap_message *ap_msg, *next; 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci list_for_each_entry_safe(ap_msg, next, &aq->pendingq, list) { 8458c2ecf20Sopenharmony_ci list_del_init(&ap_msg->list); 8468c2ecf20Sopenharmony_ci aq->pendingq_count--; 8478c2ecf20Sopenharmony_ci ap_msg->rc = -EAGAIN; 8488c2ecf20Sopenharmony_ci ap_msg->receive(aq, ap_msg, NULL); 8498c2ecf20Sopenharmony_ci } 8508c2ecf20Sopenharmony_ci list_for_each_entry_safe(ap_msg, next, &aq->requestq, list) { 8518c2ecf20Sopenharmony_ci list_del_init(&ap_msg->list); 8528c2ecf20Sopenharmony_ci aq->requestq_count--; 8538c2ecf20Sopenharmony_ci ap_msg->rc = -EAGAIN; 8548c2ecf20Sopenharmony_ci ap_msg->receive(aq, ap_msg, NULL); 8558c2ecf20Sopenharmony_ci } 8568c2ecf20Sopenharmony_ci aq->queue_count = 0; 8578c2ecf20Sopenharmony_ci} 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_civoid ap_flush_queue(struct ap_queue *aq) 8608c2ecf20Sopenharmony_ci{ 8618c2ecf20Sopenharmony_ci spin_lock_bh(&aq->lock); 8628c2ecf20Sopenharmony_ci __ap_flush_queue(aq); 8638c2ecf20Sopenharmony_ci spin_unlock_bh(&aq->lock); 8648c2ecf20Sopenharmony_ci} 8658c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ap_flush_queue); 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_civoid ap_queue_prepare_remove(struct ap_queue *aq) 8688c2ecf20Sopenharmony_ci{ 8698c2ecf20Sopenharmony_ci spin_lock_bh(&aq->lock); 8708c2ecf20Sopenharmony_ci /* flush queue */ 8718c2ecf20Sopenharmony_ci __ap_flush_queue(aq); 8728c2ecf20Sopenharmony_ci /* move queue device state to SHUTDOWN in progress */ 8738c2ecf20Sopenharmony_ci aq->dev_state = AP_DEV_STATE_SHUTDOWN; 8748c2ecf20Sopenharmony_ci spin_unlock_bh(&aq->lock); 8758c2ecf20Sopenharmony_ci del_timer_sync(&aq->timeout); 8768c2ecf20Sopenharmony_ci} 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_civoid ap_queue_remove(struct ap_queue *aq) 8798c2ecf20Sopenharmony_ci{ 8808c2ecf20Sopenharmony_ci /* 8818c2ecf20Sopenharmony_ci * all messages have been flushed and the device state 8828c2ecf20Sopenharmony_ci * is SHUTDOWN. Now reset with zero which also clears 8838c2ecf20Sopenharmony_ci * the irq registration and move the device state 8848c2ecf20Sopenharmony_ci * to the initial value AP_DEV_STATE_UNINITIATED. 8858c2ecf20Sopenharmony_ci */ 8868c2ecf20Sopenharmony_ci spin_lock_bh(&aq->lock); 8878c2ecf20Sopenharmony_ci ap_zapq(aq->qid); 8888c2ecf20Sopenharmony_ci aq->dev_state = AP_DEV_STATE_UNINITIATED; 8898c2ecf20Sopenharmony_ci spin_unlock_bh(&aq->lock); 8908c2ecf20Sopenharmony_ci} 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_civoid ap_queue_init_state(struct ap_queue *aq) 8938c2ecf20Sopenharmony_ci{ 8948c2ecf20Sopenharmony_ci spin_lock_bh(&aq->lock); 8958c2ecf20Sopenharmony_ci aq->dev_state = AP_DEV_STATE_OPERATING; 8968c2ecf20Sopenharmony_ci aq->sm_state = AP_SM_STATE_RESET_START; 8978c2ecf20Sopenharmony_ci ap_wait(ap_sm_event(aq, AP_SM_EVENT_POLL)); 8988c2ecf20Sopenharmony_ci spin_unlock_bh(&aq->lock); 8998c2ecf20Sopenharmony_ci} 9008c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ap_queue_init_state); 901