18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * driver for Microsemi PQI-based storage controllers 48c2ecf20Sopenharmony_ci * Copyright (c) 2019-2020 Microchip Technology Inc. and its subsidiaries 58c2ecf20Sopenharmony_ci * Copyright (c) 2016-2018 Microsemi Corporation 68c2ecf20Sopenharmony_ci * Copyright (c) 2016 PMC-Sierra, Inc. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Questions/Comments/Bugfixes to storagedev@microchip.com 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/delay.h> 158c2ecf20Sopenharmony_ci#include <linux/pci.h> 168c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h> 178c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 188c2ecf20Sopenharmony_ci#include "smartpqi.h" 198c2ecf20Sopenharmony_ci#include "smartpqi_sis.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/* legacy SIS interface commands */ 228c2ecf20Sopenharmony_ci#define SIS_CMD_GET_ADAPTER_PROPERTIES 0x19 238c2ecf20Sopenharmony_ci#define SIS_CMD_INIT_BASE_STRUCT_ADDRESS 0x1b 248c2ecf20Sopenharmony_ci#define SIS_CMD_GET_PQI_CAPABILITIES 0x3000 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/* for submission of legacy SIS commands */ 278c2ecf20Sopenharmony_ci#define SIS_REENABLE_SIS_MODE 0x1 288c2ecf20Sopenharmony_ci#define SIS_ENABLE_MSIX 0x40 298c2ecf20Sopenharmony_ci#define SIS_ENABLE_INTX 0x80 308c2ecf20Sopenharmony_ci#define SIS_SOFT_RESET 0x100 318c2ecf20Sopenharmony_ci#define SIS_CMD_READY 0x200 328c2ecf20Sopenharmony_ci#define SIS_TRIGGER_SHUTDOWN 0x800000 338c2ecf20Sopenharmony_ci#define SIS_PQI_RESET_QUIESCE 0x1000000 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#define SIS_CMD_COMPLETE 0x1000 368c2ecf20Sopenharmony_ci#define SIS_CLEAR_CTRL_TO_HOST_DOORBELL 0x1000 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define SIS_CMD_STATUS_SUCCESS 0x1 398c2ecf20Sopenharmony_ci#define SIS_CMD_COMPLETE_TIMEOUT_SECS 30 408c2ecf20Sopenharmony_ci#define SIS_CMD_COMPLETE_POLL_INTERVAL_MSECS 10 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* used with SIS_CMD_GET_ADAPTER_PROPERTIES command */ 438c2ecf20Sopenharmony_ci#define SIS_EXTENDED_PROPERTIES_SUPPORTED 0x800000 448c2ecf20Sopenharmony_ci#define SIS_SMARTARRAY_FEATURES_SUPPORTED 0x2 458c2ecf20Sopenharmony_ci#define SIS_PQI_MODE_SUPPORTED 0x4 468c2ecf20Sopenharmony_ci#define SIS_PQI_RESET_QUIESCE_SUPPORTED 0x8 478c2ecf20Sopenharmony_ci#define SIS_REQUIRED_EXTENDED_PROPERTIES \ 488c2ecf20Sopenharmony_ci (SIS_SMARTARRAY_FEATURES_SUPPORTED | SIS_PQI_MODE_SUPPORTED) 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci/* used with SIS_CMD_INIT_BASE_STRUCT_ADDRESS command */ 518c2ecf20Sopenharmony_ci#define SIS_BASE_STRUCT_REVISION 9 528c2ecf20Sopenharmony_ci#define SIS_BASE_STRUCT_ALIGNMENT 16 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci#define SIS_CTRL_KERNEL_UP 0x80 558c2ecf20Sopenharmony_ci#define SIS_CTRL_KERNEL_PANIC 0x100 568c2ecf20Sopenharmony_ci#define SIS_CTRL_READY_TIMEOUT_SECS 180 578c2ecf20Sopenharmony_ci#define SIS_CTRL_READY_RESUME_TIMEOUT_SECS 90 588c2ecf20Sopenharmony_ci#define SIS_CTRL_READY_POLL_INTERVAL_MSECS 10 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci#pragma pack(1) 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci/* for use with SIS_CMD_INIT_BASE_STRUCT_ADDRESS command */ 638c2ecf20Sopenharmony_cistruct sis_base_struct { 648c2ecf20Sopenharmony_ci __le32 revision; /* revision of this structure */ 658c2ecf20Sopenharmony_ci __le32 flags; /* reserved */ 668c2ecf20Sopenharmony_ci __le32 error_buffer_paddr_low; /* lower 32 bits of physical memory */ 678c2ecf20Sopenharmony_ci /* buffer for PQI error response */ 688c2ecf20Sopenharmony_ci /* data */ 698c2ecf20Sopenharmony_ci __le32 error_buffer_paddr_high; /* upper 32 bits of physical */ 708c2ecf20Sopenharmony_ci /* memory buffer for PQI */ 718c2ecf20Sopenharmony_ci /* error response data */ 728c2ecf20Sopenharmony_ci __le32 error_buffer_element_length; /* length of each PQI error */ 738c2ecf20Sopenharmony_ci /* response buffer element */ 748c2ecf20Sopenharmony_ci /* in bytes */ 758c2ecf20Sopenharmony_ci __le32 error_buffer_num_elements; /* total number of PQI error */ 768c2ecf20Sopenharmony_ci /* response buffers available */ 778c2ecf20Sopenharmony_ci}; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci#pragma pack() 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic int sis_wait_for_ctrl_ready_with_timeout(struct pqi_ctrl_info *ctrl_info, 828c2ecf20Sopenharmony_ci unsigned int timeout_secs) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci unsigned long timeout; 858c2ecf20Sopenharmony_ci u32 status; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci timeout = (timeout_secs * PQI_HZ) + jiffies; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci while (1) { 908c2ecf20Sopenharmony_ci status = readl(&ctrl_info->registers->sis_firmware_status); 918c2ecf20Sopenharmony_ci if (status != ~0) { 928c2ecf20Sopenharmony_ci if (status & SIS_CTRL_KERNEL_PANIC) { 938c2ecf20Sopenharmony_ci dev_err(&ctrl_info->pci_dev->dev, 948c2ecf20Sopenharmony_ci "controller is offline: status code 0x%x\n", 958c2ecf20Sopenharmony_ci readl( 968c2ecf20Sopenharmony_ci &ctrl_info->registers->sis_mailbox[7])); 978c2ecf20Sopenharmony_ci return -ENODEV; 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci if (status & SIS_CTRL_KERNEL_UP) 1008c2ecf20Sopenharmony_ci break; 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci if (time_after(jiffies, timeout)) { 1038c2ecf20Sopenharmony_ci dev_err(&ctrl_info->pci_dev->dev, 1048c2ecf20Sopenharmony_ci "controller not ready after %u seconds\n", 1058c2ecf20Sopenharmony_ci timeout_secs); 1068c2ecf20Sopenharmony_ci return -ETIMEDOUT; 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci msleep(SIS_CTRL_READY_POLL_INTERVAL_MSECS); 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci return 0; 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ciint sis_wait_for_ctrl_ready(struct pqi_ctrl_info *ctrl_info) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci return sis_wait_for_ctrl_ready_with_timeout(ctrl_info, 1178c2ecf20Sopenharmony_ci SIS_CTRL_READY_TIMEOUT_SECS); 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ciint sis_wait_for_ctrl_ready_resume(struct pqi_ctrl_info *ctrl_info) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci return sis_wait_for_ctrl_ready_with_timeout(ctrl_info, 1238c2ecf20Sopenharmony_ci SIS_CTRL_READY_RESUME_TIMEOUT_SECS); 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cibool sis_is_firmware_running(struct pqi_ctrl_info *ctrl_info) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci bool running; 1298c2ecf20Sopenharmony_ci u32 status; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci status = readl(&ctrl_info->registers->sis_firmware_status); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci if (status & SIS_CTRL_KERNEL_PANIC) 1348c2ecf20Sopenharmony_ci running = false; 1358c2ecf20Sopenharmony_ci else 1368c2ecf20Sopenharmony_ci running = true; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci if (!running) 1398c2ecf20Sopenharmony_ci dev_err(&ctrl_info->pci_dev->dev, 1408c2ecf20Sopenharmony_ci "controller is offline: status code 0x%x\n", 1418c2ecf20Sopenharmony_ci readl(&ctrl_info->registers->sis_mailbox[7])); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci return running; 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cibool sis_is_kernel_up(struct pqi_ctrl_info *ctrl_info) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci return readl(&ctrl_info->registers->sis_firmware_status) & 1498c2ecf20Sopenharmony_ci SIS_CTRL_KERNEL_UP; 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci/* used for passing command parameters/results when issuing SIS commands */ 1538c2ecf20Sopenharmony_cistruct sis_sync_cmd_params { 1548c2ecf20Sopenharmony_ci u32 mailbox[6]; /* mailboxes 0-5 */ 1558c2ecf20Sopenharmony_ci}; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic int sis_send_sync_cmd(struct pqi_ctrl_info *ctrl_info, 1588c2ecf20Sopenharmony_ci u32 cmd, struct sis_sync_cmd_params *params) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci struct pqi_ctrl_registers __iomem *registers; 1618c2ecf20Sopenharmony_ci unsigned int i; 1628c2ecf20Sopenharmony_ci unsigned long timeout; 1638c2ecf20Sopenharmony_ci u32 doorbell; 1648c2ecf20Sopenharmony_ci u32 cmd_status; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci registers = ctrl_info->registers; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci /* Write the command to mailbox 0. */ 1698c2ecf20Sopenharmony_ci writel(cmd, ®isters->sis_mailbox[0]); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci /* 1728c2ecf20Sopenharmony_ci * Write the command parameters to mailboxes 1-4 (mailbox 5 is not used 1738c2ecf20Sopenharmony_ci * when sending a command to the controller). 1748c2ecf20Sopenharmony_ci */ 1758c2ecf20Sopenharmony_ci for (i = 1; i <= 4; i++) 1768c2ecf20Sopenharmony_ci writel(params->mailbox[i], ®isters->sis_mailbox[i]); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci /* Clear the command doorbell. */ 1798c2ecf20Sopenharmony_ci writel(SIS_CLEAR_CTRL_TO_HOST_DOORBELL, 1808c2ecf20Sopenharmony_ci ®isters->sis_ctrl_to_host_doorbell_clear); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci /* Disable doorbell interrupts by masking all interrupts. */ 1838c2ecf20Sopenharmony_ci writel(~0, ®isters->sis_interrupt_mask); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci /* 1868c2ecf20Sopenharmony_ci * Force the completion of the interrupt mask register write before 1878c2ecf20Sopenharmony_ci * submitting the command. 1888c2ecf20Sopenharmony_ci */ 1898c2ecf20Sopenharmony_ci readl(®isters->sis_interrupt_mask); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci /* Submit the command to the controller. */ 1928c2ecf20Sopenharmony_ci writel(SIS_CMD_READY, ®isters->sis_host_to_ctrl_doorbell); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci /* 1958c2ecf20Sopenharmony_ci * Poll for command completion. Note that the call to msleep() is at 1968c2ecf20Sopenharmony_ci * the top of the loop in order to give the controller time to start 1978c2ecf20Sopenharmony_ci * processing the command before we start polling. 1988c2ecf20Sopenharmony_ci */ 1998c2ecf20Sopenharmony_ci timeout = (SIS_CMD_COMPLETE_TIMEOUT_SECS * PQI_HZ) + jiffies; 2008c2ecf20Sopenharmony_ci while (1) { 2018c2ecf20Sopenharmony_ci msleep(SIS_CMD_COMPLETE_POLL_INTERVAL_MSECS); 2028c2ecf20Sopenharmony_ci doorbell = readl(®isters->sis_ctrl_to_host_doorbell); 2038c2ecf20Sopenharmony_ci if (doorbell & SIS_CMD_COMPLETE) 2048c2ecf20Sopenharmony_ci break; 2058c2ecf20Sopenharmony_ci if (time_after(jiffies, timeout)) 2068c2ecf20Sopenharmony_ci return -ETIMEDOUT; 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci /* Read the command status from mailbox 0. */ 2108c2ecf20Sopenharmony_ci cmd_status = readl(®isters->sis_mailbox[0]); 2118c2ecf20Sopenharmony_ci if (cmd_status != SIS_CMD_STATUS_SUCCESS) { 2128c2ecf20Sopenharmony_ci dev_err(&ctrl_info->pci_dev->dev, 2138c2ecf20Sopenharmony_ci "SIS command failed for command 0x%x: status = 0x%x\n", 2148c2ecf20Sopenharmony_ci cmd, cmd_status); 2158c2ecf20Sopenharmony_ci return -EINVAL; 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci /* 2198c2ecf20Sopenharmony_ci * The command completed successfully, so save the command status and 2208c2ecf20Sopenharmony_ci * read the values returned in mailboxes 1-5. 2218c2ecf20Sopenharmony_ci */ 2228c2ecf20Sopenharmony_ci params->mailbox[0] = cmd_status; 2238c2ecf20Sopenharmony_ci for (i = 1; i < ARRAY_SIZE(params->mailbox); i++) 2248c2ecf20Sopenharmony_ci params->mailbox[i] = readl(®isters->sis_mailbox[i]); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci return 0; 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci/* 2308c2ecf20Sopenharmony_ci * This function verifies that we are talking to a controller that speaks PQI. 2318c2ecf20Sopenharmony_ci */ 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ciint sis_get_ctrl_properties(struct pqi_ctrl_info *ctrl_info) 2348c2ecf20Sopenharmony_ci{ 2358c2ecf20Sopenharmony_ci int rc; 2368c2ecf20Sopenharmony_ci u32 properties; 2378c2ecf20Sopenharmony_ci u32 extended_properties; 2388c2ecf20Sopenharmony_ci struct sis_sync_cmd_params params; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci memset(¶ms, 0, sizeof(params)); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci rc = sis_send_sync_cmd(ctrl_info, SIS_CMD_GET_ADAPTER_PROPERTIES, 2438c2ecf20Sopenharmony_ci ¶ms); 2448c2ecf20Sopenharmony_ci if (rc) 2458c2ecf20Sopenharmony_ci return rc; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci properties = params.mailbox[1]; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci if (!(properties & SIS_EXTENDED_PROPERTIES_SUPPORTED)) 2508c2ecf20Sopenharmony_ci return -ENODEV; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci extended_properties = params.mailbox[4]; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci if ((extended_properties & SIS_REQUIRED_EXTENDED_PROPERTIES) != 2558c2ecf20Sopenharmony_ci SIS_REQUIRED_EXTENDED_PROPERTIES) 2568c2ecf20Sopenharmony_ci return -ENODEV; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci if (extended_properties & SIS_PQI_RESET_QUIESCE_SUPPORTED) 2598c2ecf20Sopenharmony_ci ctrl_info->pqi_reset_quiesce_supported = true; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci return 0; 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ciint sis_get_pqi_capabilities(struct pqi_ctrl_info *ctrl_info) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci int rc; 2678c2ecf20Sopenharmony_ci struct sis_sync_cmd_params params; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci memset(¶ms, 0, sizeof(params)); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci rc = sis_send_sync_cmd(ctrl_info, SIS_CMD_GET_PQI_CAPABILITIES, 2728c2ecf20Sopenharmony_ci ¶ms); 2738c2ecf20Sopenharmony_ci if (rc) 2748c2ecf20Sopenharmony_ci return rc; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci ctrl_info->max_sg_entries = params.mailbox[1]; 2778c2ecf20Sopenharmony_ci ctrl_info->max_transfer_size = params.mailbox[2]; 2788c2ecf20Sopenharmony_ci ctrl_info->max_outstanding_requests = params.mailbox[3]; 2798c2ecf20Sopenharmony_ci ctrl_info->config_table_offset = params.mailbox[4]; 2808c2ecf20Sopenharmony_ci ctrl_info->config_table_length = params.mailbox[5]; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci return 0; 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ciint sis_init_base_struct_addr(struct pqi_ctrl_info *ctrl_info) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci int rc; 2888c2ecf20Sopenharmony_ci void *base_struct_unaligned; 2898c2ecf20Sopenharmony_ci struct sis_base_struct *base_struct; 2908c2ecf20Sopenharmony_ci struct sis_sync_cmd_params params; 2918c2ecf20Sopenharmony_ci unsigned long error_buffer_paddr; 2928c2ecf20Sopenharmony_ci dma_addr_t bus_address; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci base_struct_unaligned = kzalloc(sizeof(*base_struct) 2958c2ecf20Sopenharmony_ci + SIS_BASE_STRUCT_ALIGNMENT - 1, GFP_KERNEL); 2968c2ecf20Sopenharmony_ci if (!base_struct_unaligned) 2978c2ecf20Sopenharmony_ci return -ENOMEM; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci base_struct = PTR_ALIGN(base_struct_unaligned, 3008c2ecf20Sopenharmony_ci SIS_BASE_STRUCT_ALIGNMENT); 3018c2ecf20Sopenharmony_ci error_buffer_paddr = (unsigned long)ctrl_info->error_buffer_dma_handle; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci put_unaligned_le32(SIS_BASE_STRUCT_REVISION, &base_struct->revision); 3048c2ecf20Sopenharmony_ci put_unaligned_le32(lower_32_bits(error_buffer_paddr), 3058c2ecf20Sopenharmony_ci &base_struct->error_buffer_paddr_low); 3068c2ecf20Sopenharmony_ci put_unaligned_le32(upper_32_bits(error_buffer_paddr), 3078c2ecf20Sopenharmony_ci &base_struct->error_buffer_paddr_high); 3088c2ecf20Sopenharmony_ci put_unaligned_le32(PQI_ERROR_BUFFER_ELEMENT_LENGTH, 3098c2ecf20Sopenharmony_ci &base_struct->error_buffer_element_length); 3108c2ecf20Sopenharmony_ci put_unaligned_le32(ctrl_info->max_io_slots, 3118c2ecf20Sopenharmony_ci &base_struct->error_buffer_num_elements); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci bus_address = dma_map_single(&ctrl_info->pci_dev->dev, base_struct, 3148c2ecf20Sopenharmony_ci sizeof(*base_struct), DMA_TO_DEVICE); 3158c2ecf20Sopenharmony_ci if (dma_mapping_error(&ctrl_info->pci_dev->dev, bus_address)) { 3168c2ecf20Sopenharmony_ci rc = -ENOMEM; 3178c2ecf20Sopenharmony_ci goto out; 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci memset(¶ms, 0, sizeof(params)); 3218c2ecf20Sopenharmony_ci params.mailbox[1] = lower_32_bits((u64)bus_address); 3228c2ecf20Sopenharmony_ci params.mailbox[2] = upper_32_bits((u64)bus_address); 3238c2ecf20Sopenharmony_ci params.mailbox[3] = sizeof(*base_struct); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci rc = sis_send_sync_cmd(ctrl_info, SIS_CMD_INIT_BASE_STRUCT_ADDRESS, 3268c2ecf20Sopenharmony_ci ¶ms); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci dma_unmap_single(&ctrl_info->pci_dev->dev, bus_address, 3298c2ecf20Sopenharmony_ci sizeof(*base_struct), DMA_TO_DEVICE); 3308c2ecf20Sopenharmony_ciout: 3318c2ecf20Sopenharmony_ci kfree(base_struct_unaligned); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci return rc; 3348c2ecf20Sopenharmony_ci} 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci#define SIS_DOORBELL_BIT_CLEAR_TIMEOUT_SECS 30 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cistatic int sis_wait_for_doorbell_bit_to_clear( 3398c2ecf20Sopenharmony_ci struct pqi_ctrl_info *ctrl_info, u32 bit) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci int rc = 0; 3428c2ecf20Sopenharmony_ci u32 doorbell_register; 3438c2ecf20Sopenharmony_ci unsigned long timeout; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci timeout = (SIS_DOORBELL_BIT_CLEAR_TIMEOUT_SECS * PQI_HZ) + jiffies; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci while (1) { 3488c2ecf20Sopenharmony_ci doorbell_register = 3498c2ecf20Sopenharmony_ci readl(&ctrl_info->registers->sis_host_to_ctrl_doorbell); 3508c2ecf20Sopenharmony_ci if ((doorbell_register & bit) == 0) 3518c2ecf20Sopenharmony_ci break; 3528c2ecf20Sopenharmony_ci if (readl(&ctrl_info->registers->sis_firmware_status) & 3538c2ecf20Sopenharmony_ci SIS_CTRL_KERNEL_PANIC) { 3548c2ecf20Sopenharmony_ci rc = -ENODEV; 3558c2ecf20Sopenharmony_ci break; 3568c2ecf20Sopenharmony_ci } 3578c2ecf20Sopenharmony_ci if (time_after(jiffies, timeout)) { 3588c2ecf20Sopenharmony_ci dev_err(&ctrl_info->pci_dev->dev, 3598c2ecf20Sopenharmony_ci "doorbell register bit 0x%x not cleared\n", 3608c2ecf20Sopenharmony_ci bit); 3618c2ecf20Sopenharmony_ci rc = -ETIMEDOUT; 3628c2ecf20Sopenharmony_ci break; 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci return rc; 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistatic inline int sis_set_doorbell_bit(struct pqi_ctrl_info *ctrl_info, u32 bit) 3718c2ecf20Sopenharmony_ci{ 3728c2ecf20Sopenharmony_ci writel(bit, &ctrl_info->registers->sis_host_to_ctrl_doorbell); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci return sis_wait_for_doorbell_bit_to_clear(ctrl_info, bit); 3758c2ecf20Sopenharmony_ci} 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_civoid sis_enable_msix(struct pqi_ctrl_info *ctrl_info) 3788c2ecf20Sopenharmony_ci{ 3798c2ecf20Sopenharmony_ci sis_set_doorbell_bit(ctrl_info, SIS_ENABLE_MSIX); 3808c2ecf20Sopenharmony_ci} 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_civoid sis_enable_intx(struct pqi_ctrl_info *ctrl_info) 3838c2ecf20Sopenharmony_ci{ 3848c2ecf20Sopenharmony_ci sis_set_doorbell_bit(ctrl_info, SIS_ENABLE_INTX); 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_civoid sis_shutdown_ctrl(struct pqi_ctrl_info *ctrl_info) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci if (readl(&ctrl_info->registers->sis_firmware_status) & 3908c2ecf20Sopenharmony_ci SIS_CTRL_KERNEL_PANIC) 3918c2ecf20Sopenharmony_ci return; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci writel(SIS_TRIGGER_SHUTDOWN, 3948c2ecf20Sopenharmony_ci &ctrl_info->registers->sis_host_to_ctrl_doorbell); 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ciint sis_pqi_reset_quiesce(struct pqi_ctrl_info *ctrl_info) 3988c2ecf20Sopenharmony_ci{ 3998c2ecf20Sopenharmony_ci return sis_set_doorbell_bit(ctrl_info, SIS_PQI_RESET_QUIESCE); 4008c2ecf20Sopenharmony_ci} 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ciint sis_reenable_sis_mode(struct pqi_ctrl_info *ctrl_info) 4038c2ecf20Sopenharmony_ci{ 4048c2ecf20Sopenharmony_ci return sis_set_doorbell_bit(ctrl_info, SIS_REENABLE_SIS_MODE); 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_civoid sis_write_driver_scratch(struct pqi_ctrl_info *ctrl_info, u32 value) 4088c2ecf20Sopenharmony_ci{ 4098c2ecf20Sopenharmony_ci writel(value, &ctrl_info->registers->sis_driver_scratch); 4108c2ecf20Sopenharmony_ci} 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ciu32 sis_read_driver_scratch(struct pqi_ctrl_info *ctrl_info) 4138c2ecf20Sopenharmony_ci{ 4148c2ecf20Sopenharmony_ci return readl(&ctrl_info->registers->sis_driver_scratch); 4158c2ecf20Sopenharmony_ci} 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_civoid sis_soft_reset(struct pqi_ctrl_info *ctrl_info) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci writel(SIS_SOFT_RESET, 4208c2ecf20Sopenharmony_ci &ctrl_info->registers->sis_host_to_ctrl_doorbell); 4218c2ecf20Sopenharmony_ci} 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_cistatic void __attribute__((unused)) verify_structures(void) 4248c2ecf20Sopenharmony_ci{ 4258c2ecf20Sopenharmony_ci BUILD_BUG_ON(offsetof(struct sis_base_struct, 4268c2ecf20Sopenharmony_ci revision) != 0x0); 4278c2ecf20Sopenharmony_ci BUILD_BUG_ON(offsetof(struct sis_base_struct, 4288c2ecf20Sopenharmony_ci flags) != 0x4); 4298c2ecf20Sopenharmony_ci BUILD_BUG_ON(offsetof(struct sis_base_struct, 4308c2ecf20Sopenharmony_ci error_buffer_paddr_low) != 0x8); 4318c2ecf20Sopenharmony_ci BUILD_BUG_ON(offsetof(struct sis_base_struct, 4328c2ecf20Sopenharmony_ci error_buffer_paddr_high) != 0xc); 4338c2ecf20Sopenharmony_ci BUILD_BUG_ON(offsetof(struct sis_base_struct, 4348c2ecf20Sopenharmony_ci error_buffer_element_length) != 0x10); 4358c2ecf20Sopenharmony_ci BUILD_BUG_ON(offsetof(struct sis_base_struct, 4368c2ecf20Sopenharmony_ci error_buffer_num_elements) != 0x14); 4378c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(struct sis_base_struct) != 0x18); 4388c2ecf20Sopenharmony_ci} 439