162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * IBM ASM Service Processor Device Driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) IBM Corporation, 2004 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Author: Max Asböck <amax@us.ibm.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "ibmasm.h" 1162306a36Sopenharmony_ci#include "dot_command.h" 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci/* 1462306a36Sopenharmony_ci * Dispatch an incoming message to the specific handler for the message. 1562306a36Sopenharmony_ci * Called from interrupt context. 1662306a36Sopenharmony_ci */ 1762306a36Sopenharmony_civoid ibmasm_receive_message(struct service_processor *sp, void *message, int message_size) 1862306a36Sopenharmony_ci{ 1962306a36Sopenharmony_ci u32 size; 2062306a36Sopenharmony_ci struct dot_command_header *header = (struct dot_command_header *)message; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci if (message_size == 0) 2362306a36Sopenharmony_ci return; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci size = get_dot_command_size(message); 2662306a36Sopenharmony_ci if (size == 0) 2762306a36Sopenharmony_ci return; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci if (size > message_size) 3062306a36Sopenharmony_ci size = message_size; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci switch (header->type) { 3362306a36Sopenharmony_ci case sp_event: 3462306a36Sopenharmony_ci ibmasm_receive_event(sp, message, size); 3562306a36Sopenharmony_ci break; 3662306a36Sopenharmony_ci case sp_command_response: 3762306a36Sopenharmony_ci ibmasm_receive_command_response(sp, message, size); 3862306a36Sopenharmony_ci break; 3962306a36Sopenharmony_ci case sp_heartbeat: 4062306a36Sopenharmony_ci ibmasm_receive_heartbeat(sp, message, size); 4162306a36Sopenharmony_ci break; 4262306a36Sopenharmony_ci default: 4362306a36Sopenharmony_ci dev_err(sp->dev, "Received unknown message from service processor\n"); 4462306a36Sopenharmony_ci } 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#define INIT_BUFFER_SIZE 32 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci/* 5262306a36Sopenharmony_ci * send the 4.3.5.10 dot command (driver VPD) to the service processor 5362306a36Sopenharmony_ci */ 5462306a36Sopenharmony_ciint ibmasm_send_driver_vpd(struct service_processor *sp) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci struct command *command; 5762306a36Sopenharmony_ci struct dot_command_header *header; 5862306a36Sopenharmony_ci u8 *vpd_command; 5962306a36Sopenharmony_ci u8 *vpd_data; 6062306a36Sopenharmony_ci int result = 0; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci command = ibmasm_new_command(sp, INIT_BUFFER_SIZE); 6362306a36Sopenharmony_ci if (command == NULL) 6462306a36Sopenharmony_ci return -ENOMEM; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci header = (struct dot_command_header *)command->buffer; 6762306a36Sopenharmony_ci header->type = sp_write; 6862306a36Sopenharmony_ci header->command_size = 4; 6962306a36Sopenharmony_ci header->data_size = 16; 7062306a36Sopenharmony_ci header->status = 0; 7162306a36Sopenharmony_ci header->reserved = 0; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci vpd_command = command->buffer + sizeof(struct dot_command_header); 7462306a36Sopenharmony_ci vpd_command[0] = 0x4; 7562306a36Sopenharmony_ci vpd_command[1] = 0x3; 7662306a36Sopenharmony_ci vpd_command[2] = 0x5; 7762306a36Sopenharmony_ci vpd_command[3] = 0xa; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci vpd_data = vpd_command + header->command_size; 8062306a36Sopenharmony_ci vpd_data[0] = 0; 8162306a36Sopenharmony_ci strcat(vpd_data, IBMASM_DRIVER_VPD); 8262306a36Sopenharmony_ci vpd_data[10] = 0; 8362306a36Sopenharmony_ci vpd_data[15] = 0; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci ibmasm_exec_command(sp, command); 8662306a36Sopenharmony_ci ibmasm_wait_for_response(command, IBMASM_CMD_TIMEOUT_NORMAL); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci if (command->status != IBMASM_CMD_COMPLETE) 8962306a36Sopenharmony_ci result = -ENODEV; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci command_put(command); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci return result; 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cistruct os_state_command { 9762306a36Sopenharmony_ci struct dot_command_header header; 9862306a36Sopenharmony_ci unsigned char command[3]; 9962306a36Sopenharmony_ci unsigned char data; 10062306a36Sopenharmony_ci}; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci/* 10362306a36Sopenharmony_ci * send the 4.3.6 dot command (os state) to the service processor 10462306a36Sopenharmony_ci * During driver init this function is called with os state "up". 10562306a36Sopenharmony_ci * This causes the service processor to start sending heartbeats the 10662306a36Sopenharmony_ci * driver. 10762306a36Sopenharmony_ci * During driver exit the function is called with os state "down", 10862306a36Sopenharmony_ci * causing the service processor to stop the heartbeats. 10962306a36Sopenharmony_ci */ 11062306a36Sopenharmony_ciint ibmasm_send_os_state(struct service_processor *sp, int os_state) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci struct command *cmd; 11362306a36Sopenharmony_ci struct os_state_command *os_state_cmd; 11462306a36Sopenharmony_ci int result = 0; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci cmd = ibmasm_new_command(sp, sizeof(struct os_state_command)); 11762306a36Sopenharmony_ci if (cmd == NULL) 11862306a36Sopenharmony_ci return -ENOMEM; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci os_state_cmd = (struct os_state_command *)cmd->buffer; 12162306a36Sopenharmony_ci os_state_cmd->header.type = sp_write; 12262306a36Sopenharmony_ci os_state_cmd->header.command_size = 3; 12362306a36Sopenharmony_ci os_state_cmd->header.data_size = 1; 12462306a36Sopenharmony_ci os_state_cmd->header.status = 0; 12562306a36Sopenharmony_ci os_state_cmd->command[0] = 4; 12662306a36Sopenharmony_ci os_state_cmd->command[1] = 3; 12762306a36Sopenharmony_ci os_state_cmd->command[2] = 6; 12862306a36Sopenharmony_ci os_state_cmd->data = os_state; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci ibmasm_exec_command(sp, cmd); 13162306a36Sopenharmony_ci ibmasm_wait_for_response(cmd, IBMASM_CMD_TIMEOUT_NORMAL); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci if (cmd->status != IBMASM_CMD_COMPLETE) 13462306a36Sopenharmony_ci result = -ENODEV; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci command_put(cmd); 13762306a36Sopenharmony_ci return result; 13862306a36Sopenharmony_ci} 139