bug-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH v3 2/4 gnumach] Add HPET timer for small accurate delays


From: Samuel Thibault
Subject: Re: [PATCH v3 2/4 gnumach] Add HPET timer for small accurate delays
Date: Thu, 8 Feb 2024 00:28:17 +0100
User-agent: NeoMutt/20170609 (1.8.3)

Applied, thanks!

Could you check with your mailer how to prevent it from using the
quoted-printable encoding? git am often has troubles applying your
patches, and I have to fix the patch by hand, it's really unconvenient.

Samuel

Damien Zammit, le mer. 07 févr. 2024 05:02:15 +0000, a ecrit:
> TESTED: This works in qemu correctly
> TESTED: This works on an AMD board with ACPI v2.0 correctly
> 
> ---
>  i386/i386/apic.c              | 89 +++++++++++++++++++++++++++++++++++
>  i386/i386/apic.h              |  5 ++
>  i386/i386at/acpi_parse_apic.c | 35 ++++++++++----
>  i386/i386at/acpi_parse_apic.h | 23 +++++++++
>  i386/i386at/model_dep.c       |  5 ++
>  5 files changed, 149 insertions(+), 8 deletions(-)
> 
> diff --git a/i386/i386/apic.c b/i386/i386/apic.c
> index feb49c85..0b5be50f 100644
> --- a/i386/i386/apic.c
> +++ b/i386/i386/apic.c
> @@ -26,6 +26,10 @@
>  #include <kern/printf.h>
>  #include <kern/kalloc.h>
>  
> +/*
> + * Period of HPET timer in nanoseconds
> + */
> +uint32_t hpet_period_nsec;
>  
>  /*
>   * This dummy structure is needed so that CPU_NUMBER can be called
> @@ -362,3 +366,88 @@ lapic_eoi(void)
>  {
>      lapic->eoi.r = 0;
>  }
> +
> +#define HPET32(x) *((volatile uint32_t *)((uint8_t *)hpet_addr + x))
> +#define HPET_CAP_PERIOD                      0x04
> +#define HPET_CFG                     0x10
> +# define HPET_CFG_ENABLE             (1 << 0)
> +# define HPET_LEGACY_ROUTE           (1 << 1)
> +#define HPET_COUNTER                 0xf0
> +#define HPET_T0_CFG                  0x100
> +# define HPET_T0_32BIT_MODE          (1 << 8)
> +# define HPET_T0_VAL_SET             (1 << 6)
> +# define HPET_T0_TYPE_PERIODIC               (1 << 3)
> +# define HPET_T0_INT_ENABLE          (1 << 2)
> +#define HPET_T0_COMPARATOR           0x108
> +
> +#define FSEC_PER_NSEC                        1000000
> +#define NSEC_PER_USEC                        1000
> +
> +/* This function sets up the HPET timer to be in
> + * 32 bit periodic mode and not generating any interrupts.
> + * The timer counts upwards and when it reaches 0xffffffff it
> + * wraps to zero.  The timer ticks at a constant rate in nanoseconds which
> + * is stored in hpet_period_nsec variable.
> + */
> +void
> +hpet_init(void)
> +{
> +    uint32_t period;
> +    uint32_t val;
> +
> +    assert(hpet_addr != 0);
> +
> +    /* Find out how often the HPET ticks in nanoseconds */
> +    period = HPET32(HPET_CAP_PERIOD);
> +    hpet_period_nsec = period / FSEC_PER_NSEC;
> +    printf("HPET ticks every %d nanoseconds\n", hpet_period_nsec);
> +
> +    /* Disable HPET and legacy interrupt routing mode */
> +    val = HPET32(HPET_CFG);
> +    val = val & ~(HPET_LEGACY_ROUTE | HPET_CFG_ENABLE);
> +    HPET32(HPET_CFG) = val;
> +
> +    /* Clear the counter */
> +    HPET32(HPET_COUNTER) = 0;
> +
> +    /* Set up 32 bit periodic timer with no interrupts */
> +    val = HPET32(HPET_T0_CFG);
> +    val = (val & ~HPET_T0_INT_ENABLE) | HPET_T0_32BIT_MODE | 
> HPET_T0_TYPE_PERIODIC | HPET_T0_VAL_SET;
> +    HPET32(HPET_T0_CFG) = val;
> +
> +    /* Set comparator to max */
> +    HPET32(HPET_T0_COMPARATOR) = 0xffffffff;
> +
> +    /* Enable the HPET */
> +    HPET32(HPET_CFG) |= HPET_CFG_ENABLE;
> +
> +    printf("HPET enabled\n");
> +}
> +
> +void
> +hpet_udelay(uint32_t us)
> +{
> +    uint32_t start, now;
> +    uint32_t max_delay_us = 0xffffffff / NSEC_PER_USEC;
> +
> +    if (us > max_delay_us) {
> +        printf("HPET ERROR: Delay too long, %d usec, truncating to %d 
> usec\n",
> +               us, max_delay_us);
> +        us = max_delay_us;
> +    }
> +
> +    /* Convert us to HPET ticks */
> +    us = (us * NSEC_PER_USEC) / hpet_period_nsec;
> +
> +    start = HPET32(HPET_COUNTER);
> +    do {
> +        now = HPET32(HPET_COUNTER);
> +    } while (now - start < us);
> +}
> +
> +void
> +hpet_mdelay(uint32_t ms)
> +{
> +    hpet_udelay(ms * 1000);
> +}
> +
> diff --git a/i386/i386/apic.h b/i386/i386/apic.h
> index 29387d9d..9eef0d8b 100644
> --- a/i386/i386/apic.h
> +++ b/i386/i386/apic.h
> @@ -252,10 +252,15 @@ void calibrate_lapic_timer(void);
>  void ioapic_toggle(int pin, int mask);
>  void ioapic_configure(void);
>  
> +void hpet_init(void);
> +void hpet_udelay(uint32_t us);
> +void hpet_mdelay(uint32_t ms);
> +
>  extern int timer_pin;
>  extern void intnull(int unit);
>  extern volatile ApicLocalUnit* lapic;
>  extern int cpu_id_lut[];
> +extern uint32_t *hpet_addr;
>  
>  #endif
>  
> diff --git a/i386/i386at/acpi_parse_apic.c b/i386/i386at/acpi_parse_apic.c
> index dcd5da89..1cfc1791 100644
> --- a/i386/i386at/acpi_parse_apic.c
> +++ b/i386/i386at/acpi_parse_apic.c
> @@ -34,6 +34,7 @@
>  
>  static struct acpi_apic *apic_madt = NULL;
>  unsigned lapic_addr;
> +uint32_t *hpet_addr;
>  
>  /*
>   * acpi_print_info: shows by screen the ACPI's rsdp and rsdt virtual address
> @@ -292,28 +293,37 @@ acpi_get_xsdt(phys_addr_t rsdp_phys, int* acpi_xsdt_n)
>   * and the number of entries of RSDT table.
>   *
>   * Returns a reference to APIC/MADT table if success, NULL if failure.
> + * Also sets hpet_addr to base address of HPET.
>   */
>  static struct acpi_apic*
>  acpi_get_apic(struct acpi_rsdt *rsdt, int acpi_rsdt_n)
>  {
>      struct acpi_dhdr *descr_header;
> +    struct acpi_apic *madt = NULL;
>      int check_signature;
> +    uint64_t map_addr;
>  
>      /* Search APIC entries in rsdt table. */
>      for (int i = 0; i < acpi_rsdt_n; i++) {
>          descr_header = (struct acpi_dhdr*) 
> kmem_map_aligned_table(rsdt->entry[i], sizeof(struct acpi_dhdr),
>                                                                    
> VM_PROT_READ);
>  
> -        /* Check if the entry contains an APIC. */
> +        /* Check if the entry is a MADT */
>          check_signature = acpi_check_signature(descr_header->signature, 
> ACPI_APIC_SIG, 4*sizeof(uint8_t));
> +        if (check_signature == ACPI_SUCCESS)
> +            madt = (struct acpi_apic*) descr_header;
>  
> +        /* Check if the entry is a HPET */
> +        check_signature = acpi_check_signature(descr_header->signature, 
> ACPI_HPET_SIG, 4*sizeof(uint8_t));
>          if (check_signature == ACPI_SUCCESS) {
> -            /* If yes, return the APIC. */
> -            return (struct acpi_apic*) descr_header;
> +            map_addr = ((struct acpi_hpet *)descr_header)->address.addr64;
> +            assert (map_addr != 0);
> +            hpet_addr = (uint32_t *)kmem_map_aligned_table(map_addr, 1024, 
> VM_PROT_READ | VM_PROT_WRITE);
> +            printf("HPET at physical address 0x%llx\n", map_addr);
>          }
>      }
>  
> -    return NULL;
> +    return madt;
>  }
>  
>  /*
> @@ -323,28 +333,37 @@ acpi_get_apic(struct acpi_rsdt *rsdt, int acpi_rsdt_n)
>   * and the number of entries of XSDT table.
>   *
>   * Returns a reference to APIC/MADT table if success, NULL if failure.
> + * Also sets hpet_addr to base address of HPET.
>   */
>  static struct acpi_apic*
>  acpi_get_apic2(struct acpi_xsdt *xsdt, int acpi_xsdt_n)
>  {
>      struct acpi_dhdr *descr_header;
> +    struct acpi_apic *madt = NULL;
>      int check_signature;
> +    uint64_t map_addr;
>  
>      /* Search APIC entries in rsdt table. */
>      for (int i = 0; i < acpi_xsdt_n; i++) {
>          descr_header = (struct acpi_dhdr*) 
> kmem_map_aligned_table(xsdt->entry[i], sizeof(struct acpi_dhdr),
>                                                                    
> VM_PROT_READ);
>  
> -        /* Check if the entry contains an APIC. */
> +        /* Check if the entry is an APIC. */
>          check_signature = acpi_check_signature(descr_header->signature, 
> ACPI_APIC_SIG, 4*sizeof(uint8_t));
> +        if (check_signature == ACPI_SUCCESS)
> +            madt = (struct acpi_apic *)descr_header;
>  
> +        /* Check if the entry is a HPET. */
> +        check_signature = acpi_check_signature(descr_header->signature, 
> ACPI_HPET_SIG, 4*sizeof(uint8_t));
>          if (check_signature == ACPI_SUCCESS) {
> -            /* If yes, return the APIC. */
> -            return (struct acpi_apic*) descr_header;
> +            map_addr = ((struct acpi_hpet *)descr_header)->address.addr64;
> +            assert (map_addr != 0);
> +            hpet_addr = (uint32_t *)kmem_map_aligned_table(map_addr, 1024, 
> VM_PROT_READ | VM_PROT_WRITE);
> +            printf("HPET at physical address 0x%llx\n", map_addr);
>          }
>      }
>  
> -    return NULL;
> +    return madt;
>  }
>  
>  /*
> diff --git a/i386/i386at/acpi_parse_apic.h b/i386/i386at/acpi_parse_apic.h
> index df36bb31..85e01170 100644
> --- a/i386/i386at/acpi_parse_apic.h
> +++ b/i386/i386at/acpi_parse_apic.h
> @@ -91,6 +91,14 @@ struct acpi_xsdt {
>      uint64_t                         entry[0];
>  } __attribute__((__packed__));
>  
> +struct acpi_address {
> +    uint8_t  is_io;
> +    uint8_t  reg_width;
> +    uint8_t  reg_offset;
> +    uint8_t  reserved;
> +    uint64_t addr64;
> +} __attribute__((__packed__));
> +
>  /* APIC table signature. */
>  #define ACPI_APIC_SIG "APIC"
>  
> @@ -170,6 +178,21 @@ struct acpi_apic_irq_override {
>      uint16_t    flags;
>  } __attribute__((__packed__));
>  
> +
> +#define ACPI_HPET_SIG "HPET"
> +
> +/*
> + * HPET High Precision Event Timer structure
> + */
> +struct acpi_hpet {
> +    struct acpi_dhdr header;
> +    uint32_t id;
> +    struct acpi_address      address;
> +    uint8_t  sequence;
> +    uint16_t minimum_tick;
> +    uint8_t  flags;
> +} __attribute__((__packed__));
> +
>  int acpi_apic_init(void);
>  void acpi_print_info(phys_addr_t rsdp, void *rsdt, int acpi_rsdt_n);
>  
> diff --git a/i386/i386at/model_dep.c b/i386/i386at/model_dep.c
> index 173b99f5..b5f56c7d 100644
> --- a/i386/i386at/model_dep.c
> +++ b/i386/i386at/model_dep.c
> @@ -229,6 +229,11 @@ void machine_init(void)
>        */
>       gdt_descr_tmp.linear_base += apboot_addr;
>       apboot_jmp_offset += apboot_addr;
> +
> +     /*
> +      * Initialize the HPET
> +      */
> +     hpet_init();
>  #endif
>  }
>  
> -- 
> 2.43.0
> 
> 
> 

-- 
Samuel
---
Pour une évaluation indépendante, transparente et rigoureuse !
Je soutiens la Commission d'Évaluation de l'Inria.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]