Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ata: ahci_ceva: fix error handling for Xilinx GT PHY support

Platform clock and phy error resources are not cleaned up in Xilinx GT PHY
error path.

To fix introduce the function ceva_ahci_platform_enable_resources() which
is a customized version of ahci_platform_enable_resources() and inline with
SATA IP programming sequence it does:

- Assert SATA reset
- Program PS GTR phy
- Bring SATA by de-asserting the reset
- Wait for GT lane PLL to be locked

ceva_ahci_platform_enable_resources() is also used in the resume path
as the same SATA programming sequence (as in probe) should be followed.
Also cleanup the mixed usage of ahci_platform_enable_resources() and custom
implementation in the probe function as both are not required.

Fixes: 9a9d3abe24bb ("ata: ahci: ceva: Update the driver to support xilinx GT phy")
Signed-off-by: Radhey Shyam Pandey <radhey.shyam.pandey@amd.com>
Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Signed-off-by: Niklas Cassel <cassel@kernel.org>

authored by

Radhey Shyam Pandey and committed by
Niklas Cassel
26c8404e 9815e396

+79 -46
+79 -46
drivers/ata/ahci_ceva.c
··· 88 88 u32 axicc; 89 89 bool is_cci_enabled; 90 90 int flags; 91 - struct reset_control *rst; 92 91 }; 93 92 94 93 static unsigned int ceva_ahci_read_id(struct ata_device *dev, ··· 188 189 AHCI_SHT(DRV_NAME), 189 190 }; 190 191 192 + static int ceva_ahci_platform_enable_resources(struct ahci_host_priv *hpriv) 193 + { 194 + int rc, i; 195 + 196 + rc = ahci_platform_enable_regulators(hpriv); 197 + if (rc) 198 + return rc; 199 + 200 + rc = ahci_platform_enable_clks(hpriv); 201 + if (rc) 202 + goto disable_regulator; 203 + 204 + /* Assert the controller reset */ 205 + rc = ahci_platform_assert_rsts(hpriv); 206 + if (rc) 207 + goto disable_clks; 208 + 209 + for (i = 0; i < hpriv->nports; i++) { 210 + rc = phy_init(hpriv->phys[i]); 211 + if (rc) 212 + goto disable_rsts; 213 + } 214 + 215 + /* De-assert the controller reset */ 216 + ahci_platform_deassert_rsts(hpriv); 217 + 218 + for (i = 0; i < hpriv->nports; i++) { 219 + rc = phy_power_on(hpriv->phys[i]); 220 + if (rc) { 221 + phy_exit(hpriv->phys[i]); 222 + goto disable_phys; 223 + } 224 + } 225 + 226 + return 0; 227 + 228 + disable_rsts: 229 + ahci_platform_deassert_rsts(hpriv); 230 + 231 + disable_phys: 232 + while (--i >= 0) { 233 + phy_power_off(hpriv->phys[i]); 234 + phy_exit(hpriv->phys[i]); 235 + } 236 + 237 + disable_clks: 238 + ahci_platform_disable_clks(hpriv); 239 + 240 + disable_regulator: 241 + ahci_platform_disable_regulators(hpriv); 242 + 243 + return rc; 244 + } 245 + 191 246 static int ceva_ahci_probe(struct platform_device *pdev) 192 247 { 193 248 struct device_node *np = pdev->dev.of_node; ··· 256 203 return -ENOMEM; 257 204 258 205 cevapriv->ahci_pdev = pdev; 259 - 260 - cevapriv->rst = devm_reset_control_get_optional_exclusive(&pdev->dev, 261 - NULL); 262 - if (IS_ERR(cevapriv->rst)) 263 - dev_err_probe(&pdev->dev, PTR_ERR(cevapriv->rst), 264 - "failed to get reset\n"); 265 - 266 206 hpriv = ahci_platform_get_resources(pdev, 0); 267 207 if (IS_ERR(hpriv)) 268 208 return PTR_ERR(hpriv); 269 209 270 - if (!cevapriv->rst) { 271 - rc = ahci_platform_enable_resources(hpriv); 272 - if (rc) 273 - return rc; 274 - } else { 275 - int i; 210 + hpriv->rsts = devm_reset_control_get_optional_exclusive(&pdev->dev, 211 + NULL); 212 + if (IS_ERR(hpriv->rsts)) 213 + return dev_err_probe(&pdev->dev, PTR_ERR(hpriv->rsts), 214 + "failed to get reset\n"); 276 215 277 - rc = ahci_platform_enable_clks(hpriv); 278 - if (rc) 279 - return rc; 280 - /* Assert the controller reset */ 281 - reset_control_assert(cevapriv->rst); 282 - 283 - for (i = 0; i < hpriv->nports; i++) { 284 - rc = phy_init(hpriv->phys[i]); 285 - if (rc) 286 - return rc; 287 - } 288 - 289 - /* De-assert the controller reset */ 290 - reset_control_deassert(cevapriv->rst); 291 - 292 - for (i = 0; i < hpriv->nports; i++) { 293 - rc = phy_power_on(hpriv->phys[i]); 294 - if (rc) { 295 - phy_exit(hpriv->phys[i]); 296 - return rc; 297 - } 298 - } 299 - } 216 + rc = ceva_ahci_platform_enable_resources(hpriv); 217 + if (rc) 218 + return rc; 300 219 301 220 if (of_property_read_bool(np, "ceva,broken-gen2")) 302 221 cevapriv->flags = CEVA_FLAG_BROKEN_GEN2; ··· 277 252 if (of_property_read_u8_array(np, "ceva,p0-cominit-params", 278 253 (u8 *)&cevapriv->pp2c[0], 4) < 0) { 279 254 dev_warn(dev, "ceva,p0-cominit-params property not defined\n"); 280 - return -EINVAL; 255 + rc = -EINVAL; 256 + goto disable_resources; 281 257 } 282 258 283 259 if (of_property_read_u8_array(np, "ceva,p1-cominit-params", 284 260 (u8 *)&cevapriv->pp2c[1], 4) < 0) { 285 261 dev_warn(dev, "ceva,p1-cominit-params property not defined\n"); 286 - return -EINVAL; 262 + rc = -EINVAL; 263 + goto disable_resources; 287 264 } 288 265 289 266 /* Read OOB timing value for COMWAKE from device-tree*/ 290 267 if (of_property_read_u8_array(np, "ceva,p0-comwake-params", 291 268 (u8 *)&cevapriv->pp3c[0], 4) < 0) { 292 269 dev_warn(dev, "ceva,p0-comwake-params property not defined\n"); 293 - return -EINVAL; 270 + rc = -EINVAL; 271 + goto disable_resources; 294 272 } 295 273 296 274 if (of_property_read_u8_array(np, "ceva,p1-comwake-params", 297 275 (u8 *)&cevapriv->pp3c[1], 4) < 0) { 298 276 dev_warn(dev, "ceva,p1-comwake-params property not defined\n"); 299 - return -EINVAL; 277 + rc = -EINVAL; 278 + goto disable_resources; 300 279 } 301 280 302 281 /* Read phy BURST timing value from device-tree */ 303 282 if (of_property_read_u8_array(np, "ceva,p0-burst-params", 304 283 (u8 *)&cevapriv->pp4c[0], 4) < 0) { 305 284 dev_warn(dev, "ceva,p0-burst-params property not defined\n"); 306 - return -EINVAL; 285 + rc = -EINVAL; 286 + goto disable_resources; 307 287 } 308 288 309 289 if (of_property_read_u8_array(np, "ceva,p1-burst-params", 310 290 (u8 *)&cevapriv->pp4c[1], 4) < 0) { 311 291 dev_warn(dev, "ceva,p1-burst-params property not defined\n"); 312 - return -EINVAL; 292 + rc = -EINVAL; 293 + goto disable_resources; 313 294 } 314 295 315 296 /* Read phy RETRY interval timing value from device-tree */ 316 297 if (of_property_read_u16_array(np, "ceva,p0-retry-params", 317 298 (u16 *)&cevapriv->pp5c[0], 2) < 0) { 318 299 dev_warn(dev, "ceva,p0-retry-params property not defined\n"); 319 - return -EINVAL; 300 + rc = -EINVAL; 301 + goto disable_resources; 320 302 } 321 303 322 304 if (of_property_read_u16_array(np, "ceva,p1-retry-params", 323 305 (u16 *)&cevapriv->pp5c[1], 2) < 0) { 324 306 dev_warn(dev, "ceva,p1-retry-params property not defined\n"); 325 - return -EINVAL; 307 + rc = -EINVAL; 308 + goto disable_resources; 326 309 } 327 310 328 311 /* ··· 368 335 struct ahci_host_priv *hpriv = host->private_data; 369 336 int rc; 370 337 371 - rc = ahci_platform_enable_resources(hpriv); 338 + rc = ceva_ahci_platform_enable_resources(hpriv); 372 339 if (rc) 373 340 return rc; 374 341