1. May 21, 2023
    • Andrew Jones's avatar
      lib: sbi: pmu: Remove unnecessary probe function · 042f0c3e
      Andrew Jones authored
      
      
      The absence of a probe implementation means that the extension is
      always available. Remove the implementation for the PMU extension,
      which does no checking, and indeed even has a comment saying it's
      always available.
      
      Signed-off-by: default avatarAndrew Jones <ajones@ventanamicro.com>
      Reviewed-by: default avatarAnup Patel <anup@brainfault.org>
      042f0c3e
    • Andrew Jones's avatar
      lib: sbi: Narrow vendor extension range · e307ba7d
      Andrew Jones authored
      
      
      The vendor extension ID range is large, but at runtime at most
      a single ID will be available. Narrow the range in the
      register_extensions callback. After narrowing, we no longer
      need to check that the extension ID is correct in the other
      callbacks, as those callbacks will never be invoked with
      anything other than the single ID.
      
      Signed-off-by: default avatarAndrew Jones <ajones@ventanamicro.com>
      Reviewed-by: default avatarAnup Patel <anup@brainfault.org>
      e307ba7d
    • Andrew Jones's avatar
      lib: sbi: Introduce register_extensions extension callback · f58c1409
      Andrew Jones authored
      
      
      Rather than registering all extensions on their behalf in
      sbi_ecall_init(), introduce another extension callback and
      invoke that instead. For now, implement each callback by
      simply registering the extension, which means this patch
      has no intended functional change. In later patches, extension
      callbacks will be modified to choose when to register and to
      possibly narrow the extension ID range prior to registering.
      When an extension range needs to remove IDs, leaving gaps, then
      multiple invocations of sbi_ecall_register_extension() may be
      used. In summary, later patches for current extensions and the
      introductions of future extensions will use the new callback to
      ensure that only valid extension IDs from the initial range,
      which are also available, will be registered.
      
      Signed-off-by: default avatarAndrew Jones <ajones@ventanamicro.com>
      Reviewed-by: default avatarAnup Patel <anup@brainfault.org>
      f58c1409
  2. May 11, 2023
  3. Apr 20, 2023
  4. Apr 17, 2023
  5. Apr 14, 2023
  6. Apr 13, 2023
  7. Apr 07, 2023
  8. Apr 06, 2023
  9. Mar 10, 2023
    • Evgenii Shatokhin's avatar
      lib: sbi: Clear IPIs before init_warm_startup in non-boot harts · c6a092cd
      Evgenii Shatokhin authored
      Since commit 50d4fde1
      
       ("lib: Remove redundant sbi_platform_ipi_clear()
      calls"), the IPI sent from the boot hart in wake_coldboot_harts() is not
      cleared in the secondary harts until they reach sbi_ipi_init(). However,
      sbi_hsm_init() and sbi_hsm_hart_wait() are called earlier, so a secondary
      hart might enter sbi_hsm_hart_wait() with an already pending IPI.
      
      sbi_hsm_hart_wait() makes sure the hart leaves the loop only when it is
      actually ready, so a pending unrelated IPI should not cause safety issues.
      However, it might be inefficient on certain hardware, because it prevents
      "wfi" from stalling the hart even if the hardware supports this, making the
      hart needlessly spin in a "busy-wait" loop.
      
      This behaviour can be observed, for example, in a QEMU VM (QEMU 7.2.0) with
      "-machine virt" running a Linux guest. Inserting delays in
      sbi_hsm_hart_start() allows reproducing the issue more reliably.
      
      The comment in wait_for_coldboot() suggests that the initial IPI is needed
      in the warm resume path, so let us clear it before init_warm_startup()
      only.
      
      To do this, sbi_ipi_raw_clear() was created similar to sbi_ipi_raw_send().
      
      Signed-off-by: default avatarEvgenii Shatokhin <e.shatokhin@yadro.com>
      Reviewed-by: default avatarAnup Patel <anup@brainfault.org>
      c6a092cd
    • Evgenii Shatokhin's avatar
      lib: sbi: Set the state of a hart to START_PENDING after the hart is ready · e8e9ed37
      Evgenii Shatokhin authored
      
      
      When a boot hart executes sbi_hsm_hart_start() to start a secondary hart,
      next_arg1, next_addr and next_mode for the latter are stored in the scratch
      area after the state has been set to SBI_HSM_STATE_START_PENDING.
      
      The secondary hart waits in the loop with wfi() in sbi_hsm_hart_wait() at
      that time. However, "wfi" instruction is not guaranteed to wait for an
      interrupt to be received by the hart, it is just a hint for the CPU.
      According to RISC-V Privileged Architectures spec. v20211203, even an
      implementation of "wfi" as "nop" is legal.
      
      So, the secondary might leave the loop in sbi_hsm_hart_wait() as soon as
      its state has been set to SBI_HSM_STATE_START_PENDING, even if it got no
      IPI or it got an IPI unrelated to sbi_hsm_hart_start(). This could lead to
      the following race condition when booting Linux, for example:
      
        Boot hart (#0)                        Secondary hart (#1)
        runs Linux startup code               waits in sbi_hsm_hart_wait()
      
        sbi_ecall(SBI_EXT_HSM,
                  SBI_EXT_HSM_HART_START,
                  ...)
        enters sbi_hsm_hart_start()
        sets state of hart #1 to START_PENDING
                                              leaves sbi_hsm_hart_wait()
                                              runs to the end of init_warmboot()
                                              returns to scratch->next_addr
                                              (next_addr can be garbage here)
      
        sets next_addr, etc. for hart #1
        (no good: hart #1 has already left)
      
        sends IPI to hart #1
        (no good either)
      
      If this happens, the secondary hart jumps to a wrong next_addr at the end
      of init_warmboot(), which leads to a system hang or crash.
      
      To reproduce the issue more reliably, one could add a delay in
      sbi_hsm_hart_start() after setting the hart's state but before sending
      IPI to that hart:
      
          hstate = atomic_cmpxchg(&hdata->state, SBI_HSM_STATE_STOPPED,
                                  SBI_HSM_STATE_START_PENDING);
          ...
        + sbi_timer_mdelay(10);
          init_count = sbi_init_count(hartid);
          rscratch->next_arg1 = arg1;
          rscratch->next_addr = saddr;
      
      The issue can be reproduced, for example, in a QEMU VM with '-machine virt'
      and 2 or more CPUs, with Linux as the guest OS.
      
      This patch moves writing of next_arg1, next_addr and next_mode for the
      secondary hart before setting its state to SBI_HSM_STATE_START_PENDING.
      
      In theory, it is possible that two or more harts enter sbi_hsm_hart_start()
      for the same target hart simultaneously. To make sure the current hart has
      exclusive access to the scratch area of the target hart at that point, a
      per-hart 'start_ticket' is used. It is initially 0. The current hart tries
      to acquire the ticket first (set it to 1) at the beginning of
      sbi_hsm_hart_start() and only proceeds if it has successfully acquired it.
      
      The target hart reads next_addr, etc., and then the releases the ticket
      (sets it to 0) before calling sbi_hart_switch_mode(). This way, even if
      some other hart manages to enter sbi_hsm_hart_start() after the ticket has
      been released but before the target hart jumps to next_addr, it will not
      cause problems.
      
      atomic_cmpxchg() already has "acquire" semantics, among other things, so
      no additional barriers are needed in hsm_start_ticket_acquire(). No hart
      can perform or observe the update of *rscratch before setting of
      'start_ticket' to 1.
      
      atomic_write() only imposes ordering of writes, so an explicit barrier is
      needed in hsm_start_ticket_release() to ensure its "release" semantics.
      This guarantees that reads of scratch->next_addr, etc., in
      sbi_hsm_hart_start_finish() cannot happen after 'start_ticket' has been
      released.
      
      Signed-off-by: default avatarEvgenii Shatokhin <e.shatokhin@yadro.com>
      Reviewed-by: default avatarAnup Patel <anup@brainfault.org>
      e8e9ed37
    • Evgenii Shatokhin's avatar
      lib: sbi: Refactor the calls to sbi_hart_switch_mode() · d56049e2
      Evgenii Shatokhin authored
      
      
      Move them into sbi_hsm_hart_start_finish() and sbi_hsm_hart_resume_finish()
      to make them easier to manage.
      
      This will be used by subsequent patches.
      
      Suggested-by: default avatarAnup Patel <anup@brainfault.org>
      Signed-off-by: default avatarEvgenii Shatokhin <e.shatokhin@yadro.com>
      Reviewed-by: default avatarAnup Patel <anup@brainfault.org>
      d56049e2
    • Mayuresh Chitale's avatar
      lib: sbi_pmu: Add hartid parameter PMU device ops · c631a7da
      Mayuresh Chitale authored
      
      
      Platform specific firmware event handler may leverage the hartid to program
      per hart specific registers for a given counter.
      
      Signed-off-by: default avatarMayuresh Chitale <mchitale@ventanamicro.com>
      Reviewed-by: default avatarAtish Patra <atishp@rivosinc.com>
      Reviewed-by: default avatarAnup Patel <anup@brainfault.org>
      c631a7da
    • Mayuresh Chitale's avatar
      lib: sbi_pmu: Introduce fw_counter_write_value API · 57d3aa3b
      Mayuresh Chitale authored
      
      
      Add fw_counter_write_value API for platform specific firmware events
      which separates setting the counter's initial value from starting the
      counter. This is required so that the fw_event_data array can be reused
      to save the event data received.
      
      Signed-off-by: default avatarMayuresh Chitale <mchitale@ventanamicro.com>
      Reviewed-by: default avatarAnup Patel <anup@brainfault.org>
      57d3aa3b
    • Mayuresh Chitale's avatar
      lib: sbi_pmu: Use dedicated event code for platform firmware events · 641d2e9f
      Mayuresh Chitale authored
      
      
      For all platform specific firmware event operations use the dedicated
      event code (0xFFFF) when matching against the input firmware event.
      Furthermore save the real platform specific firmware event code received as
      the event data for future use.
      
      Signed-off-by: default avatarMayuresh Chitale <mchitale@ventanamicro.com>
      Reviewed-by: default avatarAnup Patel <anup@brainfault.org>
      641d2e9f
    • Mayuresh Chitale's avatar
      lib: sbi_pmu: Update sbi_pmu dev ops · b51ddffc
      Mayuresh Chitale authored
      
      
      Update fw_event_validate_code, fw_counter_match_code and fw_counter_start
      ops which used a 32 bit event code to use the 64 bit event data instead.
      
      Signed-off-by: default avatarMayuresh Chitale <mchitale@ventanamicro.com>
      Reviewed-by: default avatarAnup Patel <anup@brainfault.org>
      b51ddffc
    • Mayuresh Chitale's avatar
      lib: sbi_pmu: Rename fw_counter_value · 548e4b4b
      Mayuresh Chitale authored
      
      
      Rename and reuse fw_counter_value array to save both the counter values
      for the SBI firmware events and event data for the SBI platform specific
      firmware events.
      
      Signed-off-by: default avatarMayuresh Chitale <mchitale@ventanamicro.com>
      Reviewed-by: default avatarAnup Patel <anup@brainfault.org>
      Reviewed-by: default avatarAndrew Jones <ajones@ventanamicro.com>
      548e4b4b
    • Mayuresh Chitale's avatar
      lib: sbi_pmu: Reserve space for implementation specific firmware events · 60c358e6
      Mayuresh Chitale authored
      
      
      We reserve space for SBI implementation specific custom firmware
      events which can be used by M-mode firmwares and HS-mode hypervisors
      for their own use. This reserved space is intentionally large to
      ensure that SBI implementation has enough space to accommodate
      platform specific firmware events as well.
      
      Signed-off-by: default avatarMayuresh Chitale <mchitale@ventanamicro.com>
      Reviewed-by: default avatarAtish Patra <atishp@rivosinc.com>
      Reviewed-by: default avatarAnup Patel <anup@brainfault.org>
      60c358e6
    • Mayuresh Chitale's avatar
      lib: sbi_pmu: Implement sbi_pmu_counter_fw_read_hi · 51951d9e
      Mayuresh Chitale authored
      
      
      To support 64 bit firmware counters on RV32 systems, we implement
      sbi_pmu_counter_fw_read_hi() which returns the upper 32 bits of
      the firmware counter value. On RV64 (or higher) systems, this
      function will always return zero.
      
      Signed-off-by: default avatarMayuresh Chitale <mchitale@ventanamicro.com>
      Reviewed-by: default avatarAtish Patra <atishp@rivosinc.com>
      Reviewed-by: default avatarAnup Patel <anup@brainfault.org>
      51951d9e
    • Mayuresh Chitale's avatar
      lib: sbi_pmu: add callback for counter width · 1fe8dc99
      Mayuresh Chitale authored
      
      
      This patch adds a callback to fetch the number of bits implemented for a
      custom firmware counter. If the callback fails or is not implemented then
      width defaults to 63.
      
      Signed-off-by: default avatarMayuresh Chitale <mchitale@ventanamicro.com>
      Reviewed-by: default avatarAtish Patra <atishp@rivosinc.com>
      Reviewed-by: default avatarAnup Patel <anup@brainfault.org>
      1fe8dc99
  10. Mar 09, 2023