]> nv-tegra.nvidia Code Review - linux-2.6.git/commitdiff
Merge branch 'upstream-fixes' into upstream
authorJeff Garzik <jeff@garzik.org>
Thu, 3 Aug 2006 21:35:48 +0000 (17:35 -0400)
committerJeff Garzik <jeff@garzik.org>
Thu, 3 Aug 2006 21:35:48 +0000 (17:35 -0400)
1  2 
drivers/scsi/ahci.c

diff --combined drivers/scsi/ahci.c
index 35058f9296d86e0fb8b475aad0984ee9809333ff,904c25fb4ba4a26678bf81e9b8bc4315714bed5f..f5734a97580a8396ed046dc2322799b4153337a3
@@@ -92,9 -92,7 +92,9 @@@ enum 
        HOST_AHCI_EN            = (1 << 31), /* AHCI enabled */
  
        /* HOST_CAP bits */
 +      HOST_CAP_SSC            = (1 << 14), /* Slumber capable */
        HOST_CAP_CLO            = (1 << 24), /* Command List Override support */
 +      HOST_CAP_SSS            = (1 << 27), /* Staggered Spin-up */
        HOST_CAP_NCQ            = (1 << 30), /* Native Command Queueing */
        HOST_CAP_64             = (1 << 31), /* PCI DAC (64-bit DMA) support */
  
        PORT_CMD_SPIN_UP        = (1 << 1), /* Spin up device */
        PORT_CMD_START          = (1 << 0), /* Enable port DMA engine */
  
 +      PORT_CMD_ICC_MASK       = (0xf << 28), /* i/f ICC state mask */
        PORT_CMD_ICC_ACTIVE     = (0x1 << 28), /* Put i/f in active state */
        PORT_CMD_ICC_PARTIAL    = (0x2 << 28), /* Put i/f in partial state */
        PORT_CMD_ICC_SLUMBER    = (0x6 << 28), /* Put i/f in slumber state */
@@@ -215,10 -212,6 +215,10 @@@ static void ahci_freeze(struct ata_por
  static void ahci_thaw(struct ata_port *ap);
  static void ahci_error_handler(struct ata_port *ap);
  static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
 +static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg);
 +static int ahci_port_resume(struct ata_port *ap);
 +static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
 +static int ahci_pci_device_resume(struct pci_dev *pdev);
  static void ahci_remove_one (struct pci_dev *pdev);
  
  static struct scsi_host_template ahci_sht = {
        .slave_configure        = ata_scsi_slave_config,
        .slave_destroy          = ata_scsi_slave_destroy,
        .bios_param             = ata_std_bios_param,
 +      .suspend                = ata_scsi_device_suspend,
 +      .resume                 = ata_scsi_device_resume,
  };
  
  static const struct ata_port_operations ahci_ops = {
        .error_handler          = ahci_error_handler,
        .post_internal_cmd      = ahci_post_internal_cmd,
  
 +      .port_suspend           = ahci_port_suspend,
 +      .port_resume            = ahci_port_resume,
 +
        .port_start             = ahci_port_start,
        .port_stop              = ahci_port_stop,
  };
@@@ -362,14 -350,6 +362,14 @@@ static const struct pci_device_id ahci_
        { PCI_VENDOR_ID_NVIDIA, 0x044f, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
          board_ahci },         /* MCP65 */
  
 +      /* SiS */
 +      { PCI_VENDOR_ID_SI, 0x1184, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 +        board_ahci }, /* SiS 966 */
 +      { PCI_VENDOR_ID_SI, 0x1185, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 +        board_ahci }, /* SiS 966 */
 +      { PCI_VENDOR_ID_SI, 0x0186, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 +        board_ahci }, /* SiS 968 */
 +
        { }     /* terminate list */
  };
  
@@@ -378,8 -358,6 +378,8 @@@ static struct pci_driver ahci_pci_drive
        .name                   = DRV_NAME,
        .id_table               = ahci_pci_tbl,
        .probe                  = ahci_init_one,
 +      .suspend                = ahci_pci_device_suspend,
 +      .resume                 = ahci_pci_device_resume,
        .remove                 = ahci_remove_one,
  };
  
@@@ -394,289 -372,177 +394,289 @@@ static inline void __iomem *ahci_port_b
        return (void __iomem *) ahci_port_base_ul((unsigned long)base, port);
  }
  
 -static int ahci_port_start(struct ata_port *ap)
 +static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in)
  {
 -      struct device *dev = ap->host_set->dev;
 -      struct ahci_host_priv *hpriv = ap->host_set->private_data;
 -      struct ahci_port_priv *pp;
 -      void __iomem *mmio = ap->host_set->mmio_base;
 -      void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
 -      void *mem;
 -      dma_addr_t mem_dma;
 -      int rc;
 -
 -      pp = kmalloc(sizeof(*pp), GFP_KERNEL);
 -      if (!pp)
 -              return -ENOMEM;
 -      memset(pp, 0, sizeof(*pp));
 +      unsigned int sc_reg;
  
 -      rc = ata_pad_alloc(ap, dev);
 -      if (rc) {
 -              kfree(pp);
 -              return rc;
 +      switch (sc_reg_in) {
 +      case SCR_STATUS:        sc_reg = 0; break;
 +      case SCR_CONTROL:       sc_reg = 1; break;
 +      case SCR_ERROR:         sc_reg = 2; break;
 +      case SCR_ACTIVE:        sc_reg = 3; break;
 +      default:
 +              return 0xffffffffU;
        }
  
 -      mem = dma_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma, GFP_KERNEL);
 -      if (!mem) {
 -              ata_pad_free(ap, dev);
 -              kfree(pp);
 -              return -ENOMEM;
 -      }
 -      memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ);
 +      return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
 +}
  
 -      /*
 -       * First item in chunk of DMA memory: 32-slot command table,
 -       * 32 bytes each in size
 -       */
 -      pp->cmd_slot = mem;
 -      pp->cmd_slot_dma = mem_dma;
  
 -      mem += AHCI_CMD_SLOT_SZ;
 -      mem_dma += AHCI_CMD_SLOT_SZ;
 +static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in,
 +                             u32 val)
 +{
 +      unsigned int sc_reg;
  
 -      /*
 -       * Second item: Received-FIS area
 -       */
 -      pp->rx_fis = mem;
 -      pp->rx_fis_dma = mem_dma;
 +      switch (sc_reg_in) {
 +      case SCR_STATUS:        sc_reg = 0; break;
 +      case SCR_CONTROL:       sc_reg = 1; break;
 +      case SCR_ERROR:         sc_reg = 2; break;
 +      case SCR_ACTIVE:        sc_reg = 3; break;
 +      default:
 +              return;
 +      }
  
 -      mem += AHCI_RX_FIS_SZ;
 -      mem_dma += AHCI_RX_FIS_SZ;
 +      writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
 +}
  
 -      /*
 -       * Third item: data area for storing a single command
 -       * and its scatter-gather table
 -       */
 -      pp->cmd_tbl = mem;
 -      pp->cmd_tbl_dma = mem_dma;
 +static void ahci_start_engine(void __iomem *port_mmio)
 +{
 +      u32 tmp;
  
 -      ap->private_data = pp;
 +      /* start DMA */
 +      tmp = readl(port_mmio + PORT_CMD);
 +      tmp |= PORT_CMD_START;
 +      writel(tmp, port_mmio + PORT_CMD);
 +      readl(port_mmio + PORT_CMD); /* flush */
 +}
  
 -      if (hpriv->cap & HOST_CAP_64)
 -              writel((pp->cmd_slot_dma >> 16) >> 16, port_mmio + PORT_LST_ADDR_HI);
 -      writel(pp->cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR);
 -      readl(port_mmio + PORT_LST_ADDR); /* flush */
 +static int ahci_stop_engine(void __iomem *port_mmio)
 +{
 +      u32 tmp;
  
 -      if (hpriv->cap & HOST_CAP_64)
 -              writel((pp->rx_fis_dma >> 16) >> 16, port_mmio + PORT_FIS_ADDR_HI);
 -      writel(pp->rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR);
 -      readl(port_mmio + PORT_FIS_ADDR); /* flush */
 +      tmp = readl(port_mmio + PORT_CMD);
  
 -      writel(PORT_CMD_ICC_ACTIVE | PORT_CMD_FIS_RX |
 -             PORT_CMD_POWER_ON | PORT_CMD_SPIN_UP |
 -             PORT_CMD_START, port_mmio + PORT_CMD);
 -      readl(port_mmio + PORT_CMD); /* flush */
 +      /* check if the HBA is idle */
 +      if ((tmp & (PORT_CMD_START | PORT_CMD_LIST_ON)) == 0)
 +              return 0;
 +
 +      /* setting HBA to idle */
 +      tmp &= ~PORT_CMD_START;
 +      writel(tmp, port_mmio + PORT_CMD);
 +
 +      /* wait for engine to stop. This could be as long as 500 msec */
 +      tmp = ata_wait_register(port_mmio + PORT_CMD,
 +                              PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500);
 +      if (tmp & PORT_CMD_LIST_ON)
 +              return -EIO;
  
        return 0;
  }
  
 +static void ahci_start_fis_rx(void __iomem *port_mmio, u32 cap,
 +                            dma_addr_t cmd_slot_dma, dma_addr_t rx_fis_dma)
 +{
 +      u32 tmp;
 +
 +      /* set FIS registers */
 +      if (cap & HOST_CAP_64)
 +              writel((cmd_slot_dma >> 16) >> 16, port_mmio + PORT_LST_ADDR_HI);
 +      writel(cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR);
  
 -static void ahci_port_stop(struct ata_port *ap)
 +      if (cap & HOST_CAP_64)
 +              writel((rx_fis_dma >> 16) >> 16, port_mmio + PORT_FIS_ADDR_HI);
 +      writel(rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR);
 +
 +      /* enable FIS reception */
 +      tmp = readl(port_mmio + PORT_CMD);
 +      tmp |= PORT_CMD_FIS_RX;
 +      writel(tmp, port_mmio + PORT_CMD);
 +
 +      /* flush */
 +      readl(port_mmio + PORT_CMD);
 +}
 +
 +static int ahci_stop_fis_rx(void __iomem *port_mmio)
  {
 -      struct device *dev = ap->host_set->dev;
 -      struct ahci_port_priv *pp = ap->private_data;
 -      void __iomem *mmio = ap->host_set->mmio_base;
 -      void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
        u32 tmp;
  
 +      /* disable FIS reception */
        tmp = readl(port_mmio + PORT_CMD);
 -      tmp &= ~(PORT_CMD_START | PORT_CMD_FIS_RX);
 +      tmp &= ~PORT_CMD_FIS_RX;
        writel(tmp, port_mmio + PORT_CMD);
 -      readl(port_mmio + PORT_CMD); /* flush */
  
 -      /* spec says 500 msecs for each PORT_CMD_{START,FIS_RX} bit, so
 -       * this is slightly incorrect.
 -       */
 -      msleep(500);
 +      /* wait for completion, spec says 500ms, give it 1000 */
 +      tmp = ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_FIS_ON,
 +                              PORT_CMD_FIS_ON, 10, 1000);
 +      if (tmp & PORT_CMD_FIS_ON)
 +              return -EBUSY;
  
 -      ap->private_data = NULL;
 -      dma_free_coherent(dev, AHCI_PORT_PRIV_DMA_SZ,
 -                        pp->cmd_slot, pp->cmd_slot_dma);
 -      ata_pad_free(ap, dev);
 -      kfree(pp);
 +      return 0;
  }
  
 -static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in)
 +static void ahci_power_up(void __iomem *port_mmio, u32 cap)
  {
 -      unsigned int sc_reg;
 +      u32 cmd;
  
 -      switch (sc_reg_in) {
 -      case SCR_STATUS:        sc_reg = 0; break;
 -      case SCR_CONTROL:       sc_reg = 1; break;
 -      case SCR_ERROR:         sc_reg = 2; break;
 -      case SCR_ACTIVE:        sc_reg = 3; break;
 -      default:
 -              return 0xffffffffU;
 +      cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
 +
 +      /* spin up device */
 +      if (cap & HOST_CAP_SSS) {
 +              cmd |= PORT_CMD_SPIN_UP;
 +              writel(cmd, port_mmio + PORT_CMD);
        }
  
 -      return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
 +      /* wake up link */
 +      writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD);
  }
  
 +static void ahci_power_down(void __iomem *port_mmio, u32 cap)
 +{
 +      u32 cmd, scontrol;
  
 -static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in,
 -                             u32 val)
 +      cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
 +
 +      if (cap & HOST_CAP_SSC) {
 +              /* enable transitions to slumber mode */
 +              scontrol = readl(port_mmio + PORT_SCR_CTL);
 +              if ((scontrol & 0x0f00) > 0x100) {
 +                      scontrol &= ~0xf00;
 +                      writel(scontrol, port_mmio + PORT_SCR_CTL);
 +              }
 +
 +              /* put device into slumber mode */
 +              writel(cmd | PORT_CMD_ICC_SLUMBER, port_mmio + PORT_CMD);
 +
 +              /* wait for the transition to complete */
 +              ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_ICC_SLUMBER,
 +                                PORT_CMD_ICC_SLUMBER, 1, 50);
 +      }
 +
 +      /* put device into listen mode */
 +      if (cap & HOST_CAP_SSS) {
 +              /* first set PxSCTL.DET to 0 */
 +              scontrol = readl(port_mmio + PORT_SCR_CTL);
 +              scontrol &= ~0xf;
 +              writel(scontrol, port_mmio + PORT_SCR_CTL);
 +
 +              /* then set PxCMD.SUD to 0 */
 +              cmd &= ~PORT_CMD_SPIN_UP;
 +              writel(cmd, port_mmio + PORT_CMD);
 +      }
 +}
 +
 +static void ahci_init_port(void __iomem *port_mmio, u32 cap,
 +                         dma_addr_t cmd_slot_dma, dma_addr_t rx_fis_dma)
  {
 -      unsigned int sc_reg;
 +      /* power up */
 +      ahci_power_up(port_mmio, cap);
  
 -      switch (sc_reg_in) {
 -      case SCR_STATUS:        sc_reg = 0; break;
 -      case SCR_CONTROL:       sc_reg = 1; break;
 -      case SCR_ERROR:         sc_reg = 2; break;
 -      case SCR_ACTIVE:        sc_reg = 3; break;
 -      default:
 -              return;
 +      /* enable FIS reception */
 +      ahci_start_fis_rx(port_mmio, cap, cmd_slot_dma, rx_fis_dma);
 +
 +      /* enable DMA */
 +      ahci_start_engine(port_mmio);
 +}
 +
 +static int ahci_deinit_port(void __iomem *port_mmio, u32 cap, const char **emsg)
 +{
 +      int rc;
 +
 +      /* disable DMA */
 +      rc = ahci_stop_engine(port_mmio);
 +      if (rc) {
 +              *emsg = "failed to stop engine";
 +              return rc;
        }
  
 -      writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
 +      /* disable FIS reception */
 +      rc = ahci_stop_fis_rx(port_mmio);
 +      if (rc) {
 +              *emsg = "failed stop FIS RX";
 +              return rc;
 +      }
 +
 +      /* put device into slumber mode */
 +      ahci_power_down(port_mmio, cap);
 +
 +      return 0;
  }
  
 -static int ahci_stop_engine(struct ata_port *ap)
 +static int ahci_reset_controller(void __iomem *mmio, struct pci_dev *pdev)
  {
 -      void __iomem *mmio = ap->host_set->mmio_base;
 -      void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
 -      int work;
 -      u32 tmp;
 +      u32 cap_save, tmp;
  
 -      tmp = readl(port_mmio + PORT_CMD);
 -      tmp &= ~PORT_CMD_START;
 -      writel(tmp, port_mmio + PORT_CMD);
 +      cap_save = readl(mmio + HOST_CAP);
 +      cap_save &= ( (1<<28) | (1<<17) );
 +      cap_save |= (1 << 27);
  
 -      /* wait for engine to stop.  TODO: this could be
 -       * as long as 500 msec
 +      /* global controller reset */
 +      tmp = readl(mmio + HOST_CTL);
 +      if ((tmp & HOST_RESET) == 0) {
 +              writel(tmp | HOST_RESET, mmio + HOST_CTL);
 +              readl(mmio + HOST_CTL); /* flush */
 +      }
 +
 +      /* reset must complete within 1 second, or
 +       * the hardware should be considered fried.
         */
 -      work = 1000;
 -      while (work-- > 0) {
 -              tmp = readl(port_mmio + PORT_CMD);
 -              if ((tmp & PORT_CMD_LIST_ON) == 0)
 -                      return 0;
 -              udelay(10);
 +      ssleep(1);
 +
 +      tmp = readl(mmio + HOST_CTL);
 +      if (tmp & HOST_RESET) {
 +              dev_printk(KERN_ERR, &pdev->dev,
 +                         "controller reset failed (0x%x)\n", tmp);
 +              return -EIO;
        }
  
 -      return -EIO;
 +      writel(HOST_AHCI_EN, mmio + HOST_CTL);
 +      (void) readl(mmio + HOST_CTL);  /* flush */
 +      writel(cap_save, mmio + HOST_CAP);
 +      writel(0xf, mmio + HOST_PORTS_IMPL);
 +      (void) readl(mmio + HOST_PORTS_IMPL);   /* flush */
 +
 +      if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
 +              u16 tmp16;
 +
 +              /* configure PCS */
 +              pci_read_config_word(pdev, 0x92, &tmp16);
 +              tmp16 |= 0xf;
 +              pci_write_config_word(pdev, 0x92, tmp16);
 +      }
 +
 +      return 0;
  }
  
 -static void ahci_start_engine(struct ata_port *ap)
 +static void ahci_init_controller(void __iomem *mmio, struct pci_dev *pdev,
 +                               int n_ports, u32 cap)
  {
 -      void __iomem *mmio = ap->host_set->mmio_base;
 -      void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
 +      int i, rc;
        u32 tmp;
  
 -      tmp = readl(port_mmio + PORT_CMD);
 -      tmp |= PORT_CMD_START;
 -      writel(tmp, port_mmio + PORT_CMD);
 -      readl(port_mmio + PORT_CMD); /* flush */
 +      for (i = 0; i < n_ports; i++) {
 +              void __iomem *port_mmio = ahci_port_base(mmio, i);
 +              const char *emsg = NULL;
 +
 +#if 0 /* BIOSen initialize this incorrectly */
 +              if (!(hpriv->port_map & (1 << i)))
 +                      continue;
 +#endif
 +
 +              /* make sure port is not active */
 +              rc = ahci_deinit_port(port_mmio, cap, &emsg);
 +              if (rc)
 +                      dev_printk(KERN_WARNING, &pdev->dev,
 +                                 "%s (%d)\n", emsg, rc);
 +
 +              /* clear SError */
 +              tmp = readl(port_mmio + PORT_SCR_ERR);
 +              VPRINTK("PORT_SCR_ERR 0x%x\n", tmp);
 +              writel(tmp, port_mmio + PORT_SCR_ERR);
 +
 +              /* clear & turn off port IRQ */
 +              tmp = readl(port_mmio + PORT_IRQ_STAT);
 +              VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
 +              if (tmp)
 +                      writel(tmp, port_mmio + PORT_IRQ_STAT);
 +
 +              writel(1 << i, mmio + HOST_IRQ_STAT);
 +              writel(0, port_mmio + PORT_IRQ_MASK);
 +      }
 +
 +      tmp = readl(mmio + HOST_CTL);
 +      VPRINTK("HOST_CTL 0x%x\n", tmp);
 +      writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL);
 +      tmp = readl(mmio + HOST_CTL);
 +      VPRINTK("HOST_CTL 0x%x\n", tmp);
  }
  
  static unsigned int ahci_dev_classify(struct ata_port *ap)
@@@ -760,7 -626,7 +760,7 @@@ static int ahci_softreset(struct ata_po
        }
  
        /* prepare for SRST (AHCI-1.1 10.4.1) */
 -      rc = ahci_stop_engine(ap);
 +      rc = ahci_stop_engine(port_mmio);
        if (rc) {
                reason = "failed to stop engine";
                goto fail_restart;
        }
  
        /* restart engine */
 -      ahci_start_engine(ap);
 +      ahci_start_engine(port_mmio);
  
        ata_tf_init(ap->device, &tf);
        fis = pp->cmd_tbl;
        return 0;
  
   fail_restart:
 -      ahci_start_engine(ap);
 +      ahci_start_engine(port_mmio);
   fail:
        ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
        return rc;
@@@ -851,13 -717,11 +851,13 @@@ static int ahci_hardreset(struct ata_po
        struct ahci_port_priv *pp = ap->private_data;
        u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
        struct ata_taskfile tf;
 +      void __iomem *mmio = ap->host_set->mmio_base;
 +      void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
        int rc;
  
        DPRINTK("ENTER\n");
  
 -      ahci_stop_engine(ap);
 +      ahci_stop_engine(port_mmio);
  
        /* clear D2H reception area to properly wait for D2H FIS */
        ata_tf_init(ap->device, &tf);
  
        rc = sata_std_hardreset(ap, class);
  
 -      ahci_start_engine(ap);
 +      ahci_start_engine(port_mmio);
  
        if (rc == 0 && ata_port_online(ap))
                *class = ahci_dev_classify(ap);
@@@ -1076,14 -940,8 +1076,8 @@@ static void ahci_host_intr(struct ata_p
                return;
  
        /* ignore interim PIO setup fis interrupts */
-       if (ata_tag_valid(ap->active_tag)) {
-               struct ata_queued_cmd *qc =
-                       ata_qc_from_tag(ap, ap->active_tag);
-               if (qc && qc->tf.protocol == ATA_PROT_PIO &&
-                   (status & PORT_IRQ_PIOS_FIS))
-                       return;
-       }
+       if (ata_tag_valid(ap->active_tag) && (status & PORT_IRQ_PIOS_FIS)) 
+               return;
  
        if (ata_ratelimit())
                ata_port_printk(ap, KERN_INFO, "spurious interrupt "
@@@ -1188,13 -1046,10 +1182,13 @@@ static void ahci_thaw(struct ata_port *
  
  static void ahci_error_handler(struct ata_port *ap)
  {
 +      void __iomem *mmio = ap->host_set->mmio_base;
 +      void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
 +
        if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
                /* restart engine */
 -              ahci_stop_engine(ap);
 -              ahci_start_engine(ap);
 +              ahci_stop_engine(port_mmio);
 +              ahci_start_engine(port_mmio);
        }
  
        /* perform recovery */
  static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
  {
        struct ata_port *ap = qc->ap;
 +      void __iomem *mmio = ap->host_set->mmio_base;
 +      void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
  
        if (qc->flags & ATA_QCFLAG_FAILED)
                qc->err_mask |= AC_ERR_OTHER;
  
        if (qc->err_mask) {
                /* make DMA engine forget about the failed command */
 -              ahci_stop_engine(ap);
 -              ahci_start_engine(ap);
 +              ahci_stop_engine(port_mmio);
 +              ahci_start_engine(port_mmio);
 +      }
 +}
 +
 +static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
 +{
 +      struct ahci_host_priv *hpriv = ap->host_set->private_data;
 +      struct ahci_port_priv *pp = ap->private_data;
 +      void __iomem *mmio = ap->host_set->mmio_base;
 +      void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
 +      const char *emsg = NULL;
 +      int rc;
 +
 +      rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg);
 +      if (rc) {
 +              ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc);
 +              ahci_init_port(port_mmio, hpriv->cap,
 +                             pp->cmd_slot_dma, pp->rx_fis_dma);
 +      }
 +
 +      return rc;
 +}
 +
 +static int ahci_port_resume(struct ata_port *ap)
 +{
 +      struct ahci_port_priv *pp = ap->private_data;
 +      struct ahci_host_priv *hpriv = ap->host_set->private_data;
 +      void __iomem *mmio = ap->host_set->mmio_base;
 +      void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
 +
 +      ahci_init_port(port_mmio, hpriv->cap, pp->cmd_slot_dma, pp->rx_fis_dma);
 +
 +      return 0;
 +}
 +
 +static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
 +{
 +      struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev);
 +      void __iomem *mmio = host_set->mmio_base;
 +      u32 ctl;
 +
 +      if (mesg.event == PM_EVENT_SUSPEND) {
 +              /* AHCI spec rev1.1 section 8.3.3:
 +               * Software must disable interrupts prior to requesting a
 +               * transition of the HBA to D3 state.
 +               */
 +              ctl = readl(mmio + HOST_CTL);
 +              ctl &= ~HOST_IRQ_EN;
 +              writel(ctl, mmio + HOST_CTL);
 +              readl(mmio + HOST_CTL); /* flush */
 +      }
 +
 +      return ata_pci_device_suspend(pdev, mesg);
 +}
 +
 +static int ahci_pci_device_resume(struct pci_dev *pdev)
 +{
 +      struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev);
 +      struct ahci_host_priv *hpriv = host_set->private_data;
 +      void __iomem *mmio = host_set->mmio_base;
 +      int rc;
 +
 +      ata_pci_device_do_resume(pdev);
 +
 +      if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
 +              rc = ahci_reset_controller(mmio, pdev);
 +              if (rc)
 +                      return rc;
 +
 +              ahci_init_controller(mmio, pdev, host_set->n_ports, hpriv->cap);
        }
 +
 +      ata_host_set_resume(host_set);
 +
 +      return 0;
 +}
 +
 +static int ahci_port_start(struct ata_port *ap)
 +{
 +      struct device *dev = ap->host_set->dev;
 +      struct ahci_host_priv *hpriv = ap->host_set->private_data;
 +      struct ahci_port_priv *pp;
 +      void __iomem *mmio = ap->host_set->mmio_base;
 +      void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
 +      void *mem;
 +      dma_addr_t mem_dma;
 +      int rc;
 +
 +      pp = kmalloc(sizeof(*pp), GFP_KERNEL);
 +      if (!pp)
 +              return -ENOMEM;
 +      memset(pp, 0, sizeof(*pp));
 +
 +      rc = ata_pad_alloc(ap, dev);
 +      if (rc) {
 +              kfree(pp);
 +              return rc;
 +      }
 +
 +      mem = dma_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma, GFP_KERNEL);
 +      if (!mem) {
 +              ata_pad_free(ap, dev);
 +              kfree(pp);
 +              return -ENOMEM;
 +      }
 +      memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ);
 +
 +      /*
 +       * First item in chunk of DMA memory: 32-slot command table,
 +       * 32 bytes each in size
 +       */
 +      pp->cmd_slot = mem;
 +      pp->cmd_slot_dma = mem_dma;
 +
 +      mem += AHCI_CMD_SLOT_SZ;
 +      mem_dma += AHCI_CMD_SLOT_SZ;
 +
 +      /*
 +       * Second item: Received-FIS area
 +       */
 +      pp->rx_fis = mem;
 +      pp->rx_fis_dma = mem_dma;
 +
 +      mem += AHCI_RX_FIS_SZ;
 +      mem_dma += AHCI_RX_FIS_SZ;
 +
 +      /*
 +       * Third item: data area for storing a single command
 +       * and its scatter-gather table
 +       */
 +      pp->cmd_tbl = mem;
 +      pp->cmd_tbl_dma = mem_dma;
 +
 +      ap->private_data = pp;
 +
 +      /* initialize port */
 +      ahci_init_port(port_mmio, hpriv->cap, pp->cmd_slot_dma, pp->rx_fis_dma);
 +
 +      return 0;
 +}
 +
 +static void ahci_port_stop(struct ata_port *ap)
 +{
 +      struct device *dev = ap->host_set->dev;
 +      struct ahci_host_priv *hpriv = ap->host_set->private_data;
 +      struct ahci_port_priv *pp = ap->private_data;
 +      void __iomem *mmio = ap->host_set->mmio_base;
 +      void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
 +      const char *emsg = NULL;
 +      int rc;
 +
 +      /* de-initialize port */
 +      rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg);
 +      if (rc)
 +              ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc);
 +
 +      ap->private_data = NULL;
 +      dma_free_coherent(dev, AHCI_PORT_PRIV_DMA_SZ,
 +                        pp->cmd_slot, pp->cmd_slot_dma);
 +      ata_pad_free(ap, dev);
 +      kfree(pp);
  }
  
  static void ahci_setup_port(struct ata_ioports *port, unsigned long base,
@@@ -1395,12 -1089,47 +1389,12 @@@ static int ahci_host_init(struct ata_pr
        struct ahci_host_priv *hpriv = probe_ent->private_data;
        struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
        void __iomem *mmio = probe_ent->mmio_base;
 -      u32 tmp, cap_save;
 -      unsigned int i, j, using_dac;
 +      unsigned int i, using_dac;
        int rc;
 -      void __iomem *port_mmio;
 -
 -      cap_save = readl(mmio + HOST_CAP);
 -      cap_save &= ( (1<<28) | (1<<17) );
 -      cap_save |= (1 << 27);
 -
 -      /* global controller reset */
 -      tmp = readl(mmio + HOST_CTL);
 -      if ((tmp & HOST_RESET) == 0) {
 -              writel(tmp | HOST_RESET, mmio + HOST_CTL);
 -              readl(mmio + HOST_CTL); /* flush */
 -      }
 -
 -      /* reset must complete within 1 second, or
 -       * the hardware should be considered fried.
 -       */
 -      ssleep(1);
 -
 -      tmp = readl(mmio + HOST_CTL);
 -      if (tmp & HOST_RESET) {
 -              dev_printk(KERN_ERR, &pdev->dev,
 -                         "controller reset failed (0x%x)\n", tmp);
 -              return -EIO;
 -      }
  
 -      writel(HOST_AHCI_EN, mmio + HOST_CTL);
 -      (void) readl(mmio + HOST_CTL);  /* flush */
 -      writel(cap_save, mmio + HOST_CAP);
 -      writel(0xf, mmio + HOST_PORTS_IMPL);
 -      (void) readl(mmio + HOST_PORTS_IMPL);   /* flush */
 -
 -      if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
 -              u16 tmp16;
 -
 -              pci_read_config_word(pdev, 0x92, &tmp16);
 -              tmp16 |= 0xf;
 -              pci_write_config_word(pdev, 0x92, tmp16);
 -      }
 +      rc = ahci_reset_controller(mmio, pdev);
 +      if (rc)
 +              return rc;
  
        hpriv->cap = readl(mmio + HOST_CAP);
        hpriv->port_map = readl(mmio + HOST_PORTS_IMPL);
                }
        }
  
 -      for (i = 0; i < probe_ent->n_ports; i++) {
 -#if 0 /* BIOSen initialize this incorrectly */
 -              if (!(hpriv->port_map & (1 << i)))
 -                      continue;
 -#endif
 -
 -              port_mmio = ahci_port_base(mmio, i);
 -              VPRINTK("mmio %p  port_mmio %p\n", mmio, port_mmio);
 -
 -              ahci_setup_port(&probe_ent->port[i],
 -                              (unsigned long) mmio, i);
 -
 -              /* make sure port is not active */
 -              tmp = readl(port_mmio + PORT_CMD);
 -              VPRINTK("PORT_CMD 0x%x\n", tmp);
 -              if (tmp & (PORT_CMD_LIST_ON | PORT_CMD_FIS_ON |
 -                         PORT_CMD_FIS_RX | PORT_CMD_START)) {
 -                      tmp &= ~(PORT_CMD_LIST_ON | PORT_CMD_FIS_ON |
 -                               PORT_CMD_FIS_RX | PORT_CMD_START);
 -                      writel(tmp, port_mmio + PORT_CMD);
 -                      readl(port_mmio + PORT_CMD); /* flush */
 -
 -                      /* spec says 500 msecs for each bit, so
 -                       * this is slightly incorrect.
 -                       */
 -                      msleep(500);
 -              }
 -
 -              writel(PORT_CMD_SPIN_UP, port_mmio + PORT_CMD);
 -
 -              j = 0;
 -              while (j < 100) {
 -                      msleep(10);
 -                      tmp = readl(port_mmio + PORT_SCR_STAT);
 -                      if ((tmp & 0xf) == 0x3)
 -                              break;
 -                      j++;
 -              }
 -
 -              tmp = readl(port_mmio + PORT_SCR_ERR);
 -              VPRINTK("PORT_SCR_ERR 0x%x\n", tmp);
 -              writel(tmp, port_mmio + PORT_SCR_ERR);
 +      for (i = 0; i < probe_ent->n_ports; i++)
 +              ahci_setup_port(&probe_ent->port[i], (unsigned long) mmio, i);
  
 -              /* ack any pending irq events for this port */
 -              tmp = readl(port_mmio + PORT_IRQ_STAT);
 -              VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
 -              if (tmp)
 -                      writel(tmp, port_mmio + PORT_IRQ_STAT);
 -
 -              writel(1 << i, mmio + HOST_IRQ_STAT);
 -      }
 -
 -      tmp = readl(mmio + HOST_CTL);
 -      VPRINTK("HOST_CTL 0x%x\n", tmp);
 -      writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL);
 -      tmp = readl(mmio + HOST_CTL);
 -      VPRINTK("HOST_CTL 0x%x\n", tmp);
 +      ahci_init_controller(mmio, pdev, probe_ent->n_ports, hpriv->cap);
  
        pci_set_master(pdev);