From deca423213cb33feda15e261e7b5b992077a6a08 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Thu, 30 Jan 2025 14:35:46 +0100 Subject: [PATCH 1/9] ata: libata-core: Add 'external' to the libata.force kernel parameter Commit ae1f3db006b7 ("ata: ahci: do not enable LPM on external ports") changed so that LPM is not enabled on external ports (hotplug-capable or eSATA ports). This is because hotplug and LPM are mutually exclusive, see 7.3.1 Hot Plug Removal Detection and Power Management Interaction in AHCI 1.3.1. This does require that firmware has set the appropate bits (HPCP or ESP) in PxCMD (which is a per port register in the AHCI controller). If the firmware has failed to mark a port as hotplug-capable or eSATA in PxCMD, then there is currently not much a user can do. If LPM is enabled on the port, hotplug insertions and removals will not be detected on that port. In order to allow a user to fix up broken firmware, add 'external' to the libata.force kernel parameter. libata.force can be specified either on the kernel command line, or as a kernel module parameter. For more information, see Documentation/admin-guide/kernel-parameters.txt. Reviewed-by: Damien Le Moal Link: https://lore.kernel.org/r/20250130133544.219297-4-cassel@kernel.org Signed-off-by: Niklas Cassel --- .../admin-guide/kernel-parameters.txt | 2 + drivers/ata/libata-core.c | 38 +++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index fb8752b42ec8..aa7447f8837c 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -3116,6 +3116,8 @@ * max_sec_lba48: Set or clear transfer size limit to 65535 sectors. + * external: Mark port as external (hotplug-capable). + * [no]lpm: Enable or disable link power management. * [no]setxfer: Indicate if transfer speed mode setting diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 63ec2f218431..9c4a21e5a8bb 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -88,6 +88,7 @@ struct ata_force_param { unsigned int xfer_mask; unsigned int quirk_on; unsigned int quirk_off; + unsigned int pflags_on; u16 lflags_on; u16 lflags_off; }; @@ -331,6 +332,35 @@ void ata_force_cbl(struct ata_port *ap) } } +/** + * ata_force_pflags - force port flags according to libata.force + * @ap: ATA port of interest + * + * Force port flags according to libata.force and whine about it. + * + * LOCKING: + * EH context. + */ +static void ata_force_pflags(struct ata_port *ap) +{ + int i; + + for (i = ata_force_tbl_size - 1; i >= 0; i--) { + const struct ata_force_ent *fe = &ata_force_tbl[i]; + + if (fe->port != -1 && fe->port != ap->print_id) + continue; + + /* let pflags stack */ + if (fe->param.pflags_on) { + ap->pflags |= fe->param.pflags_on; + ata_port_notice(ap, + "FORCE: port flag 0x%x forced -> 0x%x\n", + fe->param.pflags_on, ap->pflags); + } + } +} + /** * ata_force_link_limits - force link limits according to libata.force * @link: ATA link of interest @@ -486,6 +516,7 @@ static void ata_force_quirks(struct ata_device *dev) } } #else +static inline void ata_force_pflags(struct ata_port *ap) { } static inline void ata_force_link_limits(struct ata_link *link) { } static inline void ata_force_xfermask(struct ata_device *dev) { } static inline void ata_force_quirks(struct ata_device *dev) { } @@ -5456,6 +5487,8 @@ struct ata_port *ata_port_alloc(struct ata_host *host) #endif ata_sff_port_init(ap); + ata_force_pflags(ap); + return ap; } EXPORT_SYMBOL_GPL(ata_port_alloc); @@ -6268,6 +6301,9 @@ EXPORT_SYMBOL_GPL(ata_platform_remove_one); { "no" #name, .lflags_on = (flags) }, \ { #name, .lflags_off = (flags) } +#define force_pflag_on(name, flags) \ + { #name, .pflags_on = (flags) } + #define force_quirk_on(name, flag) \ { #name, .quirk_on = (flag) } @@ -6327,6 +6363,8 @@ static const struct ata_force_param force_tbl[] __initconst = { force_lflag_on(rstonce, ATA_LFLAG_RST_ONCE), force_lflag_onoff(dbdelay, ATA_LFLAG_NO_DEBOUNCE_DELAY), + force_pflag_on(external, ATA_PFLAG_EXTERNAL), + force_quirk_onoff(ncq, ATA_QUIRK_NONCQ), force_quirk_onoff(ncqtrim, ATA_QUIRK_NO_NCQ_TRIM), force_quirk_onoff(ncqati, ATA_QUIRK_NO_NCQ_ON_ATI), From 0ce4a0d1551f1b0ece4910d4699a08506fc6ddb7 Mon Sep 17 00:00:00 2001 From: Salah Triki Date: Thu, 20 Feb 2025 09:07:57 +0100 Subject: [PATCH 2/9] ata: sata_via: Use str_up_down() helper in vt6420_prereset() Remove hard-coded strings by using the str_up_down() helper function. Signed-off-by: Salah Triki Reviewed-by: Damien Le Moal Link: https://lore.kernel.org/r/20250220080757.87278-1-salah.triki@gmail.com Signed-off-by: Niklas Cassel --- drivers/ata/sata_via.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index 57cbf2cef618..4ecd8f33b082 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -25,6 +25,7 @@ #include #include #include +#include #define DRV_NAME "sata_via" #define DRV_VERSION "2.6" @@ -359,7 +360,7 @@ static int vt6420_prereset(struct ata_link *link, unsigned long deadline) ata_port_info(ap, "SATA link %s 1.5 Gbps (SStatus %X SControl %X)\n", - online ? "up" : "down", sstatus, scontrol); + str_up_down(online), sstatus, scontrol); /* SStatus is read one more time */ svia_scr_read(link, SCR_STATUS, &sstatus); From 08a04e20593b8efbc6dae99be6e965104826bfe1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=2E=20Neusch=C3=A4fer?= Date: Thu, 20 Feb 2025 12:49:53 +0100 Subject: [PATCH 3/9] dt-bindings: ata: Convert fsl,pq-sata to YAML MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert the Freescale PowerQUICC SATA controller binding from text form to YAML. The list of compatible strings reflects current usage. To clarify the description, I changed it to mention "each SATA controller" instead of each port. Reviewed-by: Rob Herring (Arm) Acked-by: Damien Le Moal Signed-off-by: J. Neuschäfer Link: https://lore.kernel.org/r/20250220-ppcyaml-ata-v3-1-5e727ab86247@posteo.net Signed-off-by: Niklas Cassel --- .../devicetree/bindings/ata/fsl,pq-sata.yaml | 60 +++++++++++++++++++ .../devicetree/bindings/ata/fsl-sata.txt | 28 --------- 2 files changed, 60 insertions(+), 28 deletions(-) create mode 100644 Documentation/devicetree/bindings/ata/fsl,pq-sata.yaml delete mode 100644 Documentation/devicetree/bindings/ata/fsl-sata.txt diff --git a/Documentation/devicetree/bindings/ata/fsl,pq-sata.yaml b/Documentation/devicetree/bindings/ata/fsl,pq-sata.yaml new file mode 100644 index 000000000000..1d19ee832f0c --- /dev/null +++ b/Documentation/devicetree/bindings/ata/fsl,pq-sata.yaml @@ -0,0 +1,60 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/ata/fsl,pq-sata.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Freescale 8xxx/3.0 Gb/s SATA nodes + +maintainers: + - J. Neuschäfer + +description: + SATA nodes are defined to describe on-chip Serial ATA controllers. + Each SATA controller should have its own node. + +properties: + compatible: + oneOf: + - items: + - enum: + - fsl,mpc8377-sata + - fsl,mpc8536-sata + - fsl,mpc8315-sata + - fsl,mpc8379-sata + - const: fsl,pq-sata + - const: fsl,pq-sata-v2 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + cell-index: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [1, 2, 3, 4] + description: | + 1 for controller @ 0x18000 + 2 for controller @ 0x19000 + 3 for controller @ 0x1a000 + 4 for controller @ 0x1b000 + +required: + - compatible + - interrupts + - cell-index + +additionalProperties: false + +examples: + - | + #include + sata@18000 { + compatible = "fsl,mpc8379-sata", "fsl,pq-sata"; + reg = <0x18000 0x1000>; + cell-index = <1>; + interrupts = <44 IRQ_TYPE_LEVEL_LOW>; + }; + +... diff --git a/Documentation/devicetree/bindings/ata/fsl-sata.txt b/Documentation/devicetree/bindings/ata/fsl-sata.txt deleted file mode 100644 index fd63bb3becc9..000000000000 --- a/Documentation/devicetree/bindings/ata/fsl-sata.txt +++ /dev/null @@ -1,28 +0,0 @@ -* Freescale 8xxx/3.0 Gb/s SATA nodes - -SATA nodes are defined to describe on-chip Serial ATA controllers. -Each SATA port should have its own node. - -Required properties: -- compatible : compatible list, contains 2 entries, first is - "fsl,CHIP-sata", where CHIP is the processor - (mpc8315, mpc8379, etc.) and the second is - "fsl,pq-sata" -- interrupts : -- cell-index : controller index. - 1 for controller @ 0x18000 - 2 for controller @ 0x19000 - 3 for controller @ 0x1a000 - 4 for controller @ 0x1b000 - -Optional properties: -- reg : - -Example: - sata@18000 { - compatible = "fsl,mpc8379-sata", "fsl,pq-sata"; - reg = <0x18000 0x1000>; - cell-index = <1>; - interrupts = <2c 8>; - interrupt-parent = < &ipic >; - }; From 91ec84f8eaddbc93d7c62e363d68aeb7b89879c7 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Fri, 21 Feb 2025 02:54:23 +0100 Subject: [PATCH 4/9] ata: libata-eh: Do not use ATAPI DMA for a device limited to PIO mode atapi_eh_request_sense() currently uses ATAPI DMA if the SATA controller has ATA_FLAG_PIO_DMA (PIO cmds via DMA) set. However, ATA_FLAG_PIO_DMA is a flag that can be set by a low-level driver on a port at initialization time, before any devices are scanned. If a controller detects a connected device that only supports PIO, we set the flag ATA_DFLAG_PIO. Modify atapi_eh_request_sense() to not use ATAPI DMA if the connected device only supports PIO. Reported-by: Philip Pemberton Closes: https://lore.kernel.org/linux-ide/c6722ee8-5e21-4169-af59-cbbae9edc02f@philpem.me.uk/ Tested-by: Philip Pemberton Reviewed-by: Damien Le Moal Link: https://lore.kernel.org/r/20250221015422.20687-2-cassel@kernel.org Signed-off-by: Niklas Cassel --- drivers/ata/libata-eh.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 3b303d4ae37a..16cd676eae1f 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1542,8 +1542,15 @@ unsigned int atapi_eh_request_sense(struct ata_device *dev, tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; tf.command = ATA_CMD_PACKET; - /* is it pointless to prefer PIO for "safety reasons"? */ - if (ap->flags & ATA_FLAG_PIO_DMA) { + /* + * Do not use DMA if the connected device only supports PIO, even if the + * port prefers PIO commands via DMA. + * + * Ideally, we should call atapi_check_dma() to check if it is safe for + * the LLD to use DMA for REQUEST_SENSE, but we don't have a qc. + * Since we can't check the command, perhaps we should only use pio? + */ + if ((ap->flags & ATA_FLAG_PIO_DMA) && !(dev->flags & ATA_DFLAG_PIO)) { tf.protocol = ATAPI_PROT_DMA; tf.feature |= ATAPI_PKT_DMA; } else { From 885251dc35767b1c992f6909532ca366c830814a Mon Sep 17 00:00:00 2001 From: Daniel Kral Date: Tue, 4 Mar 2025 10:20:30 +0100 Subject: [PATCH 5/9] ahci: add PCI ID for Marvell 88SE9215 SATA Controller Add support for Marvell Technology Group Ltd. 88SE9215 SATA 6 Gb/s controller, which is e.g. used in the DAWICONTROL DC-614e RAID bus controller and was not automatically recognized before. Tested with a DAWICONTROL DC-614e RAID bus controller. Signed-off-by: Daniel Kral Link: https://lore.kernel.org/r/20250304092030.37108-1-d.kral@proxmox.com Signed-off-by: Niklas Cassel --- drivers/ata/ahci.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index f813dbdc2346..52ae8f9a7dd6 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -589,6 +589,8 @@ static const struct pci_device_id ahci_pci_tbl[] = { .driver_data = board_ahci_yes_fbs }, { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x91a3), .driver_data = board_ahci_yes_fbs }, + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9215), + .driver_data = board_ahci_yes_fbs }, { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9230), .driver_data = board_ahci_yes_fbs }, { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9235), From 725ad0283033ee52c9bc73b5ea53fb7f6d496197 Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Wed, 12 Mar 2025 21:39:54 +0800 Subject: [PATCH 6/9] ata: libata: Improve return value of atapi_check_dma() atapi_check_dma() allows a LLD to filter ATAPI commands, returning a status indicating whether or not it is OK to use DMA for the supplied ATAPI command. Change atapi_check_dma() to return -EOPNOTSUPP instead of 1 for an ATAPI command that is not allowed to use DMA. Signed-off-by: Huacai Chen Link: https://lore.kernel.org/r/20250312133954.6666-1-chenhuacai@loongson.cn [cassel: improve commit log] Signed-off-by: Niklas Cassel --- drivers/ata/libata-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 9c4a21e5a8bb..193fc3942fd3 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4579,7 +4579,7 @@ int atapi_check_dma(struct ata_queued_cmd *qc) */ if (!(qc->dev->quirks & ATA_QUIRK_ATAPI_MOD16_DMA) && unlikely(qc->nbytes & 15)) - return 1; + return -EOPNOTSUPP; if (ap->ops->check_atapi_dma) return ap->ops->check_atapi_dma(qc); From b500ee5fde1bd0c85026dfcdadbc175548fb5216 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Mon, 17 Mar 2025 12:17:55 +0100 Subject: [PATCH 7/9] ata: libata: Fix NCQ Non-Data log not supported print Currently, both ata_dev_config_ncq_send_recv() - which checks for NCQ Send/Recv Log (Log Address 13h) and ata_dev_config_ncq_non_data() - which checks for NCQ Non-Data Log (Log Address 12h), uses the same print when the log is not supported: "NCQ Send/Recv Log not supported" This seems like a copy paste error, since NCQ Non-Data Log is actually a separate log. Fix the print to reference the correct log. Fixes: 284b3b77ea88 ("libata: NCQ encapsulation for ZAC MANAGEMENT OUT") Reviewed-by: Damien Le Moal Reviewed-by: Hannes Reinecke Link: https://lore.kernel.org/r/20250317111754.1666084-2-cassel@kernel.org Signed-off-by: Niklas Cassel --- drivers/ata/libata-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 193fc3942fd3..e17e16706db7 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2274,7 +2274,7 @@ static void ata_dev_config_ncq_non_data(struct ata_device *dev) if (!ata_log_supported(dev, ATA_LOG_NCQ_NON_DATA)) { ata_dev_warn(dev, - "NCQ Send/Recv Log not supported\n"); + "NCQ Non-Data Log not supported\n"); return; } err_mask = ata_read_log_page(dev, ATA_LOG_NCQ_NON_DATA, From 0507c777f5d8f9e34b137d28ee263599a7b81242 Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Tue, 18 Mar 2025 18:43:14 +0800 Subject: [PATCH 8/9] ahci: Marvell 88SE9215 controllers prefer DMA for ATAPI We use CD/DVD drives under Marvell 88SE9215 SATA controller on many Loongson-based machines. We found its PIO doesn't work well, and on the opposite its DMA seems work very well. We don't know the detail of the 88SE9215 SATA controller, but we have tested different CD/DVD drives and they all have problems under 88SE9215 (but they all work well under an Intel SATA controller). So, we consider this problem is bound to 88SE9215 SATA controller rather than bound to CD/DVD drives. As a solution, we define a new dedicated AHCI board id which is named board_ahci_yes_fbs_atapi_dma for 88SE9215, and for this id we set the AHCI_HFLAG_ATAPI_DMA_QUIRK and ATA_QUIRK_ATAPI_MOD16_DMA flags on the SATA controller in order to prefer ATAPI DMA. Reported-by: Yuli Wang Tested-by: Jie Fan Tested-by: Erpeng Xu Tested-by: Yuli Wang Signed-off-by: Huacai Chen Link: https://lore.kernel.org/r/20250318104314.2160526-1-chenhuacai@loongson.cn Signed-off-by: Niklas Cassel --- drivers/ata/ahci.c | 11 ++++++++++- drivers/ata/ahci.h | 1 + drivers/ata/libahci.c | 4 ++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 52ae8f9a7dd6..f3a6bfe098cd 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -63,6 +63,7 @@ enum board_ids { board_ahci_pcs_quirk_no_devslp, board_ahci_pcs_quirk_no_sntf, board_ahci_yes_fbs, + board_ahci_yes_fbs_atapi_dma, /* board IDs for specific chipsets in alphabetical order */ board_ahci_al, @@ -188,6 +189,14 @@ static const struct ata_port_info ahci_port_info[] = { .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, }, + [board_ahci_yes_fbs_atapi_dma] = { + AHCI_HFLAGS (AHCI_HFLAG_YES_FBS | + AHCI_HFLAG_ATAPI_DMA_QUIRK), + .flags = AHCI_FLAG_COMMON, + .pio_mask = ATA_PIO4, + .udma_mask = ATA_UDMA6, + .port_ops = &ahci_ops, + }, /* by chipsets */ [board_ahci_al] = { AHCI_HFLAGS (AHCI_HFLAG_NO_PMP | AHCI_HFLAG_NO_MSI), @@ -590,7 +599,7 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x91a3), .driver_data = board_ahci_yes_fbs }, { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9215), - .driver_data = board_ahci_yes_fbs }, + .driver_data = board_ahci_yes_fbs_atapi_dma }, { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9230), .driver_data = board_ahci_yes_fbs }, { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9235), diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index 8e895ae45c86..ba8b811fbe30 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -246,6 +246,7 @@ enum { AHCI_HFLAG_NO_SXS = BIT(26), /* SXS not supported */ AHCI_HFLAG_43BIT_ONLY = BIT(27), /* 43bit DMA addr limit */ AHCI_HFLAG_INTEL_PCS_QUIRK = BIT(28), /* apply Intel PCS quirk */ + AHCI_HFLAG_ATAPI_DMA_QUIRK = BIT(29), /* force ATAPI to use DMA */ /* ap->flags bits */ diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index fdfa7b266218..a28ffe1e5969 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -1321,6 +1321,10 @@ static void ahci_dev_config(struct ata_device *dev) { struct ahci_host_priv *hpriv = dev->link->ap->host->private_data; + if ((dev->class == ATA_DEV_ATAPI) && + (hpriv->flags & AHCI_HFLAG_ATAPI_DMA_QUIRK)) + dev->quirks |= ATA_QUIRK_ATAPI_MOD16_DMA; + if (hpriv->flags & AHCI_HFLAG_SECT255) { dev->max_sectors = 255; ata_dev_info(dev, From 565d065acd7ea871874ac32e54e58af2d15a182a Mon Sep 17 00:00:00 2001 From: Tomas Henzl Date: Wed, 19 Mar 2025 16:50:30 +0100 Subject: [PATCH 9/9] ata: ahci: simplify init function This patch moves all the IRQ vector allocations into a single function. Instead of having the allocations spread out over two separate call sites everything will be handled in ahci_init_irq. Also a direct call into pci(m)_intx will be removed. The main part of this change is done by adding a PCI_IRQ_INTX flag into an already existing pci_alloc_irq_vectors invocation. In the current implementation of the pci_alloc_irq_vectors is the sequence of calls msi-x -> msi -> legacy irq and whatever there succeeds stops the call chain. That makes it impossible to merge all instances into as a single call to pci_alloc_irq_vectors since the order of calls there is: multiple msi-x a single msi a single msi-x a legacy irq. The two last steps can be merged into a single one which are the msi-x and legacy irq option. When PCI_IRQ_INTX flag is set the pci_alloc_irq_vectors succeeds in almost all cases - that makes it possible to convert ahci_init_irq(msi) into a void function. The exception is when dev->irq is zero then the pci_alloc_irq_vectors may return with an error code also pci_intx isn't called from pci_alloc_irq_vectors and thus certain pci calls aren't performed. That's just a negligible issue as later in ahci_init_one the (zero) value of dev->irq is via pci_irq_vector assigned to hpriv->irq. That value is then later tested in ahci_host_activate->ata_host_activate where it is welcomed with a WARN_ON message and fails with setting up irq and then the probe function (ahci_init_one) fails. The special zero value's meaning is that polling mode is being be set up which isn't the case. No functional change. Signed-off-by: Tomas Henzl Link: https://lore.kernel.org/r/20250319155030.16410-1-thenzl@redhat.com Signed-off-by: Niklas Cassel --- drivers/ata/ahci.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index f3a6bfe098cd..163ac909bd06 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1676,13 +1676,15 @@ static int ahci_get_irq_vector(struct ata_host *host, int port) return pci_irq_vector(to_pci_dev(host->dev), port); } -static int ahci_init_msi(struct pci_dev *pdev, unsigned int n_ports, +static void ahci_init_irq(struct pci_dev *pdev, unsigned int n_ports, struct ahci_host_priv *hpriv) { int nvec; - if (hpriv->flags & AHCI_HFLAG_NO_MSI) - return -ENODEV; + if (hpriv->flags & AHCI_HFLAG_NO_MSI) { + pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_INTX); + return; + } /* * If number of MSIs is less than number of ports then Sharing Last @@ -1696,7 +1698,7 @@ static int ahci_init_msi(struct pci_dev *pdev, unsigned int n_ports, if (!(readl(hpriv->mmio + HOST_CTL) & HOST_MRSM)) { hpriv->get_irq_vector = ahci_get_irq_vector; hpriv->flags |= AHCI_HFLAG_MULTI_MSI; - return nvec; + return; } /* @@ -1711,12 +1713,13 @@ static int ahci_init_msi(struct pci_dev *pdev, unsigned int n_ports, /* * If the host is not capable of supporting per-port vectors, fall - * back to single MSI before finally attempting single MSI-X. + * back to single MSI before finally attempting single MSI-X or + * a legacy INTx. */ nvec = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI); if (nvec == 1) - return nvec; - return pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSIX); + return; + pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSIX | PCI_IRQ_INTX); } static void ahci_mark_external_port(struct ata_port *ap) @@ -1996,10 +1999,8 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) } host->private_data = hpriv; - if (ahci_init_msi(pdev, n_ports, hpriv) < 0) { - /* legacy intx interrupts */ - pcim_intx(pdev, 1); - } + ahci_init_irq(pdev, n_ports, hpriv); + hpriv->irq = pci_irq_vector(pdev, 0); if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)