diff options
| -rw-r--r-- | drivers/ata/ahci_xgene.c | 60 |
1 files changed, 47 insertions, 13 deletions
diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c index 042a9bb45c86..ee3a3659bd9e 100644 --- a/drivers/ata/ahci_xgene.c +++ b/drivers/ata/ahci_xgene.c | |||
| @@ -78,6 +78,7 @@ | |||
| 78 | struct xgene_ahci_context { | 78 | struct xgene_ahci_context { |
| 79 | struct ahci_host_priv *hpriv; | 79 | struct ahci_host_priv *hpriv; |
| 80 | struct device *dev; | 80 | struct device *dev; |
| 81 | u8 last_cmd[MAX_AHCI_CHN_PERCTR]; /* tracking the last command issued*/ | ||
| 81 | void __iomem *csr_core; /* Core CSR address of IP */ | 82 | void __iomem *csr_core; /* Core CSR address of IP */ |
| 82 | void __iomem *csr_diag; /* Diag CSR address of IP */ | 83 | void __iomem *csr_diag; /* Diag CSR address of IP */ |
| 83 | void __iomem *csr_axi; /* AXI CSR address of IP */ | 84 | void __iomem *csr_axi; /* AXI CSR address of IP */ |
| @@ -98,20 +99,62 @@ static int xgene_ahci_init_memram(struct xgene_ahci_context *ctx) | |||
| 98 | } | 99 | } |
| 99 | 100 | ||
| 100 | /** | 101 | /** |
| 102 | * xgene_ahci_restart_engine - Restart the dma engine. | ||
| 103 | * @ap : ATA port of interest | ||
| 104 | * | ||
| 105 | * Restarts the dma engine inside the controller. | ||
| 106 | */ | ||
| 107 | static int xgene_ahci_restart_engine(struct ata_port *ap) | ||
| 108 | { | ||
| 109 | struct ahci_host_priv *hpriv = ap->host->private_data; | ||
| 110 | |||
| 111 | ahci_stop_engine(ap); | ||
| 112 | ahci_start_fis_rx(ap); | ||
| 113 | hpriv->start_engine(ap); | ||
| 114 | |||
| 115 | return 0; | ||
| 116 | } | ||
| 117 | |||
| 118 | /** | ||
| 119 | * xgene_ahci_qc_issue - Issue commands to the device | ||
| 120 | * @qc: Command to issue | ||
| 121 | * | ||
| 122 | * Due to Hardware errata for IDENTIFY DEVICE command, the controller cannot | ||
| 123 | * clear the BSY bit after receiving the PIO setup FIS. This results in the dma | ||
| 124 | * state machine goes into the CMFatalErrorUpdate state and locks up. By | ||
| 125 | * restarting the dma engine, it removes the controller out of lock up state. | ||
| 126 | */ | ||
| 127 | static unsigned int xgene_ahci_qc_issue(struct ata_queued_cmd *qc) | ||
| 128 | { | ||
| 129 | struct ata_port *ap = qc->ap; | ||
| 130 | struct ahci_host_priv *hpriv = ap->host->private_data; | ||
| 131 | struct xgene_ahci_context *ctx = hpriv->plat_data; | ||
| 132 | int rc = 0; | ||
| 133 | |||
| 134 | if (unlikely(ctx->last_cmd[ap->port_no] == ATA_CMD_ID_ATA)) | ||
| 135 | xgene_ahci_restart_engine(ap); | ||
| 136 | |||
| 137 | rc = ahci_qc_issue(qc); | ||
| 138 | |||
| 139 | /* Save the last command issued */ | ||
| 140 | ctx->last_cmd[ap->port_no] = qc->tf.command; | ||
| 141 | |||
| 142 | return rc; | ||
| 143 | } | ||
| 144 | |||
| 145 | /** | ||
| 101 | * xgene_ahci_read_id - Read ID data from the specified device | 146 | * xgene_ahci_read_id - Read ID data from the specified device |
| 102 | * @dev: device | 147 | * @dev: device |
| 103 | * @tf: proposed taskfile | 148 | * @tf: proposed taskfile |
| 104 | * @id: data buffer | 149 | * @id: data buffer |
| 105 | * | 150 | * |
| 106 | * This custom read ID function is required due to the fact that the HW | 151 | * This custom read ID function is required due to the fact that the HW |
| 107 | * does not support DEVSLP and the controller state machine may get stuck | 152 | * does not support DEVSLP. |
| 108 | * after processing the ID query command. | ||
| 109 | */ | 153 | */ |
| 110 | static unsigned int xgene_ahci_read_id(struct ata_device *dev, | 154 | static unsigned int xgene_ahci_read_id(struct ata_device *dev, |
| 111 | struct ata_taskfile *tf, u16 *id) | 155 | struct ata_taskfile *tf, u16 *id) |
| 112 | { | 156 | { |
| 113 | u32 err_mask; | 157 | u32 err_mask; |
| 114 | void __iomem *port_mmio = ahci_port_base(dev->link->ap); | ||
| 115 | 158 | ||
| 116 | err_mask = ata_do_dev_read_id(dev, tf, id); | 159 | err_mask = ata_do_dev_read_id(dev, tf, id); |
| 117 | if (err_mask) | 160 | if (err_mask) |
| @@ -133,16 +176,6 @@ static unsigned int xgene_ahci_read_id(struct ata_device *dev, | |||
| 133 | */ | 176 | */ |
| 134 | id[ATA_ID_FEATURE_SUPP] &= ~(1 << 8); | 177 | id[ATA_ID_FEATURE_SUPP] &= ~(1 << 8); |
| 135 | 178 | ||
| 136 | /* | ||
| 137 | * Due to HW errata, restart the port if no other command active. | ||
| 138 | * Otherwise the controller may get stuck. | ||
| 139 | */ | ||
| 140 | if (!readl(port_mmio + PORT_CMD_ISSUE)) { | ||
| 141 | writel(PORT_CMD_FIS_RX, port_mmio + PORT_CMD); | ||
| 142 | readl(port_mmio + PORT_CMD); /* Force a barrier */ | ||
| 143 | writel(PORT_CMD_FIS_RX | PORT_CMD_START, port_mmio + PORT_CMD); | ||
| 144 | readl(port_mmio + PORT_CMD); /* Force a barrier */ | ||
| 145 | } | ||
| 146 | return 0; | 179 | return 0; |
| 147 | } | 180 | } |
| 148 | 181 | ||
| @@ -300,6 +333,7 @@ static struct ata_port_operations xgene_ahci_ops = { | |||
| 300 | .host_stop = xgene_ahci_host_stop, | 333 | .host_stop = xgene_ahci_host_stop, |
| 301 | .hardreset = xgene_ahci_hardreset, | 334 | .hardreset = xgene_ahci_hardreset, |
| 302 | .read_id = xgene_ahci_read_id, | 335 | .read_id = xgene_ahci_read_id, |
| 336 | .qc_issue = xgene_ahci_qc_issue, | ||
| 303 | }; | 337 | }; |
| 304 | 338 | ||
| 305 | static const struct ata_port_info xgene_ahci_port_info = { | 339 | static const struct ata_port_info xgene_ahci_port_info = { |
