| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * libahci.c - Common AHCI SATA low-level routines |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 7 | 8 | * |
|---|
| 8 | 9 | * Copyright 2004-2005 Red Hat, Inc. |
|---|
| 9 | 10 | * |
|---|
| 10 | | - * |
|---|
| 11 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 12 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 13 | | - * the Free Software Foundation; either version 2, or (at your option) |
|---|
| 14 | | - * any later version. |
|---|
| 15 | | - * |
|---|
| 16 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 17 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 18 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 19 | | - * GNU General Public License for more details. |
|---|
| 20 | | - * |
|---|
| 21 | | - * You should have received a copy of the GNU General Public License |
|---|
| 22 | | - * along with this program; see the file COPYING. If not, write to |
|---|
| 23 | | - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
|---|
| 24 | | - * |
|---|
| 25 | | - * |
|---|
| 26 | 11 | * libata documentation is available via 'make {ps|pdf}docs', |
|---|
| 27 | 12 | * as Documentation/driver-api/libata.rst |
|---|
| 28 | 13 | * |
|---|
| 29 | 14 | * AHCI hardware documentation: |
|---|
| 30 | 15 | * http://www.intel.com/technology/serialata/pdf/rev1_0.pdf |
|---|
| 31 | 16 | * http://www.intel.com/technology/serialata/pdf/rev1_1.pdf |
|---|
| 32 | | - * |
|---|
| 33 | 17 | */ |
|---|
| 34 | 18 | |
|---|
| 35 | 19 | #include <linux/kernel.h> |
|---|
| .. | .. |
|---|
| 507 | 491 | if (!(cap & HOST_CAP_ALPM) && (hpriv->flags & AHCI_HFLAG_YES_ALPM)) { |
|---|
| 508 | 492 | dev_info(dev, "controller can do ALPM, turning on CAP_ALPM\n"); |
|---|
| 509 | 493 | cap |= HOST_CAP_ALPM; |
|---|
| 494 | + } |
|---|
| 495 | + |
|---|
| 496 | + if ((cap & HOST_CAP_SXS) && (hpriv->flags & AHCI_HFLAG_NO_SXS)) { |
|---|
| 497 | + dev_info(dev, "controller does not support SXS, disabling CAP_SXS\n"); |
|---|
| 498 | + cap &= ~HOST_CAP_SXS; |
|---|
| 510 | 499 | } |
|---|
| 511 | 500 | |
|---|
| 512 | 501 | if (hpriv->force_port_map && port_map != hpriv->force_port_map) { |
|---|
| .. | .. |
|---|
| 1210 | 1199 | return sprintf(buf, "%d\n", emp->blink_policy); |
|---|
| 1211 | 1200 | } |
|---|
| 1212 | 1201 | |
|---|
| 1202 | +static void ahci_port_clear_pending_irq(struct ata_port *ap) |
|---|
| 1203 | +{ |
|---|
| 1204 | + struct ahci_host_priv *hpriv = ap->host->private_data; |
|---|
| 1205 | + void __iomem *port_mmio = ahci_port_base(ap); |
|---|
| 1206 | + u32 tmp; |
|---|
| 1207 | + |
|---|
| 1208 | + /* clear SError */ |
|---|
| 1209 | + tmp = readl(port_mmio + PORT_SCR_ERR); |
|---|
| 1210 | + dev_dbg(ap->host->dev, "PORT_SCR_ERR 0x%x\n", tmp); |
|---|
| 1211 | + writel(tmp, port_mmio + PORT_SCR_ERR); |
|---|
| 1212 | + |
|---|
| 1213 | + /* clear port IRQ */ |
|---|
| 1214 | + tmp = readl(port_mmio + PORT_IRQ_STAT); |
|---|
| 1215 | + dev_dbg(ap->host->dev, "PORT_IRQ_STAT 0x%x\n", tmp); |
|---|
| 1216 | + if (tmp) |
|---|
| 1217 | + writel(tmp, port_mmio + PORT_IRQ_STAT); |
|---|
| 1218 | + |
|---|
| 1219 | + writel(1 << ap->port_no, hpriv->mmio + HOST_IRQ_STAT); |
|---|
| 1220 | +} |
|---|
| 1221 | + |
|---|
| 1213 | 1222 | static void ahci_port_init(struct device *dev, struct ata_port *ap, |
|---|
| 1214 | 1223 | int port_no, void __iomem *mmio, |
|---|
| 1215 | 1224 | void __iomem *port_mmio) |
|---|
| .. | .. |
|---|
| 1224 | 1233 | if (rc) |
|---|
| 1225 | 1234 | dev_warn(dev, "%s (%d)\n", emsg, rc); |
|---|
| 1226 | 1235 | |
|---|
| 1227 | | - /* clear SError */ |
|---|
| 1228 | | - tmp = readl(port_mmio + PORT_SCR_ERR); |
|---|
| 1229 | | - VPRINTK("PORT_SCR_ERR 0x%x\n", tmp); |
|---|
| 1230 | | - writel(tmp, port_mmio + PORT_SCR_ERR); |
|---|
| 1231 | | - |
|---|
| 1232 | | - /* clear port IRQ */ |
|---|
| 1233 | | - tmp = readl(port_mmio + PORT_IRQ_STAT); |
|---|
| 1234 | | - VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp); |
|---|
| 1235 | | - if (tmp) |
|---|
| 1236 | | - writel(tmp, port_mmio + PORT_IRQ_STAT); |
|---|
| 1237 | | - |
|---|
| 1238 | | - writel(1 << port_no, mmio + HOST_IRQ_STAT); |
|---|
| 1236 | + ahci_port_clear_pending_irq(ap); |
|---|
| 1239 | 1237 | |
|---|
| 1240 | 1238 | /* mark esata ports */ |
|---|
| 1241 | 1239 | tmp = readl(port_mmio + PORT_CMD); |
|---|
| .. | .. |
|---|
| 1262 | 1260 | } |
|---|
| 1263 | 1261 | |
|---|
| 1264 | 1262 | tmp = readl(mmio + HOST_CTL); |
|---|
| 1265 | | - VPRINTK("HOST_CTL 0x%x\n", tmp); |
|---|
| 1263 | + dev_dbg(host->dev, "HOST_CTL 0x%x\n", tmp); |
|---|
| 1266 | 1264 | writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL); |
|---|
| 1267 | 1265 | tmp = readl(mmio + HOST_CTL); |
|---|
| 1268 | | - VPRINTK("HOST_CTL 0x%x\n", tmp); |
|---|
| 1266 | + dev_dbg(host->dev, "HOST_CTL 0x%x\n", tmp); |
|---|
| 1269 | 1267 | } |
|---|
| 1270 | 1268 | EXPORT_SYMBOL_GPL(ahci_init_controller); |
|---|
| 1271 | 1269 | |
|---|
| .. | .. |
|---|
| 1465 | 1463 | *class = ahci_dev_classify(ap); |
|---|
| 1466 | 1464 | |
|---|
| 1467 | 1465 | /* re-enable FBS if disabled before */ |
|---|
| 1468 | | - if (fbs_disabled) |
|---|
| 1466 | + if (fbs_disabled || (!ata_is_host_link(link) && pp->fbs_supported)) |
|---|
| 1469 | 1467 | ahci_enable_fbs(ap); |
|---|
| 1470 | 1468 | |
|---|
| 1471 | 1469 | DPRINTK("EXIT, class=%u\n", *class); |
|---|
| .. | .. |
|---|
| 1564 | 1562 | ata_tf_init(link->device, &tf); |
|---|
| 1565 | 1563 | tf.command = ATA_BUSY; |
|---|
| 1566 | 1564 | ata_tf_to_fis(&tf, 0, 0, d2h_fis); |
|---|
| 1565 | + |
|---|
| 1566 | + ahci_port_clear_pending_irq(ap); |
|---|
| 1567 | 1567 | |
|---|
| 1568 | 1568 | rc = sata_link_hardreset(link, timing, deadline, online, |
|---|
| 1569 | 1569 | ahci_check_ready); |
|---|
| .. | .. |
|---|
| 1916 | 1916 | void __iomem *port_mmio = ahci_port_base(ap); |
|---|
| 1917 | 1917 | u32 status; |
|---|
| 1918 | 1918 | |
|---|
| 1919 | | - VPRINTK("ENTER\n"); |
|---|
| 1920 | | - |
|---|
| 1921 | 1919 | status = readl(port_mmio + PORT_IRQ_STAT); |
|---|
| 1922 | 1920 | writel(status, port_mmio + PORT_IRQ_STAT); |
|---|
| 1923 | 1921 | |
|---|
| 1924 | 1922 | spin_lock(ap->lock); |
|---|
| 1925 | 1923 | ahci_handle_port_interrupt(ap, port_mmio, status); |
|---|
| 1926 | 1924 | spin_unlock(ap->lock); |
|---|
| 1927 | | - |
|---|
| 1928 | | - VPRINTK("EXIT\n"); |
|---|
| 1929 | 1925 | |
|---|
| 1930 | 1926 | return IRQ_HANDLED; |
|---|
| 1931 | 1927 | } |
|---|
| .. | .. |
|---|
| 1943 | 1939 | ap = host->ports[i]; |
|---|
| 1944 | 1940 | if (ap) { |
|---|
| 1945 | 1941 | ahci_port_intr(ap); |
|---|
| 1946 | | - VPRINTK("port %u\n", i); |
|---|
| 1947 | 1942 | } else { |
|---|
| 1948 | | - VPRINTK("port %u (no irq)\n", i); |
|---|
| 1949 | 1943 | if (ata_ratelimit()) |
|---|
| 1950 | 1944 | dev_warn(host->dev, |
|---|
| 1951 | 1945 | "interrupt on disabled port %u\n", i); |
|---|
| .. | .. |
|---|
| 1965 | 1959 | unsigned int rc = 0; |
|---|
| 1966 | 1960 | void __iomem *mmio; |
|---|
| 1967 | 1961 | u32 irq_stat, irq_masked; |
|---|
| 1968 | | - |
|---|
| 1969 | | - VPRINTK("ENTER\n"); |
|---|
| 1970 | 1962 | |
|---|
| 1971 | 1963 | hpriv = host->private_data; |
|---|
| 1972 | 1964 | mmio = hpriv->mmio; |
|---|
| .. | .. |
|---|
| 1994 | 1986 | writel(irq_stat, mmio + HOST_IRQ_STAT); |
|---|
| 1995 | 1987 | |
|---|
| 1996 | 1988 | spin_unlock(&host->lock); |
|---|
| 1997 | | - |
|---|
| 1998 | | - VPRINTK("EXIT\n"); |
|---|
| 1999 | 1989 | |
|---|
| 2000 | 1990 | return IRQ_RETVAL(rc); |
|---|
| 2001 | 1991 | } |
|---|
| .. | .. |
|---|
| 2382 | 2372 | mem = dmam_alloc_coherent(dev, dma_sz, &mem_dma, GFP_KERNEL); |
|---|
| 2383 | 2373 | if (!mem) |
|---|
| 2384 | 2374 | return -ENOMEM; |
|---|
| 2385 | | - memset(mem, 0, dma_sz); |
|---|
| 2386 | 2375 | |
|---|
| 2387 | 2376 | /* |
|---|
| 2388 | 2377 | * First item in chunk of DMA memory: 32-slot command table, |
|---|
| .. | .. |
|---|
| 2600 | 2589 | int rc; |
|---|
| 2601 | 2590 | |
|---|
| 2602 | 2591 | if (hpriv->flags & AHCI_HFLAG_MULTI_MSI) { |
|---|
| 2603 | | - if (hpriv->irq_handler) |
|---|
| 2592 | + if (hpriv->irq_handler && |
|---|
| 2593 | + hpriv->irq_handler != ahci_single_level_irq_intr) |
|---|
| 2604 | 2594 | dev_warn(host->dev, |
|---|
| 2605 | 2595 | "both AHCI_HFLAG_MULTI_MSI flag set and custom irq handler implemented\n"); |
|---|
| 2606 | 2596 | if (!hpriv->get_irq_vector) { |
|---|