|
@@ -49,6 +49,10 @@
|
|
|
#define DRV_NAME "ahci"
|
|
|
#define DRV_VERSION "3.0"
|
|
|
|
|
|
+static int ahci_skip_host_reset;
|
|
|
+module_param_named(skip_host_reset, ahci_skip_host_reset, int, 0444);
|
|
|
+MODULE_PARM_DESC(skip_host_reset, "skip global host reset (0=don't skip, 1=skip)");
|
|
|
+
|
|
|
static int ahci_enable_alpm(struct ata_port *ap,
|
|
|
enum link_pm policy);
|
|
|
static void ahci_disable_alpm(struct ata_port *ap);
|
|
@@ -587,6 +591,7 @@ static const struct pci_device_id ahci_pci_tbl[] = {
|
|
|
|
|
|
/* Marvell */
|
|
|
{ PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv }, /* 6145 */
|
|
|
+ { PCI_VDEVICE(MARVELL, 0x6121), board_ahci_mv }, /* 6121 */
|
|
|
|
|
|
/* Generic, PCI class code for AHCI */
|
|
|
{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
|
|
@@ -661,6 +666,7 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
|
|
|
void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
|
|
|
u32 cap, port_map;
|
|
|
int i;
|
|
|
+ int mv;
|
|
|
|
|
|
/* make sure AHCI mode is enabled before accessing CAP */
|
|
|
ahci_enable_ahci(mmio);
|
|
@@ -696,12 +702,16 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
|
|
|
* presence register, as bit 4 (counting from 0)
|
|
|
*/
|
|
|
if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
|
|
|
+ if (pdev->device == 0x6121)
|
|
|
+ mv = 0x3;
|
|
|
+ else
|
|
|
+ mv = 0xf;
|
|
|
dev_printk(KERN_ERR, &pdev->dev,
|
|
|
"MV_AHCI HACK: port_map %x -> %x\n",
|
|
|
- hpriv->port_map,
|
|
|
- hpriv->port_map & 0xf);
|
|
|
+ port_map,
|
|
|
+ port_map & mv);
|
|
|
|
|
|
- port_map &= 0xf;
|
|
|
+ port_map &= mv;
|
|
|
}
|
|
|
|
|
|
/* cross check port_map and cap.n_ports */
|
|
@@ -1088,29 +1098,35 @@ static int ahci_reset_controller(struct ata_host *host)
|
|
|
ahci_enable_ahci(mmio);
|
|
|
|
|
|
/* 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 */
|
|
|
- }
|
|
|
+ if (!ahci_skip_host_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);
|
|
|
+ /* 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, host->dev,
|
|
|
- "controller reset failed (0x%x)\n", tmp);
|
|
|
- return -EIO;
|
|
|
- }
|
|
|
+ tmp = readl(mmio + HOST_CTL);
|
|
|
+ if (tmp & HOST_RESET) {
|
|
|
+ dev_printk(KERN_ERR, host->dev,
|
|
|
+ "controller reset failed (0x%x)\n", tmp);
|
|
|
+ return -EIO;
|
|
|
+ }
|
|
|
|
|
|
- /* turn on AHCI mode */
|
|
|
- ahci_enable_ahci(mmio);
|
|
|
+ /* turn on AHCI mode */
|
|
|
+ ahci_enable_ahci(mmio);
|
|
|
|
|
|
- /* some registers might be cleared on reset. restore initial values */
|
|
|
- ahci_restore_initial_config(host);
|
|
|
+ /* Some registers might be cleared on reset. Restore
|
|
|
+ * initial values.
|
|
|
+ */
|
|
|
+ ahci_restore_initial_config(host);
|
|
|
+ } else
|
|
|
+ dev_printk(KERN_INFO, host->dev,
|
|
|
+ "skipping global host reset\n");
|
|
|
|
|
|
if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
|
|
|
u16 tmp16;
|
|
@@ -1162,9 +1178,14 @@ static void ahci_init_controller(struct ata_host *host)
|
|
|
int i;
|
|
|
void __iomem *port_mmio;
|
|
|
u32 tmp;
|
|
|
+ int mv;
|
|
|
|
|
|
if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
|
|
|
- port_mmio = __ahci_port_base(host, 4);
|
|
|
+ if (pdev->device == 0x6121)
|
|
|
+ mv = 2;
|
|
|
+ else
|
|
|
+ mv = 4;
|
|
|
+ port_mmio = __ahci_port_base(host, mv);
|
|
|
|
|
|
writel(0, port_mmio + PORT_IRQ_MASK);
|
|
|
|
|
@@ -2241,7 +2262,10 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|
|
if (rc)
|
|
|
return rc;
|
|
|
|
|
|
- rc = pcim_iomap_regions(pdev, 1 << AHCI_PCI_BAR, DRV_NAME);
|
|
|
+ /* AHCI controllers often implement SFF compatible interface.
|
|
|
+ * Grab all PCI BARs just in case.
|
|
|
+ */
|
|
|
+ rc = pcim_iomap_regions_request_all(pdev, 1 << AHCI_PCI_BAR, DRV_NAME);
|
|
|
if (rc == -EBUSY)
|
|
|
pcim_pin_device(pdev);
|
|
|
if (rc)
|