103831d35Sstevel /* 203831d35Sstevel * CDDL HEADER START 303831d35Sstevel * 403831d35Sstevel * The contents of this file are subject to the terms of the 503831d35Sstevel * Common Development and Distribution License (the "License"). 603831d35Sstevel * You may not use this file except in compliance with the License. 703831d35Sstevel * 803831d35Sstevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 903831d35Sstevel * or http://www.opensolaris.org/os/licensing. 1003831d35Sstevel * See the License for the specific language governing permissions 1103831d35Sstevel * and limitations under the License. 1203831d35Sstevel * 1303831d35Sstevel * When distributing Covered Code, include this CDDL HEADER in each 1403831d35Sstevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1503831d35Sstevel * If applicable, add the following below this CDDL HEADER, with the 1603831d35Sstevel * fields enclosed by brackets "[]" replaced with your own identifying 1703831d35Sstevel * information: Portions Copyright [yyyy] [name of copyright owner] 1803831d35Sstevel * 1903831d35Sstevel * CDDL HEADER END 2003831d35Sstevel */ 2103831d35Sstevel 2203831d35Sstevel /* 23*d3d50737SRafael Vanoni * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 2403831d35Sstevel * Use is subject to license terms. 2503831d35Sstevel */ 2603831d35Sstevel 2703831d35Sstevel /* 2803831d35Sstevel * provide the interface to the layered drivers (send request/receive 2903831d35Sstevel * response to the RMC 3003831d35Sstevel * 3103831d35Sstevel */ 3203831d35Sstevel 3303831d35Sstevel /* 3403831d35Sstevel * Header files 3503831d35Sstevel */ 3603831d35Sstevel #include <sys/conf.h> 3703831d35Sstevel #include <sys/callb.h> 3803831d35Sstevel #include <sys/cyclic.h> 3903831d35Sstevel #include <sys/membar.h> 4003831d35Sstevel #include <sys/modctl.h> 4103831d35Sstevel #include <sys/strlog.h> 4203831d35Sstevel #include <sys/sunddi.h> 4303831d35Sstevel #include <sys/ddi.h> 4403831d35Sstevel #include <sys/types.h> 4503831d35Sstevel #include <sys/disp.h> 4603831d35Sstevel #include <sys/rmc_comm_dp.h> 4703831d35Sstevel #include <sys/rmc_comm_dp_boot.h> 4803831d35Sstevel #include <sys/rmc_comm_drvintf.h> 4903831d35Sstevel #include <sys/rmc_comm.h> 5003831d35Sstevel 5103831d35Sstevel void dp_reset(struct rmc_comm_state *, uint8_t, boolean_t, boolean_t); 5203831d35Sstevel void dp_wake_up_waiter(struct rmc_comm_state *, uint8_t); 5303831d35Sstevel 5403831d35Sstevel static int rmc_comm_send_req_resp(struct rmc_comm_state *rcs, 5503831d35Sstevel rmc_comm_msg_t *request, rmc_comm_msg_t *response, uint32_t wait_time); 5603831d35Sstevel static int rmc_comm_wait_bp_reply(struct rmc_comm_state *, 5703831d35Sstevel rmc_comm_dp_state_t *, dp_req_resp_t *, clock_t); 5803831d35Sstevel static void rmc_comm_wait_enable_to_send(struct rmc_comm_state *, 5903831d35Sstevel rmc_comm_dp_state_t *); 6003831d35Sstevel static void rmc_comm_wake_up_next(struct rmc_comm_state *); 6103831d35Sstevel static void rmc_comm_send_pend_req(caddr_t arg); 6203831d35Sstevel static int rmc_comm_dreq_thread_start(struct rmc_comm_state *rcs); 6303831d35Sstevel static void rmc_comm_dreq_thread_kill(struct rmc_comm_state *rcs); 6403831d35Sstevel 6503831d35Sstevel /* 6603831d35Sstevel * leaf driver to use this function to send a request to the remote side (RMC) 6703831d35Sstevel * and wait for a reply 6803831d35Sstevel */ 6903831d35Sstevel int 7003831d35Sstevel rmc_comm_request_response(rmc_comm_msg_t *request, 7103831d35Sstevel rmc_comm_msg_t *response, uint32_t wait_time) 7203831d35Sstevel { 7303831d35Sstevel struct rmc_comm_state *rcs; 7452f4394bSjfrank int err; 7503831d35Sstevel 7603831d35Sstevel /* 7703831d35Sstevel * get the soft state struct (instance 0) 7803831d35Sstevel */ 7903831d35Sstevel if ((rcs = rmc_comm_getstate(NULL, 0, 8003831d35Sstevel "rmc_comm_request_response")) == NULL) 8103831d35Sstevel return (RCENOSOFTSTATE); 8203831d35Sstevel 8352f4394bSjfrank do { 8452f4394bSjfrank err = rmc_comm_send_req_resp(rcs, request, response, wait_time); 8552f4394bSjfrank } while (err == RCEGENERIC); 8652f4394bSjfrank return (err); 8703831d35Sstevel } 8803831d35Sstevel 8903831d35Sstevel /* 9003831d35Sstevel * leaf driver to use this function to send a request to the remote side (RMC) 9103831d35Sstevel * without waiting for a reply. If flag is RMC_COMM_DREQ_URGENT, the request 9203831d35Sstevel * message is sent once-off (an eventual pending request is aborted). This 9303831d35Sstevel * flag must only be used when try to send a request in critical condition 9403831d35Sstevel * (while the system is shutting down for instance and the CPU signature 9503831d35Sstevel * has to be sent). Otherwise, the request is stored in a temporary location 9603831d35Sstevel * and delivered by a thread. 9703831d35Sstevel */ 9803831d35Sstevel int 9903831d35Sstevel rmc_comm_request_nowait(rmc_comm_msg_t *request, uint8_t flag) 10003831d35Sstevel { 10103831d35Sstevel struct rmc_comm_state *rcs; 10203831d35Sstevel rmc_comm_dp_state_t *dps; 10303831d35Sstevel rmc_comm_drvintf_state_t *dis; 10403831d35Sstevel dp_message_t req; 10503831d35Sstevel int err = RCNOERR; 10603831d35Sstevel uint8_t flags = 0; 10703831d35Sstevel 10803831d35Sstevel /* 10903831d35Sstevel * get the soft state struct (instance 0) 11003831d35Sstevel */ 11103831d35Sstevel if ((rcs = rmc_comm_getstate(NULL, 0, 11203831d35Sstevel "rmc_comm_request_response")) == NULL) 11303831d35Sstevel return (RCENOSOFTSTATE); 11403831d35Sstevel 11503831d35Sstevel /* 11603831d35Sstevel * just a sanity check... 11703831d35Sstevel */ 11803831d35Sstevel if (request == NULL) { 11903831d35Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "reqnowait, invalid args\n")); 12003831d35Sstevel return (RCEINVARG); 12103831d35Sstevel } 12203831d35Sstevel 12303831d35Sstevel if (!IS_NUMBERED_MSG(request->msg_type)) { 12403831d35Sstevel DPRINTF(rcs, DAPI, (CE_CONT, 12503831d35Sstevel "reqnowait, ctrl msg not allowed! req type=%x\n", 12603831d35Sstevel request->msg_type)); 12703831d35Sstevel return (RCEINVARG); 12803831d35Sstevel } 12903831d35Sstevel 13003831d35Sstevel if (flag == RMC_COMM_DREQ_URGENT) { 13103831d35Sstevel /* 13203831d35Sstevel * Send this request with high priority i.e. abort eventual 13303831d35Sstevel * request/response pending sessions. 13403831d35Sstevel */ 13503831d35Sstevel 13603831d35Sstevel dps = &rcs->dp_state; 13703831d35Sstevel 13803831d35Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "going to send request=%x (URG)\n", 13903831d35Sstevel request->msg_type)); 14003831d35Sstevel 1416fa6856eSarutz /* 1426fa6856eSarutz * Handle the case where we are called during panic 1436fa6856eSarutz * processing. If that occurs, then another thread in 1446fa6856eSarutz * rmc_comm might have been idled by panic() while 1456fa6856eSarutz * holding dp_mutex. As a result, do not unconditionally 1466fa6856eSarutz * grab dp_mutex. 1476fa6856eSarutz */ 1486fa6856eSarutz if (ddi_in_panic() != 0) { 1496fa6856eSarutz if (mutex_tryenter(dps->dp_mutex) == 0) { 1506fa6856eSarutz return (RCENODATALINK); 1516fa6856eSarutz } 1526fa6856eSarutz } else { 15303831d35Sstevel mutex_enter(dps->dp_mutex); 1546fa6856eSarutz } 15503831d35Sstevel 15603831d35Sstevel /* 15703831d35Sstevel * send the request only if the protocol data link is up. 15803831d35Sstevel * it is pointless to send it in the other case. 15903831d35Sstevel */ 16003831d35Sstevel if (dps->data_link_ok) { 16103831d35Sstevel 16203831d35Sstevel /* 16303831d35Sstevel * clean up an eventual pending request/response session 16403831d35Sstevel * (save its current status) 16503831d35Sstevel */ 16603831d35Sstevel if (dps->pending_request) { 16703831d35Sstevel flags = dps->req_resp.flags; 16803831d35Sstevel rmc_comm_dp_mcleanup(rcs); 16903831d35Sstevel } 17003831d35Sstevel 17103831d35Sstevel /* 17203831d35Sstevel * send the request message 17303831d35Sstevel */ 17403831d35Sstevel req.msg_type = request->msg_type; 17503831d35Sstevel req.msg_buf = (uint8_t *)request->msg_buf; 17603831d35Sstevel req.msg_msglen = (uint16_t)request->msg_len; 17703831d35Sstevel 17803831d35Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "send request=%x (URG)\n", 17903831d35Sstevel request->msg_type)); 18003831d35Sstevel 18103831d35Sstevel err = rmc_comm_dp_msend(rcs, &req); 18203831d35Sstevel 18303831d35Sstevel /* 18403831d35Sstevel * wait for fifos to drain 18503831d35Sstevel */ 18603831d35Sstevel rmc_comm_serdev_drain(rcs); 18703831d35Sstevel 18803831d35Sstevel /* 18903831d35Sstevel * clean up the current session 19003831d35Sstevel */ 19103831d35Sstevel rmc_comm_dp_mcleanup(rcs); 19203831d35Sstevel 19303831d35Sstevel /* 19403831d35Sstevel * abort an old session (if any) 19503831d35Sstevel */ 19603831d35Sstevel if (dps->pending_request) { 19703831d35Sstevel dps->req_resp.flags = flags; 19803831d35Sstevel dp_wake_up_waiter(rcs, MSG_ERROR); 19903831d35Sstevel } 20003831d35Sstevel } 20103831d35Sstevel 20203831d35Sstevel mutex_exit(dps->dp_mutex); 20303831d35Sstevel 20403831d35Sstevel } else { 20503831d35Sstevel 20603831d35Sstevel /* 20703831d35Sstevel * Get an 'independent' thread (rmc_comm_send_pend_req) 20803831d35Sstevel * to send this request (since the calling thread does not 20903831d35Sstevel * want to wait). Copy the request in the drvintf state 21003831d35Sstevel * structure and signal the thread. 21103831d35Sstevel */ 21203831d35Sstevel 21303831d35Sstevel dis = &rcs->drvi_state; 21403831d35Sstevel 21503831d35Sstevel mutex_enter(dis->dreq_mutex); 21603831d35Sstevel 21703831d35Sstevel if (dis->dreq_state == RMC_COMM_DREQ_ST_WAIT) { 21803831d35Sstevel 21903831d35Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "get to send request=%x\n", 22003831d35Sstevel request->msg_type)); 22103831d35Sstevel 22203831d35Sstevel /* 22303831d35Sstevel * copy the request in a temporary location 22403831d35Sstevel * (drvinf_state structure) and signal the thread 22503831d35Sstevel * that a request message has to be delivered 22603831d35Sstevel */ 22703831d35Sstevel 22803831d35Sstevel if (request->msg_len < DP_MAX_MSGLEN) { 22903831d35Sstevel dis->dreq_request.msg_type = request->msg_type; 23003831d35Sstevel dis->dreq_request.msg_len = request->msg_len; 23103831d35Sstevel dis->dreq_request.msg_buf = 23203831d35Sstevel dis->dreq_request_buf; 23303831d35Sstevel bcopy(request->msg_buf, 23403831d35Sstevel dis->dreq_request.msg_buf, 23503831d35Sstevel request->msg_len); 23603831d35Sstevel 23703831d35Sstevel dis->dreq_state = RMC_COMM_DREQ_ST_PROCESS; 23803831d35Sstevel cv_signal(dis->dreq_sig_cv); 23903831d35Sstevel 24003831d35Sstevel } else { 24103831d35Sstevel /* 24203831d35Sstevel * not enough space to hold the request 24303831d35Sstevel */ 24403831d35Sstevel err = RCEREPTOOBIG; 24503831d35Sstevel } 24603831d35Sstevel } else { 24703831d35Sstevel 24803831d35Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "cannot get to send " 24903831d35Sstevel "request=%x (busy)\n", request->msg_type)); 25003831d35Sstevel 25103831d35Sstevel /* 25203831d35Sstevel * only one request per time can be processed. 25303831d35Sstevel * the thread is either busy (RMC_COMM_DREQ_ST_PROCESS) 25403831d35Sstevel * or terminating (RMC_COMM_DREQ_ST_EXIT) 25503831d35Sstevel */ 25603831d35Sstevel err = RCEGENERIC; 25703831d35Sstevel } 25803831d35Sstevel 25903831d35Sstevel mutex_exit(dis->dreq_mutex); 26003831d35Sstevel } 26103831d35Sstevel 26203831d35Sstevel return (err); 26303831d35Sstevel } 26403831d35Sstevel 26503831d35Sstevel /* 26603831d35Sstevel * Function used to send a request and (eventually) wait for a response. 26703831d35Sstevel * It can be called from a leaf driver (via rmc_comm_request_response) or 26803831d35Sstevel * from the thread in charge of sending 'no-wait' requests 26903831d35Sstevel * (rmc_comm_send_pend_req). 27003831d35Sstevel */ 27103831d35Sstevel static int 27203831d35Sstevel rmc_comm_send_req_resp(struct rmc_comm_state *rcs, rmc_comm_msg_t *request, 27303831d35Sstevel rmc_comm_msg_t *response, uint32_t wait_time) 27403831d35Sstevel { 27503831d35Sstevel rmc_comm_dp_state_t *dps; 27603831d35Sstevel dp_req_resp_t *drr; 27703831d35Sstevel dp_message_t *exp_resp; 27803831d35Sstevel dp_message_t req; 279*d3d50737SRafael Vanoni clock_t resend_clockt, delta; 28003831d35Sstevel clock_t stop_clockt; 28103831d35Sstevel int err; 28203831d35Sstevel 28303831d35Sstevel 28403831d35Sstevel /* 28503831d35Sstevel * just a sanity check... 28603831d35Sstevel */ 28703831d35Sstevel if (request == NULL) { 28803831d35Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "reqresp, invalid args\n")); 28903831d35Sstevel return (RCEINVARG); 29003831d35Sstevel } 29103831d35Sstevel 29203831d35Sstevel /* 29303831d35Sstevel * drivers cannot send control messages at all. They are meant to 29403831d35Sstevel * be used at low level only. 29503831d35Sstevel */ 29603831d35Sstevel if (!IS_NUMBERED_MSG(request->msg_type)) { 29703831d35Sstevel DPRINTF(rcs, DAPI, (CE_CONT, 29803831d35Sstevel "reqresp, ctrl msg not allowed! req type=%x\n", 29903831d35Sstevel request->msg_type)); 30003831d35Sstevel return (RCEINVARG); 30103831d35Sstevel } 30203831d35Sstevel 30303831d35Sstevel dps = &rcs->dp_state; 30403831d35Sstevel drr = &dps->req_resp; 30503831d35Sstevel exp_resp = &drr->response; 30603831d35Sstevel 3076fa6856eSarutz /* 3086fa6856eSarutz * Handle the case where we are called during panic 3096fa6856eSarutz * processing. If that occurs, then another thread in 3106fa6856eSarutz * rmc_comm might have been idled by panic() while 3116fa6856eSarutz * holding dp_mutex. As a result, do not unconditionally 3126fa6856eSarutz * grab dp_mutex. 3136fa6856eSarutz */ 3146fa6856eSarutz if (ddi_in_panic() != 0) { 3156fa6856eSarutz if (mutex_tryenter(dps->dp_mutex) == 0) { 3166fa6856eSarutz return (RCENODATALINK); 3176fa6856eSarutz } 3186fa6856eSarutz } else { 31903831d35Sstevel mutex_enter(dps->dp_mutex); 3206fa6856eSarutz } 32103831d35Sstevel 32203831d35Sstevel /* 32303831d35Sstevel * if the data link set up is suspended, just return. 32403831d35Sstevel * the only time that this can happen is during firmware download 32503831d35Sstevel * (see rmc_comm_request_response_bp). Basically, the data link is 32603831d35Sstevel * down and the timer for setting up the data link is not running. 32703831d35Sstevel */ 32803831d35Sstevel if (!dps->data_link_ok && 32903831d35Sstevel dps->timer_link_setup == (timeout_id_t)0) { 33003831d35Sstevel 33103831d35Sstevel mutex_exit(dps->dp_mutex); 33203831d35Sstevel return (RCENODATALINK); 33303831d35Sstevel } 33403831d35Sstevel 33503831d35Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "pending request=%d, req type=%x\n", 33603831d35Sstevel dps->pending_request, request->msg_type)); 33703831d35Sstevel 33803831d35Sstevel rmc_comm_wait_enable_to_send(rcs, dps); 33903831d35Sstevel 34003831d35Sstevel /* 34103831d35Sstevel * We now have control of the RMC. 34203831d35Sstevel * Place a lower limit on the shortest amount of time to be 34303831d35Sstevel * waited before timing out while communicating with the RMC 34403831d35Sstevel */ 34503831d35Sstevel if (wait_time < DP_MIN_TIMEOUT) 34603831d35Sstevel wait_time = DP_MIN_TIMEOUT; 34703831d35Sstevel 34803831d35Sstevel stop_clockt = ddi_get_lbolt() + drv_usectohz(wait_time * 1000); 34903831d35Sstevel 35003831d35Sstevel /* 35103831d35Sstevel * initialization of the request/response data structure 35203831d35Sstevel */ 35303831d35Sstevel drr->flags = 0; 35403831d35Sstevel drr->error_status = 0; 35503831d35Sstevel 35603831d35Sstevel /* 35703831d35Sstevel * set the 'expected reply' buffer: get the buffer already allocated 35803831d35Sstevel * for the response (if a reply is expected!) 35903831d35Sstevel */ 36003831d35Sstevel if (response != NULL) { 36103831d35Sstevel exp_resp->msg_type = response->msg_type; 36203831d35Sstevel exp_resp->msg_buf = (uint8_t *)response->msg_buf; 36303831d35Sstevel exp_resp->msg_msglen = (uint16_t)response->msg_bytes; 36403831d35Sstevel exp_resp->msg_bufsiz = (uint16_t)response->msg_len; 36503831d35Sstevel } else { 36603831d35Sstevel exp_resp->msg_type = DP_NULL_MSG; 36703831d35Sstevel exp_resp->msg_buf = (uint8_t)NULL; 36803831d35Sstevel exp_resp->msg_bufsiz = (uint16_t)0; 36903831d35Sstevel exp_resp->msg_msglen = (uint16_t)0; 37003831d35Sstevel } 37103831d35Sstevel 37203831d35Sstevel /* 37303831d35Sstevel * send the request message 37403831d35Sstevel */ 37503831d35Sstevel req.msg_type = request->msg_type; 37603831d35Sstevel req.msg_buf = (uint8_t *)request->msg_buf; 37703831d35Sstevel req.msg_msglen = (uint16_t)request->msg_len; 37803831d35Sstevel 37903831d35Sstevel /* 38003831d35Sstevel * send the message and wait for the reply or ACKnowledgment 38103831d35Sstevel * re-send the message if reply/ACK is not received in the 38203831d35Sstevel * timeframe defined 38303831d35Sstevel */ 38403831d35Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "send request=%x\n", request->msg_type)); 38503831d35Sstevel 386*d3d50737SRafael Vanoni delta = drv_usectohz(TX_RETRY_TIME * 1000); 387*d3d50737SRafael Vanoni 38803831d35Sstevel while ((err = rmc_comm_dp_msend(rcs, &req)) == RCNOERR) { 38903831d35Sstevel 390*d3d50737SRafael Vanoni resend_clockt = ddi_get_lbolt() + delta; 39103831d35Sstevel 39203831d35Sstevel /* 39303831d35Sstevel * wait for a reply or an acknowledgement 39403831d35Sstevel */ 395*d3d50737SRafael Vanoni (void) cv_reltimedwait(drr->cv_wait_reply, dps->dp_mutex, 396*d3d50737SRafael Vanoni delta, TR_CLOCK_TICK); 39703831d35Sstevel 39803831d35Sstevel DPRINTF(rcs, DAPI, (CE_CONT, 39903831d35Sstevel "reqresp send status: flags=%02x req=%x resp=%x tick=%ld\n", 40003831d35Sstevel drr->flags, request->msg_type, 40103831d35Sstevel response ? response->msg_type : -1, 40203831d35Sstevel stop_clockt - resend_clockt)); 40303831d35Sstevel 40403831d35Sstevel /* 40503831d35Sstevel * Check for error condition first 40603831d35Sstevel * Then, check if the command has been replied/ACKed 40703831d35Sstevel * Then, check if it has timeout and if there is any 40803831d35Sstevel * time left to resend the message. 40903831d35Sstevel */ 41003831d35Sstevel if ((drr->flags & MSG_ERROR) != 0) { 41103831d35Sstevel if (drr->error_status == 0) { 41203831d35Sstevel err = RCEGENERIC; 41303831d35Sstevel } else { 41403831d35Sstevel err = drr->error_status; 41503831d35Sstevel } 41603831d35Sstevel break; 41703831d35Sstevel 41803831d35Sstevel } else if (response != NULL && 41903831d35Sstevel (drr->flags & MSG_REPLY_RXED) != 0) { 42003831d35Sstevel /* 42103831d35Sstevel * yes! here is the reply 42203831d35Sstevel */ 42303831d35Sstevel 42403831d35Sstevel /* 42503831d35Sstevel * get the actual length of the msg 42603831d35Sstevel * a negative value means that the reply message 42703831d35Sstevel * was too big for the receiver buffer 42803831d35Sstevel */ 42903831d35Sstevel response->msg_bytes = exp_resp->msg_msglen; 43003831d35Sstevel if (response->msg_bytes < 0) 43103831d35Sstevel err = RCEREPTOOBIG; 43203831d35Sstevel else 43303831d35Sstevel err = RCNOERR; 43403831d35Sstevel break; 43503831d35Sstevel 43603831d35Sstevel } else if (response == NULL && (drr->flags & MSG_ACKED) != 0) { 43703831d35Sstevel /* 43803831d35Sstevel * yes! message has been acknowledged 43903831d35Sstevel */ 44003831d35Sstevel 44103831d35Sstevel err = RCNOERR; 44203831d35Sstevel break; 44303831d35Sstevel 44403831d35Sstevel } else if ((stop_clockt - resend_clockt) <= 0) { 44503831d35Sstevel /* 44603831d35Sstevel * no more time left. set the error code, 44703831d35Sstevel * exit the loop 44803831d35Sstevel */ 44903831d35Sstevel 45003831d35Sstevel err = RCETIMEOUT; 45103831d35Sstevel break; 45203831d35Sstevel } 45303831d35Sstevel } 45403831d35Sstevel 45503831d35Sstevel rmc_comm_dp_mcleanup(rcs); 45603831d35Sstevel 45703831d35Sstevel rmc_comm_wake_up_next(rcs); 45803831d35Sstevel 45903831d35Sstevel mutex_exit(dps->dp_mutex); 46003831d35Sstevel 46103831d35Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "reqresp end: err=%d, request=%x\n", 46203831d35Sstevel err, request->msg_type)); 46303831d35Sstevel 46403831d35Sstevel return (err); 46503831d35Sstevel } 46603831d35Sstevel 46703831d35Sstevel /* 46803831d35Sstevel * Function used to send a BP (Boot Prom) message and get the reply. 46903831d35Sstevel * BP protocol is provided only to support firmware download. 47003831d35Sstevel * 47103831d35Sstevel * This function will look for the following key BP protocol commands: 47203831d35Sstevel * BP_OBP_BOOTINIT: the data link is brought down so that request/response 47303831d35Sstevel * sessions cannot be started. The reason why is that this command will cause 47403831d35Sstevel * RMC fw to jump to the boot monitor (BOOTMON_FLASH) and data protocol is not 47503831d35Sstevel * operational. In this context, RMC fw will only be using the BP protocol. 47603831d35Sstevel * BP_OBP_RESET: data link setup timer is resumed. This command cause the RMC 47703831d35Sstevel * to reboot and hence become operational. 47803831d35Sstevel */ 47903831d35Sstevel int 48003831d35Sstevel rmc_comm_request_response_bp(rmc_comm_msg_t *request_bp, 48103831d35Sstevel rmc_comm_msg_t *response_bp, uint32_t wait_time) 48203831d35Sstevel { 48303831d35Sstevel struct rmc_comm_state *rcs; 48403831d35Sstevel rmc_comm_dp_state_t *dps; 48503831d35Sstevel dp_req_resp_t *drr; 48603831d35Sstevel dp_message_t *resp_bp; 48703831d35Sstevel bp_msg_t *bp_msg; 48803831d35Sstevel clock_t stop_clockt; 48903831d35Sstevel int err = RCNOERR; 49003831d35Sstevel boolean_t bootinit_sent = 0; 49103831d35Sstevel 49203831d35Sstevel /* 49303831d35Sstevel * get the soft state struct (instance 0) 49403831d35Sstevel */ 49503831d35Sstevel if ((rcs = rmc_comm_getstate(NULL, 0, 49603831d35Sstevel "rmc_comm_request_response_bp")) == NULL) 49703831d35Sstevel return (RCENOSOFTSTATE); 49803831d35Sstevel 49903831d35Sstevel /* 50003831d35Sstevel * sanity check: request_bp buffer must always be provided 50103831d35Sstevel */ 50203831d35Sstevel if (request_bp == NULL) { 50303831d35Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "reqresp_bp, invalid args\n")); 50403831d35Sstevel return (RCEINVARG); 50503831d35Sstevel } 50603831d35Sstevel 50703831d35Sstevel bp_msg = (bp_msg_t *)request_bp->msg_buf; 50803831d35Sstevel 50903831d35Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "send request_bp=%x\n", bp_msg->cmd)); 51003831d35Sstevel 51103831d35Sstevel /* 51203831d35Sstevel * only BP message can be sent 51303831d35Sstevel */ 51403831d35Sstevel if (!IS_BOOT_MSG(bp_msg->cmd)) { 51503831d35Sstevel DPRINTF(rcs, DAPI, (CE_CONT, 51603831d35Sstevel "reqresp_bp, only BP msg are allowed! type=%x\n", 51703831d35Sstevel bp_msg->cmd)); 51803831d35Sstevel return (RCEINVARG); 51903831d35Sstevel } 52003831d35Sstevel 52103831d35Sstevel dps = &rcs->dp_state; 52203831d35Sstevel drr = &dps->req_resp; 52303831d35Sstevel resp_bp = &drr->response; 52403831d35Sstevel 52503831d35Sstevel mutex_enter(dps->dp_mutex); 52603831d35Sstevel 52703831d35Sstevel rmc_comm_wait_enable_to_send(rcs, dps); 52803831d35Sstevel 52903831d35Sstevel /* 53003831d35Sstevel * Now, before sending the message, just check what it is being sent 53103831d35Sstevel * and take action accordingly. 53203831d35Sstevel * 53303831d35Sstevel * is it BP_OBP_BOOTINIT or BP_OBP_RESET command? 53403831d35Sstevel */ 53503831d35Sstevel if (bp_msg->cmd == BP_OBP_BOOTINIT) { 53603831d35Sstevel 53703831d35Sstevel /* 53803831d35Sstevel * bring down the protocol data link 53903831d35Sstevel * (must be done before aborting a request/response session) 54003831d35Sstevel */ 54103831d35Sstevel dps->data_link_ok = 0; 54203831d35Sstevel dps->timer_link_setup = (timeout_id_t)0; 54303831d35Sstevel 54403831d35Sstevel bootinit_sent = 1; 54503831d35Sstevel 54603831d35Sstevel } else if (bp_msg->cmd == BP_OBP_RESET) { 54703831d35Sstevel 54803831d35Sstevel /* 54903831d35Sstevel * restart the data link set up timer. RMC is coming up... 55003831d35Sstevel */ 55103831d35Sstevel 55203831d35Sstevel dp_reset(rcs, INITIAL_SEQID, 0, 1); 55303831d35Sstevel } 55403831d35Sstevel 55503831d35Sstevel /* 55603831d35Sstevel * initialization of the request/response data structure 55703831d35Sstevel */ 55803831d35Sstevel drr->flags = 0; 55903831d35Sstevel drr->error_status = 0; 56003831d35Sstevel 56103831d35Sstevel /* 56203831d35Sstevel * set the reply buffer: get the buffer already allocated 56303831d35Sstevel * for the response 56403831d35Sstevel */ 56503831d35Sstevel if (response_bp != NULL) { 56603831d35Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "expect BP reply. len=%d\n", 56703831d35Sstevel response_bp->msg_len)); 56803831d35Sstevel 56903831d35Sstevel resp_bp->msg_buf = (uint8_t *)response_bp->msg_buf; 57003831d35Sstevel resp_bp->msg_bufsiz = (uint16_t)response_bp->msg_len; 57103831d35Sstevel } 57203831d35Sstevel 57303831d35Sstevel /* 57403831d35Sstevel * send the BP message and wait for the reply 57503831d35Sstevel */ 57603831d35Sstevel 57703831d35Sstevel rmc_comm_bp_msend(rcs, bp_msg); 57803831d35Sstevel 57903831d35Sstevel if (response_bp != NULL) { 58003831d35Sstevel 58103831d35Sstevel /* 58203831d35Sstevel * place a lower limit on the shortest amount of time to be 58303831d35Sstevel * waited before timing out while communicating with the RMC 58403831d35Sstevel */ 58503831d35Sstevel if (wait_time < DP_MIN_TIMEOUT) 58603831d35Sstevel wait_time = DP_MIN_TIMEOUT; 58703831d35Sstevel 58803831d35Sstevel stop_clockt = ddi_get_lbolt() + drv_usectohz(wait_time * 1000); 58903831d35Sstevel 59003831d35Sstevel if ((err = rmc_comm_wait_bp_reply(rcs, dps, drr, 59103831d35Sstevel stop_clockt)) == RCNOERR) { 59203831d35Sstevel 59303831d35Sstevel /* 59403831d35Sstevel * get the actual length of the msg 59503831d35Sstevel * a negative value means that the reply message 59603831d35Sstevel * was too big for the receiver buffer 59703831d35Sstevel */ 59803831d35Sstevel response_bp->msg_bytes = resp_bp->msg_msglen; 59903831d35Sstevel if (response_bp->msg_bytes < 0) { 60003831d35Sstevel err = RCEREPTOOBIG; 60103831d35Sstevel 60203831d35Sstevel } else if (bootinit_sent) { 60303831d35Sstevel 60403831d35Sstevel /* 60503831d35Sstevel * BOOTINIT cmd may fail. In this is the case, 60603831d35Sstevel * the RMC is still operational. Hence, we 60703831d35Sstevel * try (once) to set up the data link 60803831d35Sstevel * protocol. 60903831d35Sstevel */ 61003831d35Sstevel bp_msg = (bp_msg_t *)response_bp->msg_buf; 61103831d35Sstevel 61203831d35Sstevel if (bp_msg->cmd == BP_RSC_BOOTFAIL && 61303831d35Sstevel bp_msg->dat1 == BP_DAT1_REJECTED) { 61403831d35Sstevel (void) rmc_comm_dp_ctlsend(rcs, 61503831d35Sstevel DP_CTL_START); 61603831d35Sstevel } 61703831d35Sstevel } 61803831d35Sstevel } 61903831d35Sstevel } 62003831d35Sstevel 62103831d35Sstevel rmc_comm_dp_mcleanup(rcs); 62203831d35Sstevel 62303831d35Sstevel rmc_comm_wake_up_next(rcs); 62403831d35Sstevel 62503831d35Sstevel mutex_exit(dps->dp_mutex); 62603831d35Sstevel 62703831d35Sstevel return (err); 62803831d35Sstevel } 62903831d35Sstevel 63003831d35Sstevel 63103831d35Sstevel /* 63203831d35Sstevel * to register for an asynchronous (via soft interrupt) notification 63303831d35Sstevel * of a message from the remote side (RMC) 63403831d35Sstevel */ 63503831d35Sstevel int 63603831d35Sstevel rmc_comm_reg_intr(uint8_t msg_type, rmc_comm_intrfunc_t intr_handler, 63703831d35Sstevel rmc_comm_msg_t *msgbuf, uint_t *state, kmutex_t *lock) 63803831d35Sstevel { 63903831d35Sstevel struct rmc_comm_state *rcs; 64003831d35Sstevel dp_msg_intr_t *msgintr; 64103831d35Sstevel int err = RCNOERR; 64203831d35Sstevel 64303831d35Sstevel if ((rcs = rmc_comm_getstate(NULL, 0, "rmc_comm_reg_intr")) == NULL) 64403831d35Sstevel return (RCENOSOFTSTATE); 64503831d35Sstevel 64603831d35Sstevel mutex_enter(rcs->dp_state.dp_mutex); 64703831d35Sstevel 64803831d35Sstevel msgintr = &rcs->dp_state.msg_intr; 64903831d35Sstevel 65003831d35Sstevel /* 65103831d35Sstevel * lock is required. If it is not defined, the 65203831d35Sstevel * interrupt handler routine cannot be registered. 65303831d35Sstevel */ 65403831d35Sstevel if (lock == NULL) { 65503831d35Sstevel mutex_exit(rcs->dp_state.dp_mutex); 65603831d35Sstevel return (RCEINVARG); 65703831d35Sstevel } 65803831d35Sstevel 65903831d35Sstevel /* 66003831d35Sstevel * only one interrupt handler can be registered. 66103831d35Sstevel */ 66203831d35Sstevel if (msgintr->intr_handler == NULL) { 66303831d35Sstevel 66403831d35Sstevel if (ddi_add_softintr(rcs->dip, DDI_SOFTINT_HIGH, 66503831d35Sstevel &msgintr->intr_id, NULL, NULL, intr_handler, 66603831d35Sstevel (caddr_t)msgbuf) == DDI_SUCCESS) { 66703831d35Sstevel 66803831d35Sstevel msgintr->intr_handler = intr_handler; 66903831d35Sstevel msgintr->intr_lock = lock; 67003831d35Sstevel msgintr->intr_state = state; 67103831d35Sstevel msgintr->intr_msg_type = msg_type; 67203831d35Sstevel msgintr->intr_arg = (caddr_t)msgbuf; 67303831d35Sstevel } else { 67403831d35Sstevel err = RCECANTREGINTR; 67503831d35Sstevel } 67603831d35Sstevel } else { 67703831d35Sstevel err = RCEALREADYREG; 67803831d35Sstevel } 67903831d35Sstevel 68003831d35Sstevel mutex_exit(rcs->dp_state.dp_mutex); 68103831d35Sstevel 68203831d35Sstevel return (err); 68303831d35Sstevel } 68403831d35Sstevel 68503831d35Sstevel /* 68603831d35Sstevel * To unregister for asynchronous notifications 68703831d35Sstevel */ 68803831d35Sstevel int 68903831d35Sstevel rmc_comm_unreg_intr(uint8_t msg_type, rmc_comm_intrfunc_t intr_handler) 69003831d35Sstevel { 69103831d35Sstevel struct rmc_comm_state *rcs; 69203831d35Sstevel dp_msg_intr_t *msgintr; 69303831d35Sstevel int err = RCNOERR; 69403831d35Sstevel 69503831d35Sstevel if ((rcs = rmc_comm_getstate(NULL, 0, "rmc_comm_unreg_intr")) == NULL) 69603831d35Sstevel return (RCENOSOFTSTATE); 69703831d35Sstevel 69803831d35Sstevel mutex_enter(rcs->dp_state.dp_mutex); 69903831d35Sstevel 70003831d35Sstevel msgintr = &rcs->dp_state.msg_intr; 70103831d35Sstevel 70203831d35Sstevel if (msgintr->intr_handler != NULL && 70303831d35Sstevel msgintr->intr_msg_type == msg_type && 70403831d35Sstevel msgintr->intr_handler == intr_handler) { 70503831d35Sstevel 70603831d35Sstevel ddi_remove_softintr(msgintr->intr_id); 70703831d35Sstevel msgintr->intr_handler = NULL; 70803831d35Sstevel msgintr->intr_id = 0; 70903831d35Sstevel msgintr->intr_msg_type = 0; 71003831d35Sstevel msgintr->intr_arg = NULL; 71103831d35Sstevel msgintr->intr_lock = NULL; 71203831d35Sstevel msgintr->intr_state = NULL; 71303831d35Sstevel } else { 71403831d35Sstevel err = RCEGENERIC; 71503831d35Sstevel } 71603831d35Sstevel 71703831d35Sstevel mutex_exit(rcs->dp_state.dp_mutex); 71803831d35Sstevel 71903831d35Sstevel return (err); 72003831d35Sstevel } 72103831d35Sstevel 72203831d35Sstevel /* 72303831d35Sstevel * To send raw data (firmware s-records) down to the RMC. 72403831d35Sstevel * It is provided only to support firmware download. 72503831d35Sstevel */ 72603831d35Sstevel int 72703831d35Sstevel rmc_comm_send_srecord_bp(caddr_t buf, int buflen, 72803831d35Sstevel rmc_comm_msg_t *response_bp, uint32_t wait_time) 72903831d35Sstevel { 73003831d35Sstevel struct rmc_comm_state *rcs; 73103831d35Sstevel rmc_comm_dp_state_t *dps; 73203831d35Sstevel dp_req_resp_t *drr; 73303831d35Sstevel dp_message_t *resp_bp; 73403831d35Sstevel clock_t stop_clockt; 73503831d35Sstevel int err; 73603831d35Sstevel 73703831d35Sstevel /* 73803831d35Sstevel * get the soft state struct (instance 0) 73903831d35Sstevel */ 74003831d35Sstevel if ((rcs = rmc_comm_getstate(NULL, 0, 74103831d35Sstevel "rmc_comm_request_response_bp")) == NULL) 74203831d35Sstevel return (RCENOSOFTSTATE); 74303831d35Sstevel 74403831d35Sstevel /* 74503831d35Sstevel * sanity check: response_bp buffer must always be provided 74603831d35Sstevel */ 74703831d35Sstevel if (buf == NULL || response_bp == NULL) { 74803831d35Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "send_srecord_bp,invalid args\n")); 74903831d35Sstevel return (RCEINVARG); 75003831d35Sstevel } 75103831d35Sstevel 75203831d35Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "send_srecord_bp, buflen=%d\n", buflen)); 75303831d35Sstevel 75403831d35Sstevel dps = &rcs->dp_state; 75503831d35Sstevel drr = &dps->req_resp; 75603831d35Sstevel resp_bp = &drr->response; 75703831d35Sstevel 75803831d35Sstevel mutex_enter(dps->dp_mutex); 75903831d35Sstevel 76003831d35Sstevel rmc_comm_wait_enable_to_send(rcs, dps); 76103831d35Sstevel 76203831d35Sstevel /* 76303831d35Sstevel * initialization of the request/response data structure 76403831d35Sstevel */ 76503831d35Sstevel drr->flags = 0; 76603831d35Sstevel drr->error_status = 0; 76703831d35Sstevel 76803831d35Sstevel /* 76903831d35Sstevel * set the reply buffer: get the buffer already allocated 77003831d35Sstevel * for the response 77103831d35Sstevel */ 77203831d35Sstevel resp_bp->msg_buf = (uint8_t *)response_bp->msg_buf; 77303831d35Sstevel resp_bp->msg_bufsiz = (uint16_t)response_bp->msg_len; 77403831d35Sstevel 77503831d35Sstevel /* 77603831d35Sstevel * send raw data (s-record) and wait for the reply (BP message) 77703831d35Sstevel */ 77803831d35Sstevel 77903831d35Sstevel rmc_comm_bp_srecsend(rcs, (char *)buf, buflen); 78003831d35Sstevel 78103831d35Sstevel /* 78203831d35Sstevel * place a lower limit on the shortest amount of time to be 78303831d35Sstevel * waited before timing out while communicating with the RMC 78403831d35Sstevel */ 78503831d35Sstevel if (wait_time < DP_MIN_TIMEOUT) 78603831d35Sstevel wait_time = DP_MIN_TIMEOUT; 78703831d35Sstevel 78803831d35Sstevel stop_clockt = ddi_get_lbolt() + drv_usectohz(wait_time * 1000); 78903831d35Sstevel 79003831d35Sstevel if ((err = rmc_comm_wait_bp_reply(rcs, dps, drr, 79103831d35Sstevel stop_clockt)) == RCNOERR) { 79203831d35Sstevel /* 79303831d35Sstevel * get the actual length of the msg 79403831d35Sstevel * a negative value means that the reply message 79503831d35Sstevel * was too big for the receiver buffer 79603831d35Sstevel */ 79703831d35Sstevel response_bp->msg_bytes = resp_bp->msg_msglen; 79803831d35Sstevel if (response_bp->msg_bytes < 0) { 79903831d35Sstevel err = RCEREPTOOBIG; 80003831d35Sstevel } 80103831d35Sstevel } 80203831d35Sstevel 80303831d35Sstevel rmc_comm_dp_mcleanup(rcs); 80403831d35Sstevel 80503831d35Sstevel rmc_comm_wake_up_next(rcs); 80603831d35Sstevel 80703831d35Sstevel mutex_exit(dps->dp_mutex); 80803831d35Sstevel 80903831d35Sstevel return (err); 81003831d35Sstevel } 81103831d35Sstevel 81203831d35Sstevel /* 81303831d35Sstevel * To wait for (any) BP message to be received. 81403831d35Sstevel * (dp_mutex must be held) 81503831d35Sstevel */ 81603831d35Sstevel static int 81703831d35Sstevel rmc_comm_wait_bp_reply(struct rmc_comm_state *rcs, rmc_comm_dp_state_t *dps, 81803831d35Sstevel dp_req_resp_t *drr, clock_t stop_clockt) 81903831d35Sstevel { 82003831d35Sstevel clock_t clockleft = 1; 82103831d35Sstevel int err = RCNOERR; 82203831d35Sstevel 82303831d35Sstevel clockleft = cv_timedwait(drr->cv_wait_reply, dps->dp_mutex, 82403831d35Sstevel stop_clockt); 82503831d35Sstevel 82603831d35Sstevel 82703831d35Sstevel DPRINTF(rcs, DAPI, (CE_CONT, 82803831d35Sstevel "reqresp_bp, send: flags=%02x, clktick left=%ld\n", 82903831d35Sstevel drr->flags, clockleft)); 83003831d35Sstevel 83103831d35Sstevel /* 83203831d35Sstevel * Check for error condition first. 83303831d35Sstevel * Then, check if it has timeout. 83403831d35Sstevel * Then, check if the command has been replied. 83503831d35Sstevel */ 83603831d35Sstevel if ((drr->flags & MSG_ERROR) != 0) { 83703831d35Sstevel 83803831d35Sstevel err = RCEGENERIC; 83903831d35Sstevel 84003831d35Sstevel } else if (clockleft <= 0) { 84103831d35Sstevel /* 84203831d35Sstevel * timeout 84303831d35Sstevel */ 84403831d35Sstevel 84503831d35Sstevel err = RCETIMEOUT; 84603831d35Sstevel 84703831d35Sstevel } else if ((drr->flags & MSG_RXED_BP) == 0) { 84803831d35Sstevel 84903831d35Sstevel err = RCEGENERIC; 85003831d35Sstevel } 85103831d35Sstevel 85203831d35Sstevel return (err); 85303831d35Sstevel } 85403831d35Sstevel 85503831d35Sstevel /* 85603831d35Sstevel * Wait for the pending_request flag to be cleared and acquire it for our 85703831d35Sstevel * own use. The caller is then allowed to start a new request/response 85803831d35Sstevel * session with the RMC. 85903831d35Sstevel * Note that all send-receive actions to the RMC include a time-out, so 86003831d35Sstevel * the pending-request must eventually go away - even if the RMC is down. 86103831d35Sstevel * Hence there is no need to timeout the wait action of this function. 86203831d35Sstevel * (dp_mutex must be held on entry). 86303831d35Sstevel */ 86403831d35Sstevel static void 86503831d35Sstevel rmc_comm_wait_enable_to_send(struct rmc_comm_state *rcs, 86603831d35Sstevel rmc_comm_dp_state_t *dps) 86703831d35Sstevel { 86803831d35Sstevel DPRINTF(rcs, DAPI, (CE_CONT, "pending request=%d\n", 86903831d35Sstevel dps->pending_request)); 87003831d35Sstevel 87103831d35Sstevel /* 87203831d35Sstevel * A new message can actually grab the lock before the thread 87303831d35Sstevel * that has just been signaled. Therefore, we need to double 87403831d35Sstevel * check to make sure that pending_request is not already set 87503831d35Sstevel * after we wake up. 87603831d35Sstevel * 87703831d35Sstevel * Potentially this could mean starvation for certain unfortunate 87803831d35Sstevel * threads that keep getting woken up and putting back to sleep. 87903831d35Sstevel * But the window of such contention is very small to begin with. 88003831d35Sstevel */ 88103831d35Sstevel 88203831d35Sstevel while (dps->pending_request) { 88303831d35Sstevel /* 88403831d35Sstevel * just 'sit and wait' until there are no pending requests 88503831d35Sstevel */ 88603831d35Sstevel 88703831d35Sstevel cv_wait(dps->cv_ok_to_send, dps->dp_mutex); 88803831d35Sstevel } 88903831d35Sstevel 89003831d35Sstevel /* 89103831d35Sstevel * now a request/response can be started. Set the flag so that nobody 89203831d35Sstevel * else will be able to send anything. 89303831d35Sstevel */ 89403831d35Sstevel dps->pending_request = 1; 89503831d35Sstevel } 89603831d35Sstevel 89703831d35Sstevel /* 89803831d35Sstevel * To wake up one of the threads (if any) waiting for starting a 89903831d35Sstevel * request/response session. 90003831d35Sstevel * (dp_mutex must be held) 90103831d35Sstevel */ 90203831d35Sstevel static void 90303831d35Sstevel rmc_comm_wake_up_next(struct rmc_comm_state *rcs) 90403831d35Sstevel { 90503831d35Sstevel /* 90603831d35Sstevel * wake up eventual waiting threads... 90703831d35Sstevel */ 90803831d35Sstevel 90903831d35Sstevel rcs->dp_state.pending_request = 0; 91003831d35Sstevel cv_signal(rcs->dp_state.cv_ok_to_send); 91103831d35Sstevel } 91203831d35Sstevel 91303831d35Sstevel 91403831d35Sstevel /* 91503831d35Sstevel * thread which delivers pending request message to the rmc. Some leaf drivers 91603831d35Sstevel * cannot afford to wait for a request to be replied/ACKed. Hence, a request 91703831d35Sstevel * message is stored temporarily in the state structure and this thread 91803831d35Sstevel * gets woken up to deliver it. 91903831d35Sstevel */ 92003831d35Sstevel static void 92103831d35Sstevel rmc_comm_send_pend_req(caddr_t arg) 92203831d35Sstevel { 92303831d35Sstevel struct rmc_comm_state *rcs; 92403831d35Sstevel rmc_comm_drvintf_state_t *dis; 92503831d35Sstevel callb_cpr_t cprinfo; 92603831d35Sstevel 92703831d35Sstevel if (arg == NULL) { 92803831d35Sstevel thread_exit(); 92903831d35Sstevel /* NOTREACHED */ 93003831d35Sstevel } 93103831d35Sstevel 93203831d35Sstevel rcs = (struct rmc_comm_state *)arg; 93303831d35Sstevel dis = &rcs->drvi_state; 93403831d35Sstevel 93503831d35Sstevel CALLB_CPR_INIT(&cprinfo, dis->dreq_mutex, callb_generic_cpr, 93603831d35Sstevel "rmc_comm_send_pend_req"); 93703831d35Sstevel 93803831d35Sstevel mutex_enter(dis->dreq_mutex); 93903831d35Sstevel 94003831d35Sstevel if (dis->dreq_state <= RMC_COMM_DREQ_ST_READY) 94103831d35Sstevel dis->dreq_state = RMC_COMM_DREQ_ST_WAIT; 94203831d35Sstevel 94303831d35Sstevel for (;;) { 94403831d35Sstevel 94503831d35Sstevel /* 94603831d35Sstevel * Wait for someone to tell me to continue. 94703831d35Sstevel */ 94803831d35Sstevel while (dis->dreq_state == RMC_COMM_DREQ_ST_WAIT) { 94903831d35Sstevel CALLB_CPR_SAFE_BEGIN(&cprinfo); 95003831d35Sstevel cv_wait(dis->dreq_sig_cv, dis->dreq_mutex); 95103831d35Sstevel CALLB_CPR_SAFE_END(&cprinfo, dis->dreq_mutex); 95203831d35Sstevel } 95303831d35Sstevel 95403831d35Sstevel /* RMC_COMM_DREQ_ST_EXIT implies signal by _detach(). */ 95503831d35Sstevel if (dis->dreq_state == RMC_COMM_DREQ_ST_EXIT) { 95603831d35Sstevel dis->dreq_state = RMC_COMM_DREQ_ST_NOTSTARTED; 95703831d35Sstevel dis->dreq_tid = 0; 95803831d35Sstevel 95903831d35Sstevel /* dis->dreq_mutex is held at this point! */ 96003831d35Sstevel CALLB_CPR_EXIT(&cprinfo); 96103831d35Sstevel 96203831d35Sstevel thread_exit(); 96303831d35Sstevel /* NOTREACHED */ 96403831d35Sstevel } 96503831d35Sstevel 96603831d35Sstevel ASSERT(dis->dreq_state == RMC_COMM_DREQ_ST_PROCESS); 96703831d35Sstevel mutex_exit(dis->dreq_mutex); 96803831d35Sstevel 96903831d35Sstevel /* 97003831d35Sstevel * deliver the request (and wait...) 97103831d35Sstevel */ 97252f4394bSjfrank while (rmc_comm_send_req_resp(rcs, &dis->dreq_request, NULL, 97352f4394bSjfrank RMC_COMM_DREQ_DEFAULT_TIME) == RCEGENERIC) { 97452f4394bSjfrank } 97503831d35Sstevel 97603831d35Sstevel mutex_enter(dis->dreq_mutex); 97703831d35Sstevel if (dis->dreq_state != RMC_COMM_DREQ_ST_EXIT) 97803831d35Sstevel dis->dreq_state = RMC_COMM_DREQ_ST_WAIT; 97903831d35Sstevel } 98003831d35Sstevel } 98103831d35Sstevel 98203831d35Sstevel /* 98303831d35Sstevel * start thread to deal with pending requests to be delivered asynchronously 98403831d35Sstevel * (i.e. leaf driver do not have to/cannot wait for a reply/ACk of a request) 98503831d35Sstevel */ 98603831d35Sstevel static int 98703831d35Sstevel rmc_comm_dreq_thread_start(struct rmc_comm_state *rcs) 98803831d35Sstevel { 98903831d35Sstevel rmc_comm_drvintf_state_t *dis = &rcs->drvi_state; 99003831d35Sstevel int err = 0; 99103831d35Sstevel kthread_t *tp; 99203831d35Sstevel 99303831d35Sstevel mutex_enter(dis->dreq_mutex); 99403831d35Sstevel 99503831d35Sstevel if (dis->dreq_state == RMC_COMM_DREQ_ST_NOTSTARTED) { 99603831d35Sstevel 99703831d35Sstevel tp = thread_create(NULL, 0, rmc_comm_send_pend_req, 99803831d35Sstevel (caddr_t)rcs, 0, &p0, TS_RUN, maxclsyspri); 99903831d35Sstevel dis->dreq_state = RMC_COMM_DREQ_ST_READY; 100003831d35Sstevel dis->dreq_tid = tp->t_did; 100103831d35Sstevel } 100203831d35Sstevel 100303831d35Sstevel mutex_exit(dis->dreq_mutex); 100403831d35Sstevel 100503831d35Sstevel return (err); 100603831d35Sstevel } 100703831d35Sstevel 100803831d35Sstevel /* 100903831d35Sstevel * stop the thread (to deliver pending request messages) 101003831d35Sstevel */ 101103831d35Sstevel static void 101203831d35Sstevel rmc_comm_dreq_thread_kill(struct rmc_comm_state *rcs) 101303831d35Sstevel { 101403831d35Sstevel rmc_comm_drvintf_state_t *dis = &rcs->drvi_state; 101503831d35Sstevel kt_did_t tid; 101603831d35Sstevel 101703831d35Sstevel mutex_enter(dis->dreq_mutex); 101803831d35Sstevel tid = dis->dreq_tid; 101903831d35Sstevel if (tid != 0) { 102003831d35Sstevel dis->dreq_state = RMC_COMM_DREQ_ST_EXIT; 102103831d35Sstevel dis->dreq_tid = 0; 102203831d35Sstevel cv_signal(dis->dreq_sig_cv); 102303831d35Sstevel } 102403831d35Sstevel mutex_exit(dis->dreq_mutex); 102503831d35Sstevel 102603831d35Sstevel /* 102703831d35Sstevel * Wait for rmc_comm_send_pend_req() to finish 102803831d35Sstevel */ 102903831d35Sstevel if (tid != 0) 103003831d35Sstevel thread_join(tid); 103103831d35Sstevel } 103203831d35Sstevel 103303831d35Sstevel /* 103403831d35Sstevel * init function - start thread to deal with pending requests (no-wait requests) 103503831d35Sstevel */ 103603831d35Sstevel int 103703831d35Sstevel rmc_comm_drvintf_init(struct rmc_comm_state *rcs) 103803831d35Sstevel { 103903831d35Sstevel int err = 0; 104003831d35Sstevel 104103831d35Sstevel DPRINTF(rcs, DGEN, (CE_CONT, "rmc_comm_drvintf_init\n")); 104203831d35Sstevel rcs->drvi_state.dreq_state = RMC_COMM_DREQ_ST_NOTSTARTED; 104303831d35Sstevel rcs->drvi_state.dreq_tid = 0; 104403831d35Sstevel 104503831d35Sstevel mutex_init(rcs->drvi_state.dreq_mutex, NULL, MUTEX_DRIVER, NULL); 104603831d35Sstevel cv_init(rcs->drvi_state.dreq_sig_cv, NULL, CV_DRIVER, NULL); 104703831d35Sstevel 104803831d35Sstevel err = rmc_comm_dreq_thread_start(rcs); 104903831d35Sstevel if (err != 0) { 105003831d35Sstevel cv_destroy(rcs->drvi_state.dreq_sig_cv); 105103831d35Sstevel mutex_destroy(rcs->drvi_state.dreq_mutex); 105203831d35Sstevel } 105303831d35Sstevel 105403831d35Sstevel DPRINTF(rcs, DGEN, (CE_CONT, "thread started? err=%d\n", err)); 105503831d35Sstevel 105603831d35Sstevel return (err); 105703831d35Sstevel } 105803831d35Sstevel 105903831d35Sstevel /* 106003831d35Sstevel * fini function - kill thread to deal with pending requests (no-wait requests) 106103831d35Sstevel */ 106203831d35Sstevel void 106303831d35Sstevel rmc_comm_drvintf_fini(struct rmc_comm_state *rcs) 106403831d35Sstevel { 106503831d35Sstevel DPRINTF(rcs, DGEN, (CE_CONT, "rmc_comm_drvintf_fini:stop thread\n")); 106603831d35Sstevel 106703831d35Sstevel rmc_comm_dreq_thread_kill(rcs); 106803831d35Sstevel 106903831d35Sstevel DPRINTF(rcs, DGEN, (CE_CONT, "rmc_comm_drvintf_fini:destroy Mx/CVs\n")); 107003831d35Sstevel 107103831d35Sstevel cv_destroy(rcs->drvi_state.dreq_sig_cv); 107203831d35Sstevel mutex_destroy(rcs->drvi_state.dreq_mutex); 107303831d35Sstevel } 1074