arcmsr: Support hibernation
PATCH 3/16 arcmsr: Support hibernation
From: Ching<[email protected]>
Adding code for supporting system hibernation
Signed-off-by Ching<[email protected]>
---
drivers/scsi/arcmsr/arcmsr_hba.c +86 -0
@@ -89,11 +89,15 @@ static int arcmsr_bios_param(struct scsistatic int arcmsr_queue_command (struct Scsi_Host *h,struct scsi_cmnd *cmd);static int arcmsr_probe (struct pci_dev *pdev,const struct pci_device_id *id); +static int arcmsr_suspend (struct pci_dev *pdev,pm_message_t state); +static int arcmsr_resume (struct pci_dev *pdev);static void arcmsr_remove (struct pci_dev *pdev);static void arcmsr_shutdown (struct pci_dev *pdev);static void arcmsr_iop_init (struct AdapterControlBlock *acb);static void arcmsr_free_ccb_pool (struct AdapterControlBlock *acb);static u32 arcmsr_disable_outbound_ints (struct AdapterControlBlock *acb); +static void arcmsr_enable_outbound_ints (struct AdapterControlBlock *acb, +u32 intmask_org);static void arcmsr_stop_adapter_bgrb (struct AdapterControlBlock *acb);static void arcmsr_flush_hba_cache (struct AdapterControlBlock *acb);static void arcmsr_flush_hbb_cache (struct AdapterControlBlock *acb);
@@ -167,6 +171,8 @@ static struct pci_driver arcmsr_pci_driv .id_table = arcmsr_device_id_table, .probe = arcmsr_probe, .remove = arcmsr_remove, + .suspend = arcmsr_suspend, + .resume = arcmsr_resume, .shutdown = arcmsr_shutdown, };/*
@@ -793,6 +799,86 @@ pci_disable_dev:return -ENODEV ; } +static int arcmsr_suspend (struct pci_dev *pdev,pm_message_t state) +{ +int i; +uint32_t intmask_org; +struct Scsi_Host *host =pci_get_drvdata (pdev); +struct AdapterControlBlock *acb = + (struct AdapterControlBlock *)host->hostdata; + + intmask_org =arcmsr_disable_outbound_ints (acb); +if (acb->acb_flags &ACB_F_MSI_ENABLED ) { +free_irq (pdev->irq, acb); +pci_disable_msi (pdev); + }else if (acb->acb_flags &ACB_F_MSIX_ENABLED ) { +for (i =0 ; i <ARCMST_NUM_MSIX_VECTORS ; i++) +free_irq (acb->entries[i].vector, acb); +pci_disable_msix (pdev); + }else +free_irq (pdev->irq, acb); +del_timer_sync (&acb->eternal_timer); +flush_scheduled_work (); +arcmsr_stop_adapter_bgrb (acb); +arcmsr_flush_adapter_cache (acb); +arcmsr_enable_outbound_ints (acb, intmask_org); +pci_set_drvdata (pdev, host); +pci_save_state (pdev); +pci_disable_device (pdev); +pci_set_power_state (pdev,pci_choose_state (pdev, state)); +return 0 ; +} + +static int arcmsr_resume (struct pci_dev *pdev) +{ +int error; +struct Scsi_Host *host =pci_get_drvdata (pdev); +struct AdapterControlBlock *acb = + (struct AdapterControlBlock *)host->hostdata; + +pci_set_power_state (pdev,PCI_D0 ); +pci_enable_wake (pdev,PCI_D0 ,0 ); +pci_restore_state (pdev); +if (pci_enable_device (pdev)) { +pr_warn ("%s: pci_enable_device error\n" , __func__); +return -ENODEV ; + } + error =pci_set_dma_mask (pdev,DMA_BIT_MASK (64 )); +if (error) { + error =pci_set_dma_mask (pdev,DMA_BIT_MASK (32 )); +if (error) { +pr_warn ("scsi%d: No suitable DMA mask available\n" , + host->host_no); + goto controller_unregister; + } + } +pci_set_master (pdev); +if (arcmsr_request_irq (pdev, acb) ==ARC_FAILURE ) + goto controller_stop; +arcmsr_iop_init (acb); +INIT_WORK (&acb->arcmsr_do_message_isr_bh, arcmsr_message_isr_bh_fn); +atomic_set (&acb->rq_map_token,16 ); +atomic_set (&acb->ante_token_value,16 ); + acb->fw_flag =FW_NORMAL ; +init_timer (&acb->eternal_timer); + acb->eternal_timer.expires = jiffies +msecs_to_jiffies (6 *HZ ); + acb->eternal_timer.data = (unsigned long ) acb; + acb->eternal_timer.function = &arcmsr_request_device_map; +add_timer (&acb->eternal_timer); +return 0 ; +controller_stop: +arcmsr_stop_adapter_bgrb (acb); +arcmsr_flush_adapter_cache (acb); +controller_unregister: +scsi_remove_host (host); +arcmsr_free_ccb_pool (acb); +arcmsr_unmap_pciregion (acb); +pci_release_regions (pdev); +scsi_host_put (host); +pci_disable_device (pdev); +return -ENODEV ; +} +static uint8_t arcmsr_abort_hba_allcmd (struct AdapterControlBlock *acb) {struct MessageUnit_A __iomem *reg = acb->pmuA;