2
0
mirror of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git synced 2025-09-04 20:19:47 +08:00

ata fixes for 6.17-rc4

- Fix the type of return values to be signed in the ahci_xgen driver
    (Qianfeng).
 
  - Add the mask_port_ext module parameter to the ahci driver. This is to
    allow a user to ignore ports that are advertized as external (hotplug
    capable) in favor of lower link power management policies instead of
    the default max_performance for these ports. This is useful to allow
    e.g. laptops to go into low power states when hooked up to docking
    station with sata slots, connected with an external port for hotplug
    (me).
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQSRPv8tYSvhwAzJdzjdoc3SxdoYdgUCaLFeigAKCRDdoc3SxdoY
 dowvAP9Ui0ymEcYwOsuYDX2APDqe8B9+KJMkNLeRMbZdkK5zlAD/dVB/wxQNolOU
 UaYSYfRXHBjcoTI6jmxhOlXkryIvBAo=
 =iGob
 -----END PGP SIGNATURE-----

Merge tag 'ata-6.17-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/libata/linux

Pull ata fixes from Damien Le Moal:

 - Fix the type of return values to be signed in the ahci_xgen driver
   (Qianfeng)

 - Add the mask_port_ext module parameter to the ahci driver.

   This is to allow a user to ignore ports that are advertized as
   external (hotplug capable) in favor of lower link power management
   policies instead of the default max_performance for these ports.

   This is useful to allow e.g. laptops to go into low power states when
   hooked up to docking station with sata slots, connected with an
   external port for hotplug (me)

* tag 'ata-6.17-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/libata/linux:
  ata: ahci_xgene: Use int type for 'rc' to store error codes
  ata: ahci: Allow ignoring the external/hotplug capability of ports
This commit is contained in:
Linus Torvalds 2025-08-29 07:29:17 -07:00
commit 2bd3731542
3 changed files with 43 additions and 22 deletions

View File

@ -689,40 +689,50 @@ MODULE_PARM_DESC(mask_port_map,
"where <pci_dev> is the PCI ID of an AHCI controller in the "
"form \"domain:bus:dev.func\"");
static void ahci_apply_port_map_mask(struct device *dev,
struct ahci_host_priv *hpriv, char *mask_s)
static char *ahci_mask_port_ext;
module_param_named(mask_port_ext, ahci_mask_port_ext, charp, 0444);
MODULE_PARM_DESC(mask_port_ext,
"32-bits mask to ignore the external/hotplug capability of ports. "
"Valid values are: "
"\"<mask>\" to apply the same mask to all AHCI controller "
"devices, and \"<pci_dev>=<mask>,<pci_dev>=<mask>,...\" to "
"specify different masks for the controllers specified, "
"where <pci_dev> is the PCI ID of an AHCI controller in the "
"form \"domain:bus:dev.func\"");
static u32 ahci_port_mask(struct device *dev, char *mask_s)
{
unsigned int mask;
if (kstrtouint(mask_s, 0, &mask)) {
dev_err(dev, "Invalid port map mask\n");
return;
return 0;
}
hpriv->mask_port_map = mask;
return mask;
}
static void ahci_get_port_map_mask(struct device *dev,
struct ahci_host_priv *hpriv)
static u32 ahci_get_port_mask(struct device *dev, char *mask_p)
{
char *param, *end, *str, *mask_s;
char *name;
u32 mask = 0;
if (!strlen(ahci_mask_port_map))
return;
if (!mask_p || !strlen(mask_p))
return 0;
str = kstrdup(ahci_mask_port_map, GFP_KERNEL);
str = kstrdup(mask_p, GFP_KERNEL);
if (!str)
return;
return 0;
/* Handle single mask case */
if (!strchr(str, '=')) {
ahci_apply_port_map_mask(dev, hpriv, str);
mask = ahci_port_mask(dev, str);
goto free;
}
/*
* Mask list case: parse the parameter to apply the mask only if
* Mask list case: parse the parameter to get the mask only if
* the device name matches.
*/
param = str;
@ -752,11 +762,13 @@ static void ahci_get_port_map_mask(struct device *dev,
param++;
}
ahci_apply_port_map_mask(dev, hpriv, mask_s);
mask = ahci_port_mask(dev, mask_s);
}
free:
kfree(str);
return mask;
}
static void ahci_pci_save_initial_config(struct pci_dev *pdev,
@ -782,8 +794,10 @@ static void ahci_pci_save_initial_config(struct pci_dev *pdev,
}
/* Handle port map masks passed as module parameter. */
if (ahci_mask_port_map)
ahci_get_port_map_mask(&pdev->dev, hpriv);
hpriv->mask_port_map =
ahci_get_port_mask(&pdev->dev, ahci_mask_port_map);
hpriv->mask_port_ext =
ahci_get_port_mask(&pdev->dev, ahci_mask_port_ext);
ahci_save_initial_config(&pdev->dev, hpriv);
}
@ -1757,11 +1771,20 @@ static void ahci_mark_external_port(struct ata_port *ap)
void __iomem *port_mmio = ahci_port_base(ap);
u32 tmp;
/* mark external ports (hotplug-capable, eSATA) */
/*
* Mark external ports (hotplug-capable, eSATA), unless we were asked to
* ignore this feature.
*/
tmp = readl(port_mmio + PORT_CMD);
if (((tmp & PORT_CMD_ESP) && (hpriv->cap & HOST_CAP_SXS)) ||
(tmp & PORT_CMD_HPCP))
(tmp & PORT_CMD_HPCP)) {
if (hpriv->mask_port_ext & (1U << ap->port_no)) {
ata_port_info(ap,
"Ignoring external/hotplug capability\n");
return;
}
ap->pflags |= ATA_PFLAG_EXTERNAL;
}
}
static void ahci_update_initial_lpm_policy(struct ata_port *ap)

View File

@ -330,6 +330,7 @@ struct ahci_host_priv {
/* Input fields */
unsigned int flags; /* AHCI_HFLAG_* */
u32 mask_port_map; /* Mask of valid ports */
u32 mask_port_ext; /* Mask of ports ext capability */
void __iomem * mmio; /* bus-independent mem map */
u32 cap; /* cap to use */

View File

@ -450,7 +450,6 @@ static int xgene_ahci_pmp_softreset(struct ata_link *link, unsigned int *class,
{
int pmp = sata_srst_pmp(link);
struct ata_port *ap = link->ap;
u32 rc;
void __iomem *port_mmio = ahci_port_base(ap);
u32 port_fbs;
@ -463,9 +462,7 @@ static int xgene_ahci_pmp_softreset(struct ata_link *link, unsigned int *class,
port_fbs |= pmp << PORT_FBS_DEV_OFFSET;
writel(port_fbs, port_mmio + PORT_FBS);
rc = ahci_do_softreset(link, class, pmp, deadline, ahci_check_ready);
return rc;
return ahci_do_softreset(link, class, pmp, deadline, ahci_check_ready);
}
/**
@ -500,7 +497,7 @@ static int xgene_ahci_softreset(struct ata_link *link, unsigned int *class,
u32 port_fbs;
u32 port_fbs_save;
u32 retry = 1;
u32 rc;
int rc;
port_fbs_save = readl(port_mmio + PORT_FBS);