@@ -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