In addition to the clock throttling reason, user should be able to obtain also the start time and the duration of the throttling event.
Unified · Split
| @@ -455,6 +455,7 @@ static int device_early_init(struct hl_device *hdev) · 454 unmodified lines | |||
| 455 | INIT_LIST_HEAD(&hdev->fpriv_list); | 455 | INIT_LIST_HEAD(&hdev->fpriv_list); |
| 456 | mutex_init(&hdev->fpriv_list_lock); | 456 | mutex_init(&hdev->fpriv_list_lock); |
| 457 | atomic_set(&hdev->in_reset, 0); | 457 | atomic_set(&hdev->in_reset, 0); |
| 458 | mutex_init(&hdev->clk_throttling.lock); | ||
| 458 | 459 | ||
| 459 | return 0; | 460 | return 0; |
| 460 | 461 | ||
| @@ -495,6 +496,8 @@ static void device_early_fini(struct hl_device *hdev) · 34 unmodified lines | |||
| 495 | 496 | ||
| 496 | mutex_destroy(&hdev->fpriv_list_lock); | 497 | mutex_destroy(&hdev->fpriv_list_lock); |
| 497 | 498 | ||
| 499 | mutex_destroy(&hdev->clk_throttling.lock); | ||
| 500 | |||
| 498 | hl_cb_mgr_fini(hdev, &hdev->kernel_cb_mgr); | 501 | hl_cb_mgr_fini(hdev, &hdev->kernel_cb_mgr); |
| 499 | 502 | ||
| 500 | kfree(hdev->hl_chip_info); | 503 | kfree(hdev->hl_chip_info); |
| @@ -2378,6 +2378,32 @@ struct multi_cs_data { · 2377 unmodified lines | |||
| 2378 | u8 update_ts; | 2378 | u8 update_ts; |
| 2379 | }; | 2379 | }; |
| 2380 | 2380 | ||
| 2381 | /** | ||
| 2382 | * struct hl_clk_throttle_timestamp - current/last clock throttling timestamp | ||
| 2383 | * @start: timestamp taken when 'start' event is received in driver | ||
| 2384 | * @end: timestamp taken when 'end' event is received in driver | ||
| 2385 | */ | ||
| 2386 | struct hl_clk_throttle_timestamp { | ||
| 2387 | ktime_t start; | ||
| 2388 | ktime_t end; | ||
| 2389 | }; | ||
| 2390 | |||
| 2391 | /** | ||
| 2392 | * struct hl_clk_throttle - keeps current/last clock throttling timestamps | ||
| 2393 | * @timestamp: timestamp taken by driver and firmware, index 0 refers to POWER | ||
| 2394 | * index 1 refers to THERMAL | ||
| 2395 | * @lock: protects this structure as it can be accessed from both event queue | ||
| 2396 | * context and info_ioctl context | ||
| 2397 | * @current_reason: bitmask represents the current clk throttling reasons | ||
| 2398 | * @aggregated_reason: bitmask represents aggregated clk throttling reasons since driver load | ||
| 2399 | */ | ||
| 2400 | struct hl_clk_throttle { | ||
| 2401 | struct hl_clk_throttle_timestamp timestamp[HL_CLK_THROTTLE_TYPE_MAX]; | ||
| 2402 | struct mutex lock; | ||
| 2403 | u32 current_reason; | ||
| 2404 | u32 aggregated_reason; | ||
| 2405 | }; | ||
| 2406 | |||
| 2381 | /** | 2407 | /** |
| 2382 | * struct hl_device - habanalabs device structure. | 2408 | * struct hl_device - habanalabs device structure. |
| 2383 | * @pdev: pointer to PCI device, can be NULL in case of simulator device. | 2409 | * @pdev: pointer to PCI device, can be NULL in case of simulator device. |
| @@ -2445,6 +2471,7 @@ struct multi_cs_data { · 61 unmodified lines | |||
| 2445 | * @pci_mem_region: array of memory regions in the PCI | 2471 | * @pci_mem_region: array of memory regions in the PCI |
| 2446 | * @state_dump_specs: constants and dictionaries needed to dump system state. | 2472 | * @state_dump_specs: constants and dictionaries needed to dump system state. |
| 2447 | * @multi_cs_completion: array of multi-CS completion. | 2473 | * @multi_cs_completion: array of multi-CS completion. |
| 2474 | * @clk_throttling: holds information about current/previous clock throttling events | ||
| 2448 | * @dram_used_mem: current DRAM memory consumption. | 2475 | * @dram_used_mem: current DRAM memory consumption. |
| 2449 | * @timeout_jiffies: device CS timeout value. | 2476 | * @timeout_jiffies: device CS timeout value. |
| 2450 | * @max_power: the max power of the device, as configured by the sysadmin. This | 2477 | * @max_power: the max power of the device, as configured by the sysadmin. This |
| @@ -2474,7 +2501,6 @@ struct multi_cs_data { · 23 unmodified lines | |||
| 2474 | * @high_pll: high PLL profile frequency. | 2501 | * @high_pll: high PLL profile frequency. |
| 2475 | * @soft_reset_cnt: number of soft reset since the driver was loaded. | 2502 | * @soft_reset_cnt: number of soft reset since the driver was loaded. |
| 2476 | * @hard_reset_cnt: number of hard reset since the driver was loaded. | 2503 | * @hard_reset_cnt: number of hard reset since the driver was loaded. |
| 2477 | * @clk_throttling_reason: bitmask represents the current clk throttling reasons | ||
| 2478 | * @id: device minor. | 2504 | * @id: device minor. |
| 2479 | * @id_control: minor of the control device | 2505 | * @id_control: minor of the control device |
| 2480 | * @cpu_pci_msb_addr: 50-bit extension bits for the device CPU's 40-bit | 2506 | * @cpu_pci_msb_addr: 50-bit extension bits for the device CPU's 40-bit |
| @@ -2604,6 +2630,8 @@ struct hl_device { · 123 unmodified lines | |||
| 2604 | 2630 | ||
| 2605 | struct multi_cs_completion multi_cs_completion[ | 2631 | struct multi_cs_completion multi_cs_completion[ |
| 2606 | MULTI_CS_MAX_USER_CTX]; | 2632 | MULTI_CS_MAX_USER_CTX]; |
| 2633 | struct hl_clk_throttle clk_throttling; | ||
| 2634 | |||
| 2607 | u32 *stream_master_qid_arr; | 2635 | u32 *stream_master_qid_arr; |
| 2608 | atomic64_t dram_used_mem; | 2636 | atomic64_t dram_used_mem; |
| 2609 | u64 timeout_jiffies; | 2637 | u64 timeout_jiffies; |
| @@ -2622,7 +2650,6 @@ struct hl_device { · 12 unmodified lines | |||
| 2622 | u32 high_pll; | 2650 | u32 high_pll; |
| 2623 | u32 soft_reset_cnt; | 2651 | u32 soft_reset_cnt; |
| 2624 | u32 hard_reset_cnt; | 2652 | u32 hard_reset_cnt; |
| 2625 | u32 clk_throttling_reason; | ||
| 2626 | u16 id; | 2653 | u16 id; |
| 2627 | u16 id_control; | 2654 | u16 id_control; |
| 2628 | u16 cpu_pci_msb_addr; | 2655 | u16 cpu_pci_msb_addr; |
| @@ -313,15 +313,38 @@ static int pci_counters_info(struct hl_fpriv *hpriv, struct hl_info_args *args) · 312 unmodified lines | |||
| 313 | 313 | ||
| 314 | static int clk_throttle_info(struct hl_fpriv *hpriv, struct hl_info_args *args) | 314 | static int clk_throttle_info(struct hl_fpriv *hpriv, struct hl_info_args *args) |
| 315 | { | 315 | { |
| 316 | void __user *out = (void __user *) (uintptr_t) args->return_pointer; | ||
| 316 | struct hl_device *hdev = hpriv->hdev; | 317 | struct hl_device *hdev = hpriv->hdev; |
| 317 | struct hl_info_clk_throttle clk_throttle = {0}; | 318 | struct hl_info_clk_throttle clk_throttle = {0}; |
| 319 | ktime_t end_time, zero_time = ktime_set(0, 0); | ||
| 318 | u32 max_size = args->return_size; | 320 | u32 max_size = args->return_size; |
| 319 | void __user *out = (void __user *) (uintptr_t) args->return_pointer; | 321 | int i; |
| 320 | 322 | ||
| 321 | if ((!max_size) || (!out)) | 323 | if ((!max_size) || (!out)) |
| 322 | return -EINVAL; | 324 | return -EINVAL; |
| 323 | 325 | ||
| 324 | clk_throttle.clk_throttling_reason = hdev->clk_throttling_reason; | 326 | mutex_lock(&hdev->clk_throttling.lock); |
| 327 | |||
| 328 | clk_throttle.clk_throttling_reason = hdev->clk_throttling.current_reason; | ||
| 329 | |||
| 330 | for (i = 0 ; i < HL_CLK_THROTTLE_TYPE_MAX ; i++) { | ||
| 331 | if (!(hdev->clk_throttling.aggregated_reason & BIT(i))) | ||
| 332 | continue; | ||
| 333 | |||
| 334 | clk_throttle.clk_throttling_timestamp_us[i] = | ||
| 335 | ktime_to_us(hdev->clk_throttling.timestamp[i].start); | ||
| 336 | |||
| 337 | if (ktime_compare(hdev->clk_throttling.timestamp[i].end, zero_time)) | ||
| 338 | end_time = ktime_get(); | ||
| 339 | else | ||
| 340 | end_time = hdev->clk_throttling.timestamp[i].end; | ||
| 341 | |||
| 342 | clk_throttle.clk_throttling_duration_ns[i] = | ||
| 343 | ktime_to_ns(ktime_sub(end_time, | ||
| 344 | hdev->clk_throttling.timestamp[i].start)); | ||
| 345 | |||
| 346 | } | ||
| 347 | mutex_unlock(&hdev->clk_throttling.lock); | ||
| 325 | 348 | ||
| 326 | return copy_to_user(out, &clk_throttle, | 349 | return copy_to_user(out, &clk_throttle, |
| 327 | min((size_t) max_size, sizeof(clk_throttle))) ? -EFAULT : 0; | 350 | min((size_t) max_size, sizeof(clk_throttle))) ? -EFAULT : 0; |
| @@ -7925,27 +7925,39 @@ static int tpc_krn_event_to_tpc_id(u16 tpc_dec_event_type) · 7924 unmodified lines | |||
| 7925 | static void gaudi_print_clk_change_info(struct hl_device *hdev, | 7925 | static void gaudi_print_clk_change_info(struct hl_device *hdev, |
| 7926 | u16 event_type) | 7926 | u16 event_type) |
| 7927 | { | 7927 | { |
| 7928 | ktime_t zero_time = ktime_set(0, 0); | ||
| 7929 | |||
| 7930 | mutex_lock(&hdev->clk_throttling.lock); | ||
| 7931 | |||
| 7928 | switch (event_type) { | 7932 | switch (event_type) { |
| 7929 | case GAUDI_EVENT_FIX_POWER_ENV_S: | 7933 | case GAUDI_EVENT_FIX_POWER_ENV_S: |
| 7930 | hdev->clk_throttling_reason |= HL_CLK_THROTTLE_POWER; | 7934 | hdev->clk_throttling.current_reason |= HL_CLK_THROTTLE_POWER; |
| 7935 | hdev->clk_throttling.aggregated_reason |= HL_CLK_THROTTLE_POWER; | ||
| 7936 | hdev->clk_throttling.timestamp[HL_CLK_THROTTLE_TYPE_POWER].start = ktime_get(); | ||
| 7937 | hdev->clk_throttling.timestamp[HL_CLK_THROTTLE_TYPE_POWER].end = zero_time; | ||
| 7931 | dev_info_ratelimited(hdev->dev, | 7938 | dev_info_ratelimited(hdev->dev, |
| 7932 | "Clock throttling due to power consumption\n"); | 7939 | "Clock throttling due to power consumption\n"); |
| 7933 | break; | 7940 | break; |
| 7934 | 7941 | ||
| 7935 | case GAUDI_EVENT_FIX_POWER_ENV_E: | 7942 | case GAUDI_EVENT_FIX_POWER_ENV_E: |
| 7936 | hdev->clk_throttling_reason &= ~HL_CLK_THROTTLE_POWER; | 7943 | hdev->clk_throttling.current_reason &= ~HL_CLK_THROTTLE_POWER; |
| 7944 | hdev->clk_throttling.timestamp[HL_CLK_THROTTLE_TYPE_POWER].end = ktime_get(); | ||
| 7937 | dev_info_ratelimited(hdev->dev, | 7945 | dev_info_ratelimited(hdev->dev, |
| 7938 | "Power envelop is safe, back to optimal clock\n"); | 7946 | "Power envelop is safe, back to optimal clock\n"); |
| 7939 | break; | 7947 | break; |
| 7940 | 7948 | ||
| 7941 | case GAUDI_EVENT_FIX_THERMAL_ENV_S: | 7949 | case GAUDI_EVENT_FIX_THERMAL_ENV_S: |
| 7942 | hdev->clk_throttling_reason |= HL_CLK_THROTTLE_THERMAL; | 7950 | hdev->clk_throttling.current_reason |= HL_CLK_THROTTLE_THERMAL; |
| 7951 | hdev->clk_throttling.aggregated_reason |= HL_CLK_THROTTLE_THERMAL; | ||
| 7952 | hdev->clk_throttling.timestamp[HL_CLK_THROTTLE_TYPE_THERMAL].start = ktime_get(); | ||
| 7953 | hdev->clk_throttling.timestamp[HL_CLK_THROTTLE_TYPE_THERMAL].end = zero_time; | ||
| 7943 | dev_info_ratelimited(hdev->dev, | 7954 | dev_info_ratelimited(hdev->dev, |
| 7944 | "Clock throttling due to overheating\n"); | 7955 | "Clock throttling due to overheating\n"); |
| 7945 | break; | 7956 | break; |
| 7946 | 7957 | ||
| 7947 | case GAUDI_EVENT_FIX_THERMAL_ENV_E: | 7958 | case GAUDI_EVENT_FIX_THERMAL_ENV_E: |
| 7948 | hdev->clk_throttling_reason &= ~HL_CLK_THROTTLE_THERMAL; | 7959 | hdev->clk_throttling.current_reason &= ~HL_CLK_THROTTLE_THERMAL; |
| 7960 | hdev->clk_throttling.timestamp[HL_CLK_THROTTLE_TYPE_THERMAL].end = ktime_get(); | ||
| 7949 | dev_info_ratelimited(hdev->dev, | 7961 | dev_info_ratelimited(hdev->dev, |
| 7950 | "Thermal envelop is safe, back to optimal clock\n"); | 7962 | "Thermal envelop is safe, back to optimal clock\n"); |
| 7951 | break; | 7963 | break; |
| @@ -7955,6 +7967,8 @@ static void gaudi_print_clk_change_info(struct hl_device *hdev, · 3 unmodified lines | |||
| 7955 | event_type); | 7967 | event_type); |
| 7956 | break; | 7968 | break; |
| 7957 | } | 7969 | } |
| 7970 | |||
| 7971 | mutex_unlock(&hdev->clk_throttling.lock); | ||
| 7958 | } | 7972 | } |
| 7959 | 7973 | ||
| 7960 | static void gaudi_handle_eqe(struct hl_device *hdev, | 7974 | static void gaudi_handle_eqe(struct hl_device *hdev, |
| @@ -4768,24 +4768,39 @@ static int goya_unmask_irq(struct hl_device *hdev, u16 event_type) · 4767 unmodified lines | |||
| 4768 | 4768 | ||
| 4769 | static void goya_print_clk_change_info(struct hl_device *hdev, u16 event_type) | 4769 | static void goya_print_clk_change_info(struct hl_device *hdev, u16 event_type) |
| 4770 | { | 4770 | { |
| 4771 | ktime_t zero_time = ktime_set(0, 0); | ||
| 4772 | |||
| 4773 | mutex_lock(&hdev->clk_throttling.lock); | ||
| 4774 | |||
| 4771 | switch (event_type) { | 4775 | switch (event_type) { |
| 4772 | case GOYA_ASYNC_EVENT_ID_FIX_POWER_ENV_S: | 4776 | case GOYA_ASYNC_EVENT_ID_FIX_POWER_ENV_S: |
| 4773 | hdev->clk_throttling_reason |= HL_CLK_THROTTLE_POWER; | 4777 | hdev->clk_throttling.current_reason |= HL_CLK_THROTTLE_POWER; |
| 4778 | hdev->clk_throttling.aggregated_reason |= HL_CLK_THROTTLE_POWER; | ||
| 4779 | hdev->clk_throttling.timestamp[HL_CLK_THROTTLE_TYPE_POWER].start = ktime_get(); | ||
| 4780 | hdev->clk_throttling.timestamp[HL_CLK_THROTTLE_TYPE_POWER].end = zero_time; | ||
| 4774 | dev_info_ratelimited(hdev->dev, | 4781 | dev_info_ratelimited(hdev->dev, |
| 4775 | "Clock throttling due to power consumption\n"); | 4782 | "Clock throttling due to power consumption\n"); |
| 4776 | break; | 4783 | break; |
| 4784 | |||
| 4777 | case GOYA_ASYNC_EVENT_ID_FIX_POWER_ENV_E: | 4785 | case GOYA_ASYNC_EVENT_ID_FIX_POWER_ENV_E: |
| 4778 | hdev->clk_throttling_reason &= ~HL_CLK_THROTTLE_POWER; | 4786 | hdev->clk_throttling.current_reason &= ~HL_CLK_THROTTLE_POWER; |
| 4787 | hdev->clk_throttling.timestamp[HL_CLK_THROTTLE_TYPE_POWER].end = ktime_get(); | ||
| 4779 | dev_info_ratelimited(hdev->dev, | 4788 | dev_info_ratelimited(hdev->dev, |
| 4780 | "Power envelop is safe, back to optimal clock\n"); | 4789 | "Power envelop is safe, back to optimal clock\n"); |
| 4781 | break; | 4790 | break; |
| 4791 | |||
| 4782 | case GOYA_ASYNC_EVENT_ID_FIX_THERMAL_ENV_S: | 4792 | case GOYA_ASYNC_EVENT_ID_FIX_THERMAL_ENV_S: |
| 4783 | hdev->clk_throttling_reason |= HL_CLK_THROTTLE_THERMAL; | 4793 | hdev->clk_throttling.current_reason |= HL_CLK_THROTTLE_THERMAL; |
| 4794 | hdev->clk_throttling.aggregated_reason |= HL_CLK_THROTTLE_THERMAL; | ||
| 4795 | hdev->clk_throttling.timestamp[HL_CLK_THROTTLE_TYPE_THERMAL].start = ktime_get(); | ||
| 4796 | hdev->clk_throttling.timestamp[HL_CLK_THROTTLE_TYPE_THERMAL].end = zero_time; | ||
| 4784 | dev_info_ratelimited(hdev->dev, | 4797 | dev_info_ratelimited(hdev->dev, |
| 4785 | "Clock throttling due to overheating\n"); | 4798 | "Clock throttling due to overheating\n"); |
| 4786 | break; | 4799 | break; |
| 4800 | |||
| 4787 | case GOYA_ASYNC_EVENT_ID_FIX_THERMAL_ENV_E: | 4801 | case GOYA_ASYNC_EVENT_ID_FIX_THERMAL_ENV_E: |
| 4788 | hdev->clk_throttling_reason &= ~HL_CLK_THROTTLE_THERMAL; | 4802 | hdev->clk_throttling.current_reason &= ~HL_CLK_THROTTLE_THERMAL; |
| 4803 | hdev->clk_throttling.timestamp[HL_CLK_THROTTLE_TYPE_THERMAL].end = ktime_get(); | ||
| 4789 | dev_info_ratelimited(hdev->dev, | 4804 | dev_info_ratelimited(hdev->dev, |
| 4790 | "Thermal envelop is safe, back to optimal clock\n"); | 4805 | "Thermal envelop is safe, back to optimal clock\n"); |
| 4791 | break; | 4806 | break; |
| @@ -4795,6 +4810,8 @@ static void goya_print_clk_change_info(struct hl_device *hdev, u16 event_type) · 3 unmodified lines | |||
| 4795 | event_type); | 4810 | event_type); |
| 4796 | break; | 4811 | break; |
| 4797 | } | 4812 | } |
| 4813 | |||
| 4814 | mutex_unlock(&hdev->clk_throttling.lock); | ||
| 4798 | } | 4815 | } |
| 4799 | 4816 | ||
| 4800 | void goya_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entry) | 4817 | void goya_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entry) |
| @@ -473,15 +473,27 @@ struct hl_info_pci_counters { · 472 unmodified lines | |||
| 473 | __u64 replay_cnt; | 473 | __u64 replay_cnt; |
| 474 | }; | 474 | }; |
| 475 | 475 | ||
| 476 | #define HL_CLK_THROTTLE_POWER 0x1 | 476 | enum hl_clk_throttling_type { |
| 477 | #define HL_CLK_THROTTLE_THERMAL 0x2 | 477 | HL_CLK_THROTTLE_TYPE_POWER, |
| 478 | HL_CLK_THROTTLE_TYPE_THERMAL, | ||
| 479 | HL_CLK_THROTTLE_TYPE_MAX | ||
| 480 | }; | ||
| 481 | |||
| 482 | /* clk_throttling_reason masks */ | ||
| 483 | #define HL_CLK_THROTTLE_POWER (1 << HL_CLK_THROTTLE_TYPE_POWER) | ||
| 484 | #define HL_CLK_THROTTLE_THERMAL (1 << HL_CLK_THROTTLE_TYPE_THERMAL) | ||
| 478 | 485 | ||
| 479 | /** | 486 | /** |
| 480 | * struct hl_info_clk_throttle - clock throttling reason | 487 | * struct hl_info_clk_throttle - clock throttling reason |
| 481 | * @clk_throttling_reason: each bit represents a clk throttling reason | 488 | * @clk_throttling_reason: each bit represents a clk throttling reason |
| 489 | * @clk_throttling_timestamp_us: represents CPU timestamp in microseconds of the start-event | ||
| 490 | * @clk_throttling_duration_ns: the clock throttle time in nanosec | ||
| 482 | */ | 491 | */ |
| 483 | struct hl_info_clk_throttle { | 492 | struct hl_info_clk_throttle { |
| 484 | __u32 clk_throttling_reason; | 493 | __u32 clk_throttling_reason; |
| 494 | __u32 pad; | ||
| 495 | __u64 clk_throttling_timestamp_us[HL_CLK_THROTTLE_TYPE_MAX]; | ||
| 496 | __u64 clk_throttling_duration_ns[HL_CLK_THROTTLE_TYPE_MAX]; | ||
| 485 | }; | 497 | }; |
| 486 | 498 | ||
| 487 | /** | 499 | /** |