diff options
Diffstat (limited to 'drivers/ata')
-rw-r--r-- | drivers/ata/ahci_xgene.c | 48 |
1 files changed, 34 insertions, 14 deletions
diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c index 37501fd0973d..f03aab187f4d 100644 --- a/drivers/ata/ahci_xgene.c +++ b/drivers/ata/ahci_xgene.c | |||
@@ -78,6 +78,9 @@ | |||
78 | #define CFG_MEM_RAM_SHUTDOWN 0x00000070 | 78 | #define CFG_MEM_RAM_SHUTDOWN 0x00000070 |
79 | #define BLOCK_MEM_RDY 0x00000074 | 79 | #define BLOCK_MEM_RDY 0x00000074 |
80 | 80 | ||
81 | /* Max retry for link down */ | ||
82 | #define MAX_LINK_DOWN_RETRY 3 | ||
83 | |||
81 | struct xgene_ahci_context { | 84 | struct xgene_ahci_context { |
82 | struct ahci_host_priv *hpriv; | 85 | struct ahci_host_priv *hpriv; |
83 | struct device *dev; | 86 | struct device *dev; |
@@ -237,8 +240,11 @@ static void xgene_ahci_set_phy_cfg(struct xgene_ahci_context *ctx, int channel) | |||
237 | * and Gen1 (1.5Gbps). Otherwise during long IO stress test, the PHY will | 240 | * and Gen1 (1.5Gbps). Otherwise during long IO stress test, the PHY will |
238 | * report disparity error and etc. In addition, during COMRESET, there can | 241 | * report disparity error and etc. In addition, during COMRESET, there can |
239 | * be error reported in the register PORT_SCR_ERR. For SERR_DISPARITY and | 242 | * be error reported in the register PORT_SCR_ERR. For SERR_DISPARITY and |
240 | * SERR_10B_8B_ERR, the PHY receiver line must be reseted. The following | 243 | * SERR_10B_8B_ERR, the PHY receiver line must be reseted. Also during long |
241 | * algorithm is followed to proper configure the hardware PHY during COMRESET: | 244 | * reboot cycle regression, sometimes the PHY reports link down even if the |
245 | * device is present because of speed negotiation failure. so need to retry | ||
246 | * the COMRESET to get the link up. The following algorithm is followed to | ||
247 | * proper configure the hardware PHY during COMRESET: | ||
242 | * | 248 | * |
243 | * Alg Part 1: | 249 | * Alg Part 1: |
244 | * 1. Start the PHY at Gen3 speed (default setting) | 250 | * 1. Start the PHY at Gen3 speed (default setting) |
@@ -254,9 +260,15 @@ static void xgene_ahci_set_phy_cfg(struct xgene_ahci_context *ctx, int channel) | |||
254 | * Alg Part 2: | 260 | * Alg Part 2: |
255 | * 1. On link up, if there are any SERR_DISPARITY and SERR_10B_8B_ERR error | 261 | * 1. On link up, if there are any SERR_DISPARITY and SERR_10B_8B_ERR error |
256 | * reported in the register PORT_SCR_ERR, then reset the PHY receiver line | 262 | * reported in the register PORT_SCR_ERR, then reset the PHY receiver line |
257 | * 2. Go to Alg Part 3 | 263 | * 2. Go to Alg Part 4 |
258 | * | 264 | * |
259 | * Alg Part 3: | 265 | * Alg Part 3: |
266 | * 1. Check the PORT_SCR_STAT to see whether device presence detected but PHY | ||
267 | * communication establishment failed and maximum link down attempts are | ||
268 | * less than Max attempts 3 then goto Alg Part 1. | ||
269 | * 2. Go to Alg Part 4. | ||
270 | * | ||
271 | * Alg Part 4: | ||
260 | * 1. Clear any pending from register PORT_SCR_ERR. | 272 | * 1. Clear any pending from register PORT_SCR_ERR. |
261 | * | 273 | * |
262 | * NOTE: For the initial version, we will NOT support Gen1/Gen2. In addition | 274 | * NOTE: For the initial version, we will NOT support Gen1/Gen2. In addition |
@@ -275,19 +287,27 @@ static int xgene_ahci_do_hardreset(struct ata_link *link, | |||
275 | u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; | 287 | u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; |
276 | void __iomem *port_mmio = ahci_port_base(ap); | 288 | void __iomem *port_mmio = ahci_port_base(ap); |
277 | struct ata_taskfile tf; | 289 | struct ata_taskfile tf; |
290 | int link_down_retry = 0; | ||
278 | int rc; | 291 | int rc; |
279 | u32 val; | 292 | u32 val, sstatus; |
280 | 293 | ||
281 | /* clear D2H reception area to properly wait for D2H FIS */ | 294 | do { |
282 | ata_tf_init(link->device, &tf); | 295 | /* clear D2H reception area to properly wait for D2H FIS */ |
283 | tf.command = ATA_BUSY; | 296 | ata_tf_init(link->device, &tf); |
284 | ata_tf_to_fis(&tf, 0, 0, d2h_fis); | 297 | tf.command = ATA_BUSY; |
285 | rc = sata_link_hardreset(link, timing, deadline, online, | 298 | ata_tf_to_fis(&tf, 0, 0, d2h_fis); |
299 | rc = sata_link_hardreset(link, timing, deadline, online, | ||
286 | ahci_check_ready); | 300 | ahci_check_ready); |
287 | 301 | if (*online) { | |
288 | val = readl(port_mmio + PORT_SCR_ERR); | 302 | val = readl(port_mmio + PORT_SCR_ERR); |
289 | if (val & (SERR_DISPARITY | SERR_10B_8B_ERR)) | 303 | if (val & (SERR_DISPARITY | SERR_10B_8B_ERR)) |
290 | dev_warn(ctx->dev, "link has error\n"); | 304 | dev_warn(ctx->dev, "link has error\n"); |
305 | break; | ||
306 | } | ||
307 | |||
308 | sata_scr_read(link, SCR_STATUS, &sstatus); | ||
309 | } while (link_down_retry++ < MAX_LINK_DOWN_RETRY && | ||
310 | (sstatus & 0xff) == 0x1); | ||
291 | 311 | ||
292 | /* clear all errors if any pending */ | 312 | /* clear all errors if any pending */ |
293 | val = readl(port_mmio + PORT_SCR_ERR); | 313 | val = readl(port_mmio + PORT_SCR_ERR); |