diff options
author | Shane Huang <shane.huang@amd.com> | 2009-12-09 04:23:04 -0500 |
---|---|---|
committer | Jeff Garzik <jgarzik@redhat.com> | 2010-03-01 14:58:43 -0500 |
commit | d6ef31539d715db7a0eb2d67a1a008c9d8ccf059 (patch) | |
tree | a2516cbb7e156a400dfa97e35b5aae1cc8560052 /drivers/ata | |
parent | d817898c2fc73e6ea33b58498c87a43d7e9fcd7a (diff) |
ahci: Implement SATA AHCI FIS-based switching support
Tested on AMD internal reference board.
Signed-off-by: Shane Huang <shane.huang@amd.com>
Acked-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/ata')
-rw-r--r-- | drivers/ata/ahci.c | 221 |
1 files changed, 203 insertions, 18 deletions
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index a6a736a7dbf2..705bd8b1ea67 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c | |||
@@ -93,6 +93,9 @@ enum { | |||
93 | AHCI_CMD_TBL_AR_SZ = AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS, | 93 | AHCI_CMD_TBL_AR_SZ = AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS, |
94 | AHCI_PORT_PRIV_DMA_SZ = AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ + | 94 | AHCI_PORT_PRIV_DMA_SZ = AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ + |
95 | AHCI_RX_FIS_SZ, | 95 | AHCI_RX_FIS_SZ, |
96 | AHCI_PORT_PRIV_FBS_DMA_SZ = AHCI_CMD_SLOT_SZ + | ||
97 | AHCI_CMD_TBL_AR_SZ + | ||
98 | (AHCI_RX_FIS_SZ * 16), | ||
96 | AHCI_IRQ_ON_SG = (1 << 31), | 99 | AHCI_IRQ_ON_SG = (1 << 31), |
97 | AHCI_CMD_ATAPI = (1 << 5), | 100 | AHCI_CMD_ATAPI = (1 << 5), |
98 | AHCI_CMD_WRITE = (1 << 6), | 101 | AHCI_CMD_WRITE = (1 << 6), |
@@ -170,6 +173,7 @@ enum { | |||
170 | PORT_SCR_ERR = 0x30, /* SATA phy register: SError */ | 173 | PORT_SCR_ERR = 0x30, /* SATA phy register: SError */ |
171 | PORT_SCR_ACT = 0x34, /* SATA phy register: SActive */ | 174 | PORT_SCR_ACT = 0x34, /* SATA phy register: SActive */ |
172 | PORT_SCR_NTF = 0x3c, /* SATA phy register: SNotification */ | 175 | PORT_SCR_NTF = 0x3c, /* SATA phy register: SNotification */ |
176 | PORT_FBS = 0x40, /* FIS-based Switching */ | ||
173 | 177 | ||
174 | /* PORT_IRQ_{STAT,MASK} bits */ | 178 | /* PORT_IRQ_{STAT,MASK} bits */ |
175 | PORT_IRQ_COLD_PRES = (1 << 31), /* cold presence detect */ | 179 | PORT_IRQ_COLD_PRES = (1 << 31), /* cold presence detect */ |
@@ -208,6 +212,7 @@ enum { | |||
208 | PORT_CMD_ASP = (1 << 27), /* Aggressive Slumber/Partial */ | 212 | PORT_CMD_ASP = (1 << 27), /* Aggressive Slumber/Partial */ |
209 | PORT_CMD_ALPE = (1 << 26), /* Aggressive Link PM enable */ | 213 | PORT_CMD_ALPE = (1 << 26), /* Aggressive Link PM enable */ |
210 | PORT_CMD_ATAPI = (1 << 24), /* Device is ATAPI */ | 214 | PORT_CMD_ATAPI = (1 << 24), /* Device is ATAPI */ |
215 | PORT_CMD_FBSCP = (1 << 22), /* FBS Capable Port */ | ||
211 | PORT_CMD_PMP = (1 << 17), /* PMP attached */ | 216 | PORT_CMD_PMP = (1 << 17), /* PMP attached */ |
212 | PORT_CMD_LIST_ON = (1 << 15), /* cmd list DMA engine running */ | 217 | PORT_CMD_LIST_ON = (1 << 15), /* cmd list DMA engine running */ |
213 | PORT_CMD_FIS_ON = (1 << 14), /* FIS DMA engine running */ | 218 | PORT_CMD_FIS_ON = (1 << 14), /* FIS DMA engine running */ |
@@ -222,6 +227,14 @@ enum { | |||
222 | PORT_CMD_ICC_PARTIAL = (0x2 << 28), /* Put i/f in partial state */ | 227 | PORT_CMD_ICC_PARTIAL = (0x2 << 28), /* Put i/f in partial state */ |
223 | PORT_CMD_ICC_SLUMBER = (0x6 << 28), /* Put i/f in slumber state */ | 228 | PORT_CMD_ICC_SLUMBER = (0x6 << 28), /* Put i/f in slumber state */ |
224 | 229 | ||
230 | PORT_FBS_DWE_OFFSET = 16, /* FBS device with error offset */ | ||
231 | PORT_FBS_ADO_OFFSET = 12, /* FBS active dev optimization offset */ | ||
232 | PORT_FBS_DEV_OFFSET = 8, /* FBS device to issue offset */ | ||
233 | PORT_FBS_DEV_MASK = (0xf << PORT_FBS_DEV_OFFSET), /* FBS.DEV */ | ||
234 | PORT_FBS_SDE = (1 << 2), /* FBS single device error */ | ||
235 | PORT_FBS_DEC = (1 << 1), /* FBS device error clear */ | ||
236 | PORT_FBS_EN = (1 << 0), /* Enable FBS */ | ||
237 | |||
225 | /* hpriv->flags bits */ | 238 | /* hpriv->flags bits */ |
226 | AHCI_HFLAG_NO_NCQ = (1 << 0), | 239 | AHCI_HFLAG_NO_NCQ = (1 << 0), |
227 | AHCI_HFLAG_IGN_IRQ_IF_ERR = (1 << 1), /* ignore IRQ_IF_ERR */ | 240 | AHCI_HFLAG_IGN_IRQ_IF_ERR = (1 << 1), /* ignore IRQ_IF_ERR */ |
@@ -304,6 +317,9 @@ struct ahci_port_priv { | |||
304 | unsigned int ncq_saw_dmas:1; | 317 | unsigned int ncq_saw_dmas:1; |
305 | unsigned int ncq_saw_sdb:1; | 318 | unsigned int ncq_saw_sdb:1; |
306 | u32 intr_mask; /* interrupts to enable */ | 319 | u32 intr_mask; /* interrupts to enable */ |
320 | bool fbs_supported; /* set iff FBS is supported */ | ||
321 | bool fbs_enabled; /* set iff FBS is enabled */ | ||
322 | int fbs_last_dev; /* save FBS.DEV of last FIS */ | ||
307 | /* enclosure management info per PM slot */ | 323 | /* enclosure management info per PM slot */ |
308 | struct ahci_em_priv em_priv[EM_MAX_SLOTS]; | 324 | struct ahci_em_priv em_priv[EM_MAX_SLOTS]; |
309 | }; | 325 | }; |
@@ -315,9 +331,12 @@ static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc); | |||
315 | static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc); | 331 | static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc); |
316 | static int ahci_port_start(struct ata_port *ap); | 332 | static int ahci_port_start(struct ata_port *ap); |
317 | static void ahci_port_stop(struct ata_port *ap); | 333 | static void ahci_port_stop(struct ata_port *ap); |
334 | static int ahci_pmp_qc_defer(struct ata_queued_cmd *qc); | ||
318 | static void ahci_qc_prep(struct ata_queued_cmd *qc); | 335 | static void ahci_qc_prep(struct ata_queued_cmd *qc); |
319 | static void ahci_freeze(struct ata_port *ap); | 336 | static void ahci_freeze(struct ata_port *ap); |
320 | static void ahci_thaw(struct ata_port *ap); | 337 | static void ahci_thaw(struct ata_port *ap); |
338 | static void ahci_enable_fbs(struct ata_port *ap); | ||
339 | static void ahci_disable_fbs(struct ata_port *ap); | ||
321 | static void ahci_pmp_attach(struct ata_port *ap); | 340 | static void ahci_pmp_attach(struct ata_port *ap); |
322 | static void ahci_pmp_detach(struct ata_port *ap); | 341 | static void ahci_pmp_detach(struct ata_port *ap); |
323 | static int ahci_softreset(struct ata_link *link, unsigned int *class, | 342 | static int ahci_softreset(struct ata_link *link, unsigned int *class, |
@@ -390,7 +409,7 @@ static struct scsi_host_template ahci_sht = { | |||
390 | static struct ata_port_operations ahci_ops = { | 409 | static struct ata_port_operations ahci_ops = { |
391 | .inherits = &sata_pmp_port_ops, | 410 | .inherits = &sata_pmp_port_ops, |
392 | 411 | ||
393 | .qc_defer = sata_pmp_qc_defer_cmd_switch, | 412 | .qc_defer = ahci_pmp_qc_defer, |
394 | .qc_prep = ahci_qc_prep, | 413 | .qc_prep = ahci_qc_prep, |
395 | .qc_issue = ahci_qc_issue, | 414 | .qc_issue = ahci_qc_issue, |
396 | .qc_fill_rtf = ahci_qc_fill_rtf, | 415 | .qc_fill_rtf = ahci_qc_fill_rtf, |
@@ -2045,6 +2064,17 @@ static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl) | |||
2045 | return si; | 2064 | return si; |
2046 | } | 2065 | } |
2047 | 2066 | ||
2067 | static int ahci_pmp_qc_defer(struct ata_queued_cmd *qc) | ||
2068 | { | ||
2069 | struct ata_port *ap = qc->ap; | ||
2070 | struct ahci_port_priv *pp = ap->private_data; | ||
2071 | |||
2072 | if (!sata_pmp_attached(ap) || pp->fbs_enabled) | ||
2073 | return ata_std_qc_defer(qc); | ||
2074 | else | ||
2075 | return sata_pmp_qc_defer_cmd_switch(qc); | ||
2076 | } | ||
2077 | |||
2048 | static void ahci_qc_prep(struct ata_queued_cmd *qc) | 2078 | static void ahci_qc_prep(struct ata_queued_cmd *qc) |
2049 | { | 2079 | { |
2050 | struct ata_port *ap = qc->ap; | 2080 | struct ata_port *ap = qc->ap; |
@@ -2083,6 +2113,31 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc) | |||
2083 | ahci_fill_cmd_slot(pp, qc->tag, opts); | 2113 | ahci_fill_cmd_slot(pp, qc->tag, opts); |
2084 | } | 2114 | } |
2085 | 2115 | ||
2116 | static void ahci_fbs_dec_intr(struct ata_port *ap) | ||
2117 | { | ||
2118 | struct ahci_port_priv *pp = ap->private_data; | ||
2119 | void __iomem *port_mmio = ahci_port_base(ap); | ||
2120 | u32 fbs = readl(port_mmio + PORT_FBS); | ||
2121 | int retries = 3; | ||
2122 | |||
2123 | DPRINTK("ENTER\n"); | ||
2124 | BUG_ON(!pp->fbs_enabled); | ||
2125 | |||
2126 | /* time to wait for DEC is not specified by AHCI spec, | ||
2127 | * add a retry loop for safety. | ||
2128 | */ | ||
2129 | writel(fbs | PORT_FBS_DEC, port_mmio + PORT_FBS); | ||
2130 | fbs = readl(port_mmio + PORT_FBS); | ||
2131 | while ((fbs & PORT_FBS_DEC) && retries--) { | ||
2132 | udelay(1); | ||
2133 | fbs = readl(port_mmio + PORT_FBS); | ||
2134 | } | ||
2135 | |||
2136 | if (fbs & PORT_FBS_DEC) | ||
2137 | dev_printk(KERN_ERR, ap->host->dev, | ||
2138 | "failed to clear device error\n"); | ||
2139 | } | ||
2140 | |||
2086 | static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) | 2141 | static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) |
2087 | { | 2142 | { |
2088 | struct ahci_host_priv *hpriv = ap->host->private_data; | 2143 | struct ahci_host_priv *hpriv = ap->host->private_data; |
@@ -2091,12 +2146,26 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) | |||
2091 | struct ata_link *link = NULL; | 2146 | struct ata_link *link = NULL; |
2092 | struct ata_queued_cmd *active_qc; | 2147 | struct ata_queued_cmd *active_qc; |
2093 | struct ata_eh_info *active_ehi; | 2148 | struct ata_eh_info *active_ehi; |
2149 | bool fbs_need_dec = false; | ||
2094 | u32 serror; | 2150 | u32 serror; |
2095 | 2151 | ||
2096 | /* determine active link */ | 2152 | /* determine active link with error */ |
2097 | ata_for_each_link(link, ap, EDGE) | 2153 | if (pp->fbs_enabled) { |
2098 | if (ata_link_active(link)) | 2154 | void __iomem *port_mmio = ahci_port_base(ap); |
2099 | break; | 2155 | u32 fbs = readl(port_mmio + PORT_FBS); |
2156 | int pmp = fbs >> PORT_FBS_DWE_OFFSET; | ||
2157 | |||
2158 | if ((fbs & PORT_FBS_SDE) && (pmp < ap->nr_pmp_links) && | ||
2159 | ata_link_online(&ap->pmp_link[pmp])) { | ||
2160 | link = &ap->pmp_link[pmp]; | ||
2161 | fbs_need_dec = true; | ||
2162 | } | ||
2163 | |||
2164 | } else | ||
2165 | ata_for_each_link(link, ap, EDGE) | ||
2166 | if (ata_link_active(link)) | ||
2167 | break; | ||
2168 | |||
2100 | if (!link) | 2169 | if (!link) |
2101 | link = &ap->link; | 2170 | link = &ap->link; |
2102 | 2171 | ||
@@ -2153,8 +2222,13 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) | |||
2153 | } | 2222 | } |
2154 | 2223 | ||
2155 | if (irq_stat & PORT_IRQ_IF_ERR) { | 2224 | if (irq_stat & PORT_IRQ_IF_ERR) { |
2156 | host_ehi->err_mask |= AC_ERR_ATA_BUS; | 2225 | if (fbs_need_dec) |
2157 | host_ehi->action |= ATA_EH_RESET; | 2226 | active_ehi->err_mask |= AC_ERR_DEV; |
2227 | else { | ||
2228 | host_ehi->err_mask |= AC_ERR_ATA_BUS; | ||
2229 | host_ehi->action |= ATA_EH_RESET; | ||
2230 | } | ||
2231 | |||
2158 | ata_ehi_push_desc(host_ehi, "interface fatal error"); | 2232 | ata_ehi_push_desc(host_ehi, "interface fatal error"); |
2159 | } | 2233 | } |
2160 | 2234 | ||
@@ -2169,7 +2243,10 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) | |||
2169 | 2243 | ||
2170 | if (irq_stat & PORT_IRQ_FREEZE) | 2244 | if (irq_stat & PORT_IRQ_FREEZE) |
2171 | ata_port_freeze(ap); | 2245 | ata_port_freeze(ap); |
2172 | else | 2246 | else if (fbs_need_dec) { |
2247 | ata_link_abort(link); | ||
2248 | ahci_fbs_dec_intr(ap); | ||
2249 | } else | ||
2173 | ata_port_abort(ap); | 2250 | ata_port_abort(ap); |
2174 | } | 2251 | } |
2175 | 2252 | ||
@@ -2222,12 +2299,19 @@ static void ahci_port_intr(struct ata_port *ap) | |||
2222 | /* If the 'N' bit in word 0 of the FIS is set, | 2299 | /* If the 'N' bit in word 0 of the FIS is set, |
2223 | * we just received asynchronous notification. | 2300 | * we just received asynchronous notification. |
2224 | * Tell libata about it. | 2301 | * Tell libata about it. |
2302 | * | ||
2303 | * Lack of SNotification should not appear in | ||
2304 | * ahci 1.2, so the workaround is unnecessary | ||
2305 | * when FBS is enabled. | ||
2225 | */ | 2306 | */ |
2226 | const __le32 *f = pp->rx_fis + RX_FIS_SDB; | 2307 | if (pp->fbs_enabled) |
2227 | u32 f0 = le32_to_cpu(f[0]); | 2308 | WARN_ON_ONCE(1); |
2228 | 2309 | else { | |
2229 | if (f0 & (1 << 15)) | 2310 | const __le32 *f = pp->rx_fis + RX_FIS_SDB; |
2230 | sata_async_notification(ap); | 2311 | u32 f0 = le32_to_cpu(f[0]); |
2312 | if (f0 & (1 << 15)) | ||
2313 | sata_async_notification(ap); | ||
2314 | } | ||
2231 | } | 2315 | } |
2232 | } | 2316 | } |
2233 | 2317 | ||
@@ -2321,6 +2405,15 @@ static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc) | |||
2321 | 2405 | ||
2322 | if (qc->tf.protocol == ATA_PROT_NCQ) | 2406 | if (qc->tf.protocol == ATA_PROT_NCQ) |
2323 | writel(1 << qc->tag, port_mmio + PORT_SCR_ACT); | 2407 | writel(1 << qc->tag, port_mmio + PORT_SCR_ACT); |
2408 | |||
2409 | if (pp->fbs_enabled && pp->fbs_last_dev != qc->dev->link->pmp) { | ||
2410 | u32 fbs = readl(port_mmio + PORT_FBS); | ||
2411 | fbs &= ~(PORT_FBS_DEV_MASK | PORT_FBS_DEC); | ||
2412 | fbs |= qc->dev->link->pmp << PORT_FBS_DEV_OFFSET; | ||
2413 | writel(fbs, port_mmio + PORT_FBS); | ||
2414 | pp->fbs_last_dev = qc->dev->link->pmp; | ||
2415 | } | ||
2416 | |||
2324 | writel(1 << qc->tag, port_mmio + PORT_CMD_ISSUE); | 2417 | writel(1 << qc->tag, port_mmio + PORT_CMD_ISSUE); |
2325 | 2418 | ||
2326 | ahci_sw_activity(qc->dev->link); | 2419 | ahci_sw_activity(qc->dev->link); |
@@ -2333,6 +2426,9 @@ static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc) | |||
2333 | struct ahci_port_priv *pp = qc->ap->private_data; | 2426 | struct ahci_port_priv *pp = qc->ap->private_data; |
2334 | u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; | 2427 | u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; |
2335 | 2428 | ||
2429 | if (pp->fbs_enabled) | ||
2430 | d2h_fis += qc->dev->link->pmp * AHCI_RX_FIS_SZ; | ||
2431 | |||
2336 | ata_tf_from_fis(d2h_fis, &qc->result_tf); | 2432 | ata_tf_from_fis(d2h_fis, &qc->result_tf); |
2337 | return true; | 2433 | return true; |
2338 | } | 2434 | } |
@@ -2381,6 +2477,71 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) | |||
2381 | ahci_kick_engine(ap); | 2477 | ahci_kick_engine(ap); |
2382 | } | 2478 | } |
2383 | 2479 | ||
2480 | static void ahci_enable_fbs(struct ata_port *ap) | ||
2481 | { | ||
2482 | struct ahci_port_priv *pp = ap->private_data; | ||
2483 | void __iomem *port_mmio = ahci_port_base(ap); | ||
2484 | u32 fbs; | ||
2485 | int rc; | ||
2486 | |||
2487 | if (!pp->fbs_supported) | ||
2488 | return; | ||
2489 | |||
2490 | fbs = readl(port_mmio + PORT_FBS); | ||
2491 | if (fbs & PORT_FBS_EN) { | ||
2492 | pp->fbs_enabled = true; | ||
2493 | pp->fbs_last_dev = -1; /* initialization */ | ||
2494 | return; | ||
2495 | } | ||
2496 | |||
2497 | rc = ahci_stop_engine(ap); | ||
2498 | if (rc) | ||
2499 | return; | ||
2500 | |||
2501 | writel(fbs | PORT_FBS_EN, port_mmio + PORT_FBS); | ||
2502 | fbs = readl(port_mmio + PORT_FBS); | ||
2503 | if (fbs & PORT_FBS_EN) { | ||
2504 | dev_printk(KERN_INFO, ap->host->dev, "FBS is enabled.\n"); | ||
2505 | pp->fbs_enabled = true; | ||
2506 | pp->fbs_last_dev = -1; /* initialization */ | ||
2507 | } else | ||
2508 | dev_printk(KERN_ERR, ap->host->dev, "Failed to enable FBS\n"); | ||
2509 | |||
2510 | ahci_start_engine(ap); | ||
2511 | } | ||
2512 | |||
2513 | static void ahci_disable_fbs(struct ata_port *ap) | ||
2514 | { | ||
2515 | struct ahci_port_priv *pp = ap->private_data; | ||
2516 | void __iomem *port_mmio = ahci_port_base(ap); | ||
2517 | u32 fbs; | ||
2518 | int rc; | ||
2519 | |||
2520 | if (!pp->fbs_supported) | ||
2521 | return; | ||
2522 | |||
2523 | fbs = readl(port_mmio + PORT_FBS); | ||
2524 | if ((fbs & PORT_FBS_EN) == 0) { | ||
2525 | pp->fbs_enabled = false; | ||
2526 | return; | ||
2527 | } | ||
2528 | |||
2529 | rc = ahci_stop_engine(ap); | ||
2530 | if (rc) | ||
2531 | return; | ||
2532 | |||
2533 | writel(fbs & ~PORT_FBS_EN, port_mmio + PORT_FBS); | ||
2534 | fbs = readl(port_mmio + PORT_FBS); | ||
2535 | if (fbs & PORT_FBS_EN) | ||
2536 | dev_printk(KERN_ERR, ap->host->dev, "Failed to disable FBS\n"); | ||
2537 | else { | ||
2538 | dev_printk(KERN_INFO, ap->host->dev, "FBS is disabled.\n"); | ||
2539 | pp->fbs_enabled = false; | ||
2540 | } | ||
2541 | |||
2542 | ahci_start_engine(ap); | ||
2543 | } | ||
2544 | |||
2384 | static void ahci_pmp_attach(struct ata_port *ap) | 2545 | static void ahci_pmp_attach(struct ata_port *ap) |
2385 | { | 2546 | { |
2386 | void __iomem *port_mmio = ahci_port_base(ap); | 2547 | void __iomem *port_mmio = ahci_port_base(ap); |
@@ -2391,6 +2552,8 @@ static void ahci_pmp_attach(struct ata_port *ap) | |||
2391 | cmd |= PORT_CMD_PMP; | 2552 | cmd |= PORT_CMD_PMP; |
2392 | writel(cmd, port_mmio + PORT_CMD); | 2553 | writel(cmd, port_mmio + PORT_CMD); |
2393 | 2554 | ||
2555 | ahci_enable_fbs(ap); | ||
2556 | |||
2394 | pp->intr_mask |= PORT_IRQ_BAD_PMP; | 2557 | pp->intr_mask |= PORT_IRQ_BAD_PMP; |
2395 | writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); | 2558 | writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); |
2396 | } | 2559 | } |
@@ -2401,6 +2564,8 @@ static void ahci_pmp_detach(struct ata_port *ap) | |||
2401 | struct ahci_port_priv *pp = ap->private_data; | 2564 | struct ahci_port_priv *pp = ap->private_data; |
2402 | u32 cmd; | 2565 | u32 cmd; |
2403 | 2566 | ||
2567 | ahci_disable_fbs(ap); | ||
2568 | |||
2404 | cmd = readl(port_mmio + PORT_CMD); | 2569 | cmd = readl(port_mmio + PORT_CMD); |
2405 | cmd &= ~PORT_CMD_PMP; | 2570 | cmd &= ~PORT_CMD_PMP; |
2406 | writel(cmd, port_mmio + PORT_CMD); | 2571 | writel(cmd, port_mmio + PORT_CMD); |
@@ -2492,20 +2657,40 @@ static int ahci_pci_device_resume(struct pci_dev *pdev) | |||
2492 | 2657 | ||
2493 | static int ahci_port_start(struct ata_port *ap) | 2658 | static int ahci_port_start(struct ata_port *ap) |
2494 | { | 2659 | { |
2660 | struct ahci_host_priv *hpriv = ap->host->private_data; | ||
2495 | struct device *dev = ap->host->dev; | 2661 | struct device *dev = ap->host->dev; |
2496 | struct ahci_port_priv *pp; | 2662 | struct ahci_port_priv *pp; |
2497 | void *mem; | 2663 | void *mem; |
2498 | dma_addr_t mem_dma; | 2664 | dma_addr_t mem_dma; |
2665 | size_t dma_sz, rx_fis_sz; | ||
2499 | 2666 | ||
2500 | pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL); | 2667 | pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL); |
2501 | if (!pp) | 2668 | if (!pp) |
2502 | return -ENOMEM; | 2669 | return -ENOMEM; |
2503 | 2670 | ||
2504 | mem = dmam_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma, | 2671 | /* check FBS capability */ |
2505 | GFP_KERNEL); | 2672 | if ((hpriv->cap & HOST_CAP_FBS) && sata_pmp_supported(ap)) { |
2673 | void __iomem *port_mmio = ahci_port_base(ap); | ||
2674 | u32 cmd = readl(port_mmio + PORT_CMD); | ||
2675 | if (cmd & PORT_CMD_FBSCP) | ||
2676 | pp->fbs_supported = true; | ||
2677 | else | ||
2678 | dev_printk(KERN_WARNING, dev, | ||
2679 | "The port is not capable of FBS\n"); | ||
2680 | } | ||
2681 | |||
2682 | if (pp->fbs_supported) { | ||
2683 | dma_sz = AHCI_PORT_PRIV_FBS_DMA_SZ; | ||
2684 | rx_fis_sz = AHCI_RX_FIS_SZ * 16; | ||
2685 | } else { | ||
2686 | dma_sz = AHCI_PORT_PRIV_DMA_SZ; | ||
2687 | rx_fis_sz = AHCI_RX_FIS_SZ; | ||
2688 | } | ||
2689 | |||
2690 | mem = dmam_alloc_coherent(dev, dma_sz, &mem_dma, GFP_KERNEL); | ||
2506 | if (!mem) | 2691 | if (!mem) |
2507 | return -ENOMEM; | 2692 | return -ENOMEM; |
2508 | memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ); | 2693 | memset(mem, 0, dma_sz); |
2509 | 2694 | ||
2510 | /* | 2695 | /* |
2511 | * First item in chunk of DMA memory: 32-slot command table, | 2696 | * First item in chunk of DMA memory: 32-slot command table, |
@@ -2523,8 +2708,8 @@ static int ahci_port_start(struct ata_port *ap) | |||
2523 | pp->rx_fis = mem; | 2708 | pp->rx_fis = mem; |
2524 | pp->rx_fis_dma = mem_dma; | 2709 | pp->rx_fis_dma = mem_dma; |
2525 | 2710 | ||
2526 | mem += AHCI_RX_FIS_SZ; | 2711 | mem += rx_fis_sz; |
2527 | mem_dma += AHCI_RX_FIS_SZ; | 2712 | mem_dma += rx_fis_sz; |
2528 | 2713 | ||
2529 | /* | 2714 | /* |
2530 | * Third item: data area for storing a single command | 2715 | * Third item: data area for storing a single command |