Commit 061ef06a authored by Kevin Barnett's avatar Kevin Barnett Committed by Martin K. Petersen

scsi: smartpqi: add suspend and resume support

add support for ACPI S3 (suspend) and S4 (hibernate)
system power states.
Reviewed-by: default avatarScott Benesh <scott.benesh@microsemi.com>
Signed-off-by: default avatarKevin Barnett <kevin.barnett@microsemi.com>
Signed-off-by: default avatarDon Brace <don.brace@microsemi.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 7561a7e4
......@@ -61,7 +61,7 @@ struct pqi_device_registers {
/*
* controller registers
*
* These are defined by the PMC implementation.
* These are defined by the Microsemi implementation.
*
* Some registers (those named sis_*) are only used when in
* legacy SIS mode before we transition the controller into
......@@ -102,6 +102,12 @@ enum pqi_io_path {
AIO_PATH = 1
};
enum pqi_irq_mode {
IRQ_MODE_NONE,
IRQ_MODE_INTX,
IRQ_MODE_MSIX
};
struct pqi_sg_descriptor {
__le64 address;
__le32 length;
......@@ -908,7 +914,7 @@ struct pqi_ctrl_info {
dma_addr_t error_buffer_dma_handle;
size_t sg_chain_buffer_length;
unsigned int num_queue_groups;
unsigned int num_active_queue_groups;
u16 max_hw_queue_index;
u16 num_elements_per_iq;
u16 num_elements_per_oq;
u16 max_inbound_iu_length_per_firmware;
......@@ -923,6 +929,7 @@ struct pqi_ctrl_info {
struct pqi_admin_queues admin_queues;
struct pqi_queue_group queue_groups[PQI_MAX_QUEUE_GROUPS];
struct pqi_event_queue event_queue;
enum pqi_irq_mode irq_mode;
int max_msix_vectors;
int num_msix_vectors_enabled;
int num_msix_vectors_initialized;
......@@ -937,6 +944,7 @@ struct pqi_ctrl_info {
u8 outbound_spanning_supported : 1;
u8 pqi_mode_enabled : 1;
u8 heartbeat_timer_started : 1;
u8 update_time_worker_scheduled : 1;
struct list_head scsi_device_list;
spinlock_t scsi_device_list_lock;
......
This diff is collapsed.
......@@ -33,6 +33,7 @@
/* for submission of legacy SIS commands */
#define SIS_REENABLE_SIS_MODE 0x1
#define SIS_ENABLE_MSIX 0x40
#define SIS_ENABLE_INTX 0x80
#define SIS_SOFT_RESET 0x100
#define SIS_TRIGGER_SHUTDOWN 0x800000
#define SIS_CMD_READY 0x200
......@@ -56,6 +57,7 @@
#define SIS_CTRL_KERNEL_UP 0x80
#define SIS_CTRL_KERNEL_PANIC 0x100
#define SIS_CTRL_READY_TIMEOUT_SECS 30
#define SIS_CTRL_READY_RESUME_TIMEOUT_SECS 90
#define SIS_CTRL_READY_POLL_INTERVAL_MSECS 10
#pragma pack(1)
......@@ -79,12 +81,13 @@ struct sis_base_struct {
#pragma pack()
int sis_wait_for_ctrl_ready(struct pqi_ctrl_info *ctrl_info)
static int sis_wait_for_ctrl_ready_with_timeout(struct pqi_ctrl_info *ctrl_info,
unsigned int timeout_secs)
{
unsigned long timeout;
u32 status;
timeout = (SIS_CTRL_READY_TIMEOUT_SECS * HZ) + jiffies;
timeout = (timeout_secs * HZ) + jiffies;
while (1) {
status = readl(&ctrl_info->registers->sis_firmware_status);
......@@ -107,6 +110,18 @@ int sis_wait_for_ctrl_ready(struct pqi_ctrl_info *ctrl_info)
return 0;
}
int sis_wait_for_ctrl_ready(struct pqi_ctrl_info *ctrl_info)
{
return sis_wait_for_ctrl_ready_with_timeout(ctrl_info,
SIS_CTRL_READY_TIMEOUT_SECS);
}
int sis_wait_for_ctrl_ready_resume(struct pqi_ctrl_info *ctrl_info)
{
return sis_wait_for_ctrl_ready_with_timeout(ctrl_info,
SIS_CTRL_READY_RESUME_TIMEOUT_SECS);
}
bool sis_is_firmware_running(struct pqi_ctrl_info *ctrl_info)
{
bool running;
......@@ -315,6 +330,34 @@ int sis_init_base_struct_addr(struct pqi_ctrl_info *ctrl_info)
return rc;
}
#define SIS_DOORBELL_BIT_CLEAR_TIMEOUT_SECS 30
static void sis_wait_for_doorbell_bit_to_clear(
struct pqi_ctrl_info *ctrl_info, u32 bit)
{
u32 doorbell_register;
unsigned long timeout;
timeout = (SIS_DOORBELL_BIT_CLEAR_TIMEOUT_SECS * HZ) + jiffies;
while (1) {
doorbell_register =
readl(&ctrl_info->registers->sis_host_to_ctrl_doorbell);
if ((doorbell_register & bit) == 0)
break;
if (readl(&ctrl_info->registers->sis_firmware_status) &
SIS_CTRL_KERNEL_PANIC)
break;
if (time_after(jiffies, timeout)) {
dev_err(&ctrl_info->pci_dev->dev,
"doorbell register bit 0x%x not cleared\n",
bit);
break;
}
usleep_range(1000, 2000);
}
}
/* Enable MSI-X interrupts on the controller. */
void sis_enable_msix(struct pqi_ctrl_info *ctrl_info)
......@@ -327,6 +370,8 @@ void sis_enable_msix(struct pqi_ctrl_info *ctrl_info)
writel(doorbell_register,
&ctrl_info->registers->sis_host_to_ctrl_doorbell);
sis_wait_for_doorbell_bit_to_clear(ctrl_info, SIS_ENABLE_MSIX);
}
/* Disable MSI-X interrupts on the controller. */
......@@ -343,6 +388,32 @@ void sis_disable_msix(struct pqi_ctrl_info *ctrl_info)
&ctrl_info->registers->sis_host_to_ctrl_doorbell);
}
void sis_enable_intx(struct pqi_ctrl_info *ctrl_info)
{
u32 doorbell_register;
doorbell_register =
readl(&ctrl_info->registers->sis_host_to_ctrl_doorbell);
doorbell_register |= SIS_ENABLE_INTX;
writel(doorbell_register,
&ctrl_info->registers->sis_host_to_ctrl_doorbell);
sis_wait_for_doorbell_bit_to_clear(ctrl_info, SIS_ENABLE_INTX);
}
void sis_disable_intx(struct pqi_ctrl_info *ctrl_info)
{
u32 doorbell_register;
doorbell_register =
readl(&ctrl_info->registers->sis_host_to_ctrl_doorbell);
doorbell_register &= ~SIS_ENABLE_INTX;
writel(doorbell_register,
&ctrl_info->registers->sis_host_to_ctrl_doorbell);
}
void sis_soft_reset(struct pqi_ctrl_info *ctrl_info)
{
writel(SIS_SOFT_RESET,
......
......@@ -20,6 +20,7 @@
#define _SMARTPQI_SIS_H
int sis_wait_for_ctrl_ready(struct pqi_ctrl_info *ctrl_info);
int sis_wait_for_ctrl_ready_resume(struct pqi_ctrl_info *ctrl_info);
bool sis_is_firmware_running(struct pqi_ctrl_info *ctrl_info);
bool sis_is_kernel_up(struct pqi_ctrl_info *ctrl_info);
int sis_get_ctrl_properties(struct pqi_ctrl_info *ctrl_info);
......@@ -27,6 +28,8 @@ int sis_get_pqi_capabilities(struct pqi_ctrl_info *ctrl_info);
int sis_init_base_struct_addr(struct pqi_ctrl_info *ctrl_info);
void sis_enable_msix(struct pqi_ctrl_info *ctrl_info);
void sis_disable_msix(struct pqi_ctrl_info *ctrl_info);
void sis_enable_intx(struct pqi_ctrl_info *ctrl_info);
void sis_disable_intx(struct pqi_ctrl_info *ctrl_info);
void sis_soft_reset(struct pqi_ctrl_info *ctrl_info);
void sis_shutdown_ctrl(struct pqi_ctrl_info *ctrl_info);
int sis_reenable_sis_mode(struct pqi_ctrl_info *ctrl_info);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment