Skip to content

Commit 8c87215

Browse files
Josua-SRdamien-lemoal
authored andcommitted
ata: libahci_platform: support non-consecutive port numbers
So far ahci_platform relied on number of child nodes in firmware to allocate arrays and expected port numbers to start from 0 without holes. This number of ports is then set in private structure for use when configuring phys and regulators. Some platforms may not use every port of an ahci controller. E.g. SolidRUN CN9130 Clearfog uses only port 1 but not port 0, leading to the following errors during boot: [ 1.719476] ahci f2540000.sata: invalid port number 1 [ 1.724562] ahci f2540000.sata: No port enabled Update all accessesors of ahci_host_priv phys and target_pwrs arrays to support holes. Access is gated by hpriv->mask_port_map which has a bit set for each enabled port. Update ahci_platform_get_resources to ignore holes in the port numbers and enable ports defined in firmware by their reg property only. When firmware does not define children it is assumed that there is exactly one port, using index 0. Signed-off-by: Josua Mayer <josua@solid-run.com> Reviewed-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
1 parent 7b64859 commit 8c87215

File tree

3 files changed

+43
-6
lines changed

3 files changed

+43
-6
lines changed

drivers/ata/ahci_brcm.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,9 @@ static unsigned int brcm_ahci_read_id(struct ata_device *dev,
288288

289289
/* Re-initialize and calibrate the PHY */
290290
for (i = 0; i < hpriv->nports; i++) {
291+
if (!(hpriv->mask_port_map & (1 << i)))
292+
continue;
293+
291294
rc = phy_init(hpriv->phys[i]);
292295
if (rc)
293296
goto disable_phys;

drivers/ata/ahci_ceva.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,9 @@ static int ceva_ahci_platform_enable_resources(struct ahci_host_priv *hpriv)
206206
goto disable_clks;
207207

208208
for (i = 0; i < hpriv->nports; i++) {
209+
if (!(hpriv->mask_port_map & (1 << i)))
210+
continue;
211+
209212
rc = phy_init(hpriv->phys[i]);
210213
if (rc)
211214
goto disable_rsts;
@@ -215,6 +218,9 @@ static int ceva_ahci_platform_enable_resources(struct ahci_host_priv *hpriv)
215218
ahci_platform_deassert_rsts(hpriv);
216219

217220
for (i = 0; i < hpriv->nports; i++) {
221+
if (!(hpriv->mask_port_map & (1 << i)))
222+
continue;
223+
218224
rc = phy_power_on(hpriv->phys[i]);
219225
if (rc) {
220226
phy_exit(hpriv->phys[i]);

drivers/ata/libahci_platform.c

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ int ahci_platform_enable_phys(struct ahci_host_priv *hpriv)
4949
int rc, i;
5050

5151
for (i = 0; i < hpriv->nports; i++) {
52+
if (!(hpriv->mask_port_map & (1 << i)))
53+
continue;
54+
5255
rc = phy_init(hpriv->phys[i]);
5356
if (rc)
5457
goto disable_phys;
@@ -70,6 +73,9 @@ int ahci_platform_enable_phys(struct ahci_host_priv *hpriv)
7073

7174
disable_phys:
7275
while (--i >= 0) {
76+
if (!(hpriv->mask_port_map & (1 << i)))
77+
continue;
78+
7379
phy_power_off(hpriv->phys[i]);
7480
phy_exit(hpriv->phys[i]);
7581
}
@@ -88,6 +94,9 @@ void ahci_platform_disable_phys(struct ahci_host_priv *hpriv)
8894
int i;
8995

9096
for (i = 0; i < hpriv->nports; i++) {
97+
if (!(hpriv->mask_port_map & (1 << i)))
98+
continue;
99+
91100
phy_power_off(hpriv->phys[i]);
92101
phy_exit(hpriv->phys[i]);
93102
}
@@ -432,6 +441,20 @@ static int ahci_platform_get_firmware(struct ahci_host_priv *hpriv,
432441
return 0;
433442
}
434443

444+
static u32 ahci_platform_find_max_port_id(struct device *dev)
445+
{
446+
u32 max_port = 0;
447+
448+
for_each_child_of_node_scoped(dev->of_node, child) {
449+
u32 port;
450+
451+
if (!of_property_read_u32(child, "reg", &port))
452+
max_port = max(max_port, port);
453+
}
454+
455+
return max_port;
456+
}
457+
435458
/**
436459
* ahci_platform_get_resources - Get platform resources
437460
* @pdev: platform device to get resources for
@@ -458,6 +481,7 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
458481
struct device *dev = &pdev->dev;
459482
struct ahci_host_priv *hpriv;
460483
u32 mask_port_map = 0;
484+
u32 max_port;
461485

462486
if (!devres_open_group(dev, NULL, GFP_KERNEL))
463487
return ERR_PTR(-ENOMEM);
@@ -549,15 +573,17 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
549573
goto err_out;
550574
}
551575

576+
/* find maximum port id for allocating structures */
577+
max_port = ahci_platform_find_max_port_id(dev);
552578
/*
553-
* If no sub-node was found, we still need to set nports to
554-
* one in order to be able to use the
579+
* Set nports according to maximum port id. Clamp at
580+
* AHCI_MAX_PORTS, warning message for invalid port id
581+
* is generated later.
582+
* When DT has no sub-nodes max_port is 0, nports is 1,
583+
* in order to be able to use the
555584
* ahci_platform_[en|dis]able_[phys|regulators] functions.
556585
*/
557-
if (child_nodes)
558-
hpriv->nports = child_nodes;
559-
else
560-
hpriv->nports = 1;
586+
hpriv->nports = min(AHCI_MAX_PORTS, max_port + 1);
561587

562588
hpriv->phys = devm_kcalloc(dev, hpriv->nports, sizeof(*hpriv->phys), GFP_KERNEL);
563589
if (!hpriv->phys) {
@@ -625,6 +651,8 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
625651
* If no sub-node was found, keep this for device tree
626652
* compatibility
627653
*/
654+
hpriv->mask_port_map |= BIT(0);
655+
628656
rc = ahci_platform_get_phy(hpriv, 0, dev, dev->of_node);
629657
if (rc)
630658
goto err_out;

0 commit comments

Comments
 (0)