ata: libata-acpi: Do not assume 40 wire cable if no devices are enabled
authorTasos Sahanidis <tasos@tasossah.com>
Mon, 19 May 2025 08:56:55 +0000 (11:56 +0300)
committerNiklas Cassel <cassel@kernel.org>
Tue, 10 Jun 2025 12:08:24 +0000 (14:08 +0200)
On at least an ASRock 990FX Extreme 4 with a VIA VT6330, the devices
have not yet been enabled by the first time ata_acpi_cbl_80wire() is
called. This means that the ata_for_each_dev loop is never entered,
and a 40 wire cable is assumed.

The VIA controller on this board does not report the cable in the PCI
config space, thus having to fall back to ACPI even though no SATA
bridge is present.

The _GTM values are correctly reported by the firmware through ACPI,
which has already set up faster transfer modes, but due to the above
the controller is forced down to a maximum of UDMA/33.

Resolve this by modifying ata_acpi_cbl_80wire() to directly return the
cable type. First, an unknown cable is assumed which preserves the mode
set by the firmware, and then on subsequent calls when the devices have
been enabled, an 80 wire cable is correctly detected.

Since the function now directly returns the cable type, it is renamed
to ata_acpi_cbl_pata_type().

Signed-off-by: Tasos Sahanidis <tasos@tasossah.com>
Link: https://lore.kernel.org/r/20250519085945.1399466-1-tasos@tasossah.com
Signed-off-by: Niklas Cassel <cassel@kernel.org>
drivers/ata/libata-acpi.c
drivers/ata/pata_via.c
include/linux/libata.h

index b7f0bf795521343ad438c9eda52b307e1c6d71ba..f2140fc06ba0f8255d1c0bdc89216007dafd6168 100644 (file)
@@ -514,15 +514,19 @@ unsigned int ata_acpi_gtm_xfermask(struct ata_device *dev,
 EXPORT_SYMBOL_GPL(ata_acpi_gtm_xfermask);
 
 /**
- * ata_acpi_cbl_80wire         -       Check for 80 wire cable
+ * ata_acpi_cbl_pata_type - Return PATA cable type
  * @ap: Port to check
- * @gtm: GTM data to use
  *
- * Return 1 if the @gtm indicates the BIOS selected an 80wire mode.
+ * Return ATA_CBL_PATA* according to the transfer mode selected by BIOS
  */
-int ata_acpi_cbl_80wire(struct ata_port *ap, const struct ata_acpi_gtm *gtm)
+int ata_acpi_cbl_pata_type(struct ata_port *ap)
 {
        struct ata_device *dev;
+       int ret = ATA_CBL_PATA_UNK;
+       const struct ata_acpi_gtm *gtm = ata_acpi_init_gtm(ap);
+
+       if (!gtm)
+               return ATA_CBL_PATA40;
 
        ata_for_each_dev(dev, &ap->link, ENABLED) {
                unsigned int xfer_mask, udma_mask;
@@ -530,13 +534,17 @@ int ata_acpi_cbl_80wire(struct ata_port *ap, const struct ata_acpi_gtm *gtm)
                xfer_mask = ata_acpi_gtm_xfermask(dev, gtm);
                ata_unpack_xfermask(xfer_mask, NULL, NULL, &udma_mask);
 
-               if (udma_mask & ~ATA_UDMA_MASK_40C)
-                       return 1;
+               ret = ATA_CBL_PATA40;
+
+               if (udma_mask & ~ATA_UDMA_MASK_40C) {
+                       ret = ATA_CBL_PATA80;
+                       break;
+               }
        }
 
-       return 0;
+       return ret;
 }
-EXPORT_SYMBOL_GPL(ata_acpi_cbl_80wire);
+EXPORT_SYMBOL_GPL(ata_acpi_cbl_pata_type);
 
 static void ata_acpi_gtf_to_tf(struct ata_device *dev,
                               const struct ata_acpi_gtf *gtf,
index d82728a01832b51b58f55c11dcdf80aa4a6bab46..bb80e7800dcbe91b0b63c21b03fc283d25a33c3a 100644 (file)
@@ -201,11 +201,9 @@ static int via_cable_detect(struct ata_port *ap) {
           two drives */
        if (ata66 & (0x10100000 >> (16 * ap->port_no)))
                return ATA_CBL_PATA80;
+
        /* Check with ACPI so we can spot BIOS reported SATA bridges */
-       if (ata_acpi_init_gtm(ap) &&
-           ata_acpi_cbl_80wire(ap, ata_acpi_init_gtm(ap)))
-               return ATA_CBL_PATA80;
-       return ATA_CBL_PATA40;
+       return ata_acpi_cbl_pata_type(ap);
 }
 
 static int via_pre_reset(struct ata_link *link, unsigned long deadline)
index 31be45fd47a616f0cce7195d2b6e7f4214962e15..1e5aec839041de78b0b37ee4f9f7c6483911402b 100644 (file)
@@ -1352,7 +1352,7 @@ int ata_acpi_stm(struct ata_port *ap, const struct ata_acpi_gtm *stm);
 int ata_acpi_gtm(struct ata_port *ap, struct ata_acpi_gtm *stm);
 unsigned int ata_acpi_gtm_xfermask(struct ata_device *dev,
                                   const struct ata_acpi_gtm *gtm);
-int ata_acpi_cbl_80wire(struct ata_port *ap, const struct ata_acpi_gtm *gtm);
+int ata_acpi_cbl_pata_type(struct ata_port *ap);
 #else
 static inline const struct ata_acpi_gtm *ata_acpi_init_gtm(struct ata_port *ap)
 {
@@ -1377,10 +1377,9 @@ static inline unsigned int ata_acpi_gtm_xfermask(struct ata_device *dev,
        return 0;
 }
 
-static inline int ata_acpi_cbl_80wire(struct ata_port *ap,
-                                     const struct ata_acpi_gtm *gtm)
+static inline int ata_acpi_cbl_pata_type(struct ata_port *ap)
 {
-       return 0;
+       return ATA_CBL_PATA40;
 }
 #endif