/* Copyright (c) 2015, The Linux Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of The Linux Fundation, Inc. nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define RPM_REQ_MAGIC 0x00716572 #define RPM_CMD_MAGIC 0x00646d63 #define REQ_MSG_LENGTH 0x14 #define CMD_MSG_LENGTH 0x08 #define ACK_MSG_LENGTH 0x0C glink_handle_type rpm_glink_port, ssr_glink_port; static uint32_t msg_id; static event_t wait_for_rpm_init; static event_t wait_for_ssr_init; static event_t wait_for_data; extern glink_err_type glink_wait_link_down(glink_handle_type handle); glink_err_type rpm_glink_send_data(uint32_t *data, uint32_t len, msg_type type) { rpm_req req; rpm_cmd cmd; glink_err_type send_err = 0; uint32_t len_to_rpm = 0; void *rpm_data = NULL; event_init(&wait_for_data, false, EVENT_FLAG_AUTOUNSIGNAL); switch(type) { case RPM_REQUEST_TYPE: req.hdr.type = RPM_REQ_MAGIC; req.hdr.len = len + REQ_MSG_LENGTH;//20 req.req_hdr.id = ++msg_id; req.req_hdr.set = 0; req.req_hdr.resourceType = data[RESOURCETYPE]; req.req_hdr.resourceId = data[RESOURCEID]; req.req_hdr.dataLength = len; fill_kvp_object(&req.data, data, len); len_to_rpm = req.req_hdr.dataLength + 0x28; rpm_data = (void*) malloc(len_to_rpm); ASSERT(rpm_data); memset(rpm_data, 0, len_to_rpm); memcpy(rpm_data, &req.hdr, sizeof(rpm_gen_hdr)); memcpy(rpm_data + sizeof(rpm_gen_hdr), &req.req_hdr, sizeof(rpm_req_hdr)); memcpy(rpm_data + sizeof(rpm_gen_hdr)+ sizeof(rpm_req_hdr), req.data, len); // Send Data Request to RPM send_err = glink_tx(rpm_glink_port, NULL, (const void *)rpm_data, len_to_rpm, 0); if (send_err) { dprintf(CRITICAL, "%s:%d, Glink tx error: 0x%x\n", __func__, __LINE__, send_err); free(rpm_data); free_kvp_object(&req.data); break; } #ifdef DEBUG_GLINK dprintf(INFO, "%s:%d, Wait till we receive response from RPM\n", __func__, __LINE__); #endif event_wait(&wait_for_data); free(rpm_data); free_kvp_object(&req.data); break; case RPM_CMD_TYPE: cmd.hdr.type = RPM_CMD_MAGIC; cmd.hdr.len = CMD_MSG_LENGTH;//0x8; len_to_rpm = sizeof(rpm_cmd); fill_kvp_object(&cmd.data, data, len); send_err = glink_tx(rpm_glink_port, NULL, (const void *)&cmd, len_to_rpm, 0); if (send_err) dprintf(CRITICAL, "%s:%d, Glink tx error: 0x%x\n", __func__, __LINE__, send_err); free_kvp_object(&cmd.data); break; default: dprintf(CRITICAL, "Invalid RPM Request\n"); break; } return send_err; } uint32_t rpm_glink_recv_data(char *rx_buffer, uint32_t* len) { rpm_ack_msg *resp; msg_type type = 0; uint32_t ret = 0; /* As per the current design rpm response does not exceed 20 bytes */ if (rx_buffer == NULL) { dprintf(CRITICAL, "Invalid pointer to data received from RPM\n"); return 99; } resp = (rpm_ack_msg *)rx_buffer; if(resp->hdr.type == RPM_CMD_MAGIC) { type = RPM_CMD_TYPE; } else if(resp->hdr.type == RPM_REQ_MAGIC) { type = RPM_REQUEST_TYPE; } if (type == RPM_CMD_TYPE && resp->hdr.len == ACK_MSG_LENGTH) { dprintf(SPEW, "Received SUCCESS CMD ACK\n"); } else if (type == RPM_REQUEST_TYPE && resp->hdr.len == ACK_MSG_LENGTH) { dprintf(SPEW, "Received SUCCESS REQ ACK \n"); } else { ret = 1; dprintf(CRITICAL, "Received ERROR ACK \n"); } if(!ret) { ret = sizeof(rpm_gen_hdr) + sizeof(kvp_data); } #ifdef DEBUG_GLINK dprintf(INFO, "%s:%d Return value %u\n", __func__, __LINE__, ret); #endif return ret; } void rpm_vector_glink_ssr_isr(glink_handle_type port, void *unused_open_data, void *unused_pkt_priv, void *buffer, size_t size, size_t intent_used, glink_buffer_provider_fn vprovider, glink_buffer_provider_fn pprovider) { char rx_buffer[12]; char *return_buffer = NULL; uint32_t ret = 0; uint32_t offset = 0; size_t return_size = 0; #ifdef DEBUG_GLINK dprintf(INFO, "RPM Vector GLINK SSR ISR\n"); #endif if (size == 0) { dprintf(CRITICAL, "Invalid size of RPM response\n"); ASSERT(0); } if (size > sizeof(rx_buffer)) { dprintf(CRITICAL, "Need larger RPM rx buffer. Size of Local Buffer: %u\tSize of RX Buffer: %u\n", size, sizeof(rx_buffer)); ASSERT(0); } do { return_buffer = vprovider(buffer, offset, &return_size); if(return_buffer) { memcpy(rx_buffer+offset,return_buffer, return_size); offset += return_size; } } while(return_buffer); ret = rpm_glink_recv_data(rx_buffer,(uint32_t *)&size); if(ret) { dprintf(CRITICAL, "Return value from recv_data: %x\n", ret); } // Release the mutex #ifdef DEBUG_GLINK dprintf(INFO, "Received Data from RPM\n"); #endif event_signal(&wait_for_data, false); } void rpm_vector_glink_isr(glink_handle_type port, void *unused_open_data, void *unused_pkt_priv, void *buffer, size_t size, size_t intent_used, glink_buffer_provider_fn vprovider, glink_buffer_provider_fn pprovider) { char rx_buffer[64]; char *return_buffer = NULL; uint32_t ret = 0; uint32_t offset = 0; size_t return_size = 0; #ifdef DEBUG_GLINK dprintf(INFO, "RPM Vector GLINK ISR\n"); #endif if (size == 0) { dprintf(CRITICAL, "Invalid size of RPM response\n"); ASSERT(0); } if (size > sizeof(rx_buffer)) { dprintf(CRITICAL, "Need larger RPM rx buffer. Size of Local Buffer: %u\tSize of RX Buffer: %u\n", size, sizeof(rx_buffer)); ASSERT(0); } do { return_buffer = vprovider(buffer, offset, &return_size); if(return_buffer) { memcpy(rx_buffer+offset,return_buffer, return_size); offset += return_size; } } while(return_buffer); ret = rpm_glink_recv_data(rx_buffer, (uint32_t *)&size); if(ret) { dprintf(CRITICAL, "Return value from recv_data: %x\n", ret); } // Release the mutex #ifdef DEBUG_GLINK dprintf(INFO, "Received Data from RPM\n"); #endif event_signal(&wait_for_data, false); } void rpm_glink_notify_state_isr(glink_handle_type handle, void *data, glink_channel_event_type event) { if(event == GLINK_CONNECTED) { event_signal(&wait_for_rpm_init, false); dprintf(INFO, "Glink Connection between APPS and RPM established\n"); return; } } void rpm_glink_notify_state_ssr_isr(glink_handle_type handle, void *data, glink_channel_event_type event) { if(event == GLINK_CONNECTED) { event_signal(&wait_for_ssr_init, false); dprintf(INFO, "Glink Connection between APPS and RPM established\n"); return; } } void rpm_glink_tx_done_isr(void) { //empty function for tx_done cb. Nothing required here for now since we are always in //"single-threaded" operation of sending GLink requests return; } void rpm_glink_open(glink_link_info_type *link_info, void* priv) { glink_err_type ret; glink_open_config_type glink_open_cfg = {0}, glink_ssr_open_cfg = {0}; // Open channel for tx glink_open_cfg.name = "rpm_requests"; glink_open_cfg.remote_ss = link_info->remote_ss; glink_open_cfg.notify_rx = NULL; glink_open_cfg.notify_rxv = (glink_rxv_notification_cb)rpm_vector_glink_isr; glink_open_cfg.notify_tx_done = (glink_tx_notification_cb)rpm_glink_tx_done_isr; glink_open_cfg.notify_state = (glink_state_notification_cb)rpm_glink_notify_state_isr; glink_open_cfg.priv = NULL; ret = glink_open(&glink_open_cfg, &rpm_glink_port); if (ret == GLINK_STATUS_SUCCESS) dprintf(INFO, "Opening RPM Glink Port success\n"); else { dprintf(CRITICAL, "Opening RPM Glink Port failure %d\n", ret); ASSERT(0); } // Open Channel for tear down glink_ssr_open_cfg.name = "glink_ssr"; glink_ssr_open_cfg.remote_ss = link_info->remote_ss; glink_ssr_open_cfg.notify_rx = NULL; glink_ssr_open_cfg.notify_rxv = (glink_rxv_notification_cb)rpm_vector_glink_ssr_isr; glink_ssr_open_cfg.notify_tx_done = (glink_tx_notification_cb)rpm_glink_tx_done_isr; glink_ssr_open_cfg.notify_state = (glink_state_notification_cb)rpm_glink_notify_state_ssr_isr; glink_ssr_open_cfg.priv = NULL; ret = glink_open(&glink_ssr_open_cfg, &ssr_glink_port); if (ret == GLINK_STATUS_SUCCESS) dprintf(INFO, "Opening SSR Glink Port success\n"); else { dprintf(CRITICAL, "Opening SSR Glink Port failure %d\n", ret); ASSERT(0); } } void rpm_glink_init() { glink_err_type ret; glink_link_id_type link_id; event_init(&wait_for_rpm_init, false, EVENT_FLAG_AUTOUNSIGNAL); event_init(&wait_for_ssr_init, false, EVENT_FLAG_AUTOUNSIGNAL); dprintf(INFO, "RPM GLink Init\n"); // Initialize RPM transport ret = xport_rpm_init(NULL); if (ret == GLINK_STATUS_SUCCESS) { unmask_interrupt(GLINK_IPC_IRQ); GLINK_LINK_ID_STRUCT_INIT(link_id); link_id.remote_ss = "rpm"; link_id.link_notifier = (glink_link_state_notif_cb)rpm_glink_open; glink_register_link_state_cb(&link_id, NULL); } else { dprintf(CRITICAL, "RPM Glink Init Failure 0x%x\n", ret); ASSERT(0); } event_wait(&wait_for_rpm_init); event_wait(&wait_for_ssr_init); } void rpm_glink_uninit() { rpm_ssr_req req; glink_err_type ret; uint32_t len_to_rpm, loop = 100000; // update ssr request req.version = 0; req.cmd = 0; req.seqnumber = 0; memset(req.name, 0, sizeof(req.name)); strlcpy(req.name, "apss", sizeof(req.name)); req.namelength = strlen(req.name); len_to_rpm = sizeof(rpm_ssr_req); dprintf(INFO, "RPM GLINK UnInit\n"); ret = glink_tx(ssr_glink_port, NULL, (const void *)&req, len_to_rpm, 0); if (ret) { dprintf(CRITICAL, "Glink SSR Channel: Tx for link tear down request failure with error code: 0x%x\n", ret); ASSERT(0); } #ifdef DEBUG_GLINK dprintf(INFO, "%s:%d, Wait till we receive response from RPM\n", __func__, __LINE__); #endif // loop till the FIFO indices are cleared while((ret = glink_wait_link_down(ssr_glink_port)) && loop) { loop--; mdelay(1); continue; } if (!loop) { dprintf(INFO, "%s:%d, Tearing down Glink SSR Channel Timed out\n", __func__, __LINE__); ASSERT(0); } }