Skip to content

Commit bef9d8c

Browse files
rizlikdanielinux
authored andcommitted
ahci/sata: improve wait for clear operations
1 parent b3465b5 commit bef9d8c

File tree

1 file changed

+77
-51
lines changed

1 file changed

+77
-51
lines changed

src/x86/ahci.c

Lines changed: 77 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ __attribute__((aligned(HBA_TBL_ALIGN)));
9797
#define PCI_REG_MAP_AHCI_MODE (0x1 << 6)
9898
#define PCI_REG_MAP_ALL_PORTS (0x1 << 5)
9999

100+
#define SATA_MAX_TRIES (5)
101+
#define SATA_DELAY (100)
102+
100103
#ifdef DEBUG_AHCI
101104
#define AHCI_DEBUG_PRINTF(...) wolfBoot_printf(__VA_ARGS__)
102105
#else
@@ -416,6 +419,40 @@ static int sata_unlock_disk(int drv)
416419
return 0;
417420
}
418421
#endif /* WOLFBOOT_ATA_DISK_LOCK */
422+
423+
/**
424+
* @brief Waits until a specific address is cleared by a given mask.
425+
*
426+
* This function waits until a specific 32-bit PCI memory address is cleared by a given
427+
* mask. After SATA_DELAY * SATA_MAX_TRIES ms, if the address in memory is not
428+
* cleared, the function returns -1. *
429+
* @param[in] address The memory address to monitor.
430+
* @param[in] mask The mask to apply to the value at the address.
431+
*
432+
* @return 0 if the masked bits are cleared within the specified number of
433+
* tries, 1 otherwise.
434+
*/
435+
static int sata_wait_until_clear(uint32_t address, uint32_t mask)
436+
{
437+
int count = SATA_MAX_TRIES;
438+
uint32_t reg;
439+
int ret = -1;
440+
441+
while (1) {
442+
if (count-- == 0)
443+
break;
444+
445+
reg = mmio_read32(address);
446+
if ((reg & mask) == 0) {
447+
ret = 0;
448+
break;
449+
}
450+
delay(SATA_DELAY);
451+
}
452+
453+
return ret;
454+
}
455+
419456
/**
420457
* @brief Enables SATA ports and detects connected SATA disks.
421458
*
@@ -451,12 +488,15 @@ void sata_enable(uint32_t base)
451488
mmio_or32(AHCI_HBA_GHC(base), HBA_GHC_HR | HBA_GHC_IE);
452489

453490
/* Wait until reset is complete */
454-
while ((mmio_read32(AHCI_HBA_GHC(base)) & HBA_GHC_HR) != 0)
455-
;
456-
491+
r = sata_wait_until_clear(AHCI_HBA_GHC(base), HBA_GHC_HR);
492+
if (r != 0) {
493+
wolfBoot_printf("ACHI: timeout waiting reset\r\n");
494+
panic();
495+
}
496+
457497
/* Wait until enabled. */
458498
if ((mmio_read32(AHCI_HBA_GHC(base)) & HBA_GHC_AE) == 0)
459-
mmio_or32(AHCI_HBA_GHC(base), HBA_GHC_AE);;
499+
mmio_or32(AHCI_HBA_GHC(base), HBA_GHC_AE);
460500

461501
AHCI_DEBUG_PRINTF("AHCI reset complete.\r\n");
462502

@@ -502,20 +542,18 @@ void sata_enable(uint32_t base)
502542
mmio_or32(AHCI_PxSCTL(base, i), (0x03 << 8));
503543

504544
/* Disable interrupt reporting to SW */
505-
//mmio_write32(AHCI_PxIE(base, i), 0);
506-
507545
count = 0;
508546
while (1) {
509547
ssts = mmio_read32(AHCI_PxSSTS(base, i));
510548
ipm = (ssts >> 8) & 0x0F;
511549
ssts &= AHCI_SSTS_DET_MASK;
512550
if (ssts == AHCI_PORT_SSTS_DET_PCE)
513551
break;
514-
if (count++ > 5) {
552+
if (count++ > SATA_MAX_TRIES) {
515553
AHCI_DEBUG_PRINTF("AHCI port %d: Timeout occurred.\r\n", i);
516554
break;
517555
}
518-
delay(1000);
556+
delay(SATA_DELAY);
519557
};
520558

521559
if (ssts == 0) {
@@ -544,15 +582,12 @@ void sata_enable(uint32_t base)
544582
AHCI_DEBUG_PRINTF("AHCI port: Sending STOP ...\r\n");
545583

546584
/* Wait for CR to be cleared */
547-
count = 0;
548-
do {
549-
reg = mmio_read32(AHCI_PxCMD(base, i));
550-
if (count++ > 5) {
551-
AHCI_DEBUG_PRINTF("AHCI Error: Port did not clear CR!\r\n");
552-
break;
553-
}
554-
delay(1000);
555-
} while ((reg & AHCI_PORT_CMD_CR) != 0);
585+
r = sata_wait_until_clear(AHCI_PxCMD(base, i), AHCI_PORT_CMD_CR);
586+
if (r != 0) {
587+
wolfBoot_printf("AHCI Error: Port did not clear CR!\r\n");
588+
panic();
589+
}
590+
556591
AHCI_DEBUG_PRINTF("AHCI port: Sent STOP.\r\n");
557592

558593
AHCI_DEBUG_PRINTF("AHCI port: Disabling FIS ...\r\n");
@@ -566,15 +601,12 @@ void sata_enable(uint32_t base)
566601
}
567602

568603
/* Wait for FR to be cleared */
569-
count = 0;
570-
do {
571-
reg = mmio_read32(AHCI_PxCMD(base, i));
572-
if (count++ > 5) {
573-
wolfBoot_printf("AHCI Error: Port did not clear FR!\r\n");
574-
break;
575-
}
576-
delay(1000);
577-
} while ((reg & AHCI_PORT_CMD_FR) != 0);
604+
r = sata_wait_until_clear(AHCI_PxCMD(base, i), AHCI_PORT_CMD_FR);
605+
if (r != 0 ) {
606+
wolfBoot_printf("AHCI Error: Port did not clear FR!\r\n");
607+
panic();
608+
}
609+
578610
AHCI_DEBUG_PRINTF("AHCI port: FIS disabled.\r\n");
579611

580612
clb = (uint32_t)(uintptr_t)(ahci_hba_clb + i * HBA_CLB_SIZE);
@@ -594,9 +626,11 @@ void sata_enable(uint32_t base)
594626
memset((uint8_t*)(uintptr_t)fis, 0, HBA_FIS_SIZE);
595627

596628
/* Wait until CR is cleared */
597-
do {
598-
reg = mmio_read32(AHCI_PxCMD(base, i));
599-
} while(reg & AHCI_PORT_CMD_CR);
629+
r = sata_wait_until_clear(AHCI_PxCMD(base, i), AHCI_PORT_CMD_CR);
630+
if (r != 0) {
631+
wolfBoot_printf("AHCI error: CR clear error\r\n");
632+
panic();
633+
}
600634

601635
reg |= AHCI_PORT_CMD_FRE | AHCI_PORT_CMD_START;
602636
mmio_write32(AHCI_PxCMD(base, i), reg);
@@ -649,6 +683,8 @@ void sata_disable(uint32_t base)
649683
uint32_t ports_impl;
650684
uint32_t i, reg;
651685
volatile uint32_t count;
686+
int r;
687+
652688
AHCI_DEBUG_PRINTF("SATA: disabling sata controller at 0x%x\r\n", base);
653689

654690
ports_impl = mmio_read32(AHCI_HBA_PI(base));
@@ -674,15 +710,12 @@ void sata_disable(uint32_t base)
674710
}
675711

676712
/* Wait for CR to be cleared */
677-
count = 0;
678-
do {
679-
reg = mmio_read32(AHCI_PxCMD(base, i));
680-
if (count++ > 5) {
681-
break;
682-
}
683-
delay(1000);
684-
} while ((reg & AHCI_PORT_CMD_CR) != 0);
685-
713+
r = sata_wait_until_clear(AHCI_PxCMD(base, i), AHCI_PORT_CMD_CR);
714+
if (r != 0) {
715+
wolfBoot_printf("AHCI error: CR clear error\r\n");
716+
panic();
717+
}
718+
686719
/* Disable FIS RX */
687720
reg = mmio_read32(AHCI_PxCMD(base, i));
688721
if (reg & (AHCI_PORT_CMD_CR | AHCI_PORT_CMD_START)) {
@@ -693,24 +726,17 @@ void sata_disable(uint32_t base)
693726
}
694727

695728
/* Wait for FR to be cleared */
696-
count = 0;
697-
do {
698-
reg = mmio_read32(AHCI_PxCMD(base, i));
699-
if (count++ > 5) {
700-
wolfBoot_printf("AHCI Error: Port did not clear FR!\r\n");
701-
break;
702-
}
703-
delay(1000);
704-
} while ((reg & AHCI_PORT_CMD_FR) != 0);
729+
r = sata_wait_until_clear(AHCI_PxCMD(base, i), AHCI_PORT_CMD_FR);
730+
if (r != 0) {
731+
wolfBoot_printf("AHCI error: FR clear error\r\n");
732+
panic();
733+
}
705734
reg = mmio_read32(AHCI_PxCMD(base, i));
706735
mmio_write32(AHCI_PxCMD(base, i),
707736
reg & (~AHCI_PORT_CMD_ICC_ACTIVE));
708737

709738
}
710-
/* reg = mmio_read32(AHCI_HBA_GHC(base)); */
711-
/* mmio_write32(AHCI_HBA_GHC(base), reg & (~HBA_GHC_AE)); */
712-
/* mmio_or32(AHCI_HBA_GHC(base), HBA_GHC_HR | HBA_GHC_IE); */
713-
/* memset((void *)SATA_BASE, 0, 0x1000000); */
739+
714740
}
715741
#endif /* AHCI_H_ */
716742

0 commit comments

Comments
 (0)