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 | 455 | INIT_LIST_HEAD(&hdev->fpriv_list); |
| 456 | 456 | mutex_init(&hdev->fpriv_list_lock); |
| 457 | 457 | atomic_set(&hdev->in_reset, 0); |
| 458 | + mutex_init(&hdev->clk_throttling.lock); | |
| 458 | 459 | |
| 459 | 460 | return 0; |
| 460 | 461 | |
| @@ -495,6 +496,8 @@ static void device_early_fini(struct hl_device *hdev) · 34 unmodified lines | ||
| 495 | 496 | |
| 496 | 497 | mutex_destroy(&hdev->fpriv_list_lock); |
| 497 | 498 | |
| 499 | + mutex_destroy(&hdev->clk_throttling.lock); | |
| 500 | + | |
| 498 | 501 | hl_cb_mgr_fini(hdev, &hdev->kernel_cb_mgr); |
| 499 | 502 | |
| 500 | 503 | kfree(hdev->hl_chip_info); |
| @@ -2378,6 +2378,32 @@ struct multi_cs_data { · 2377 unmodified lines | ||
| 2378 | 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 | 2408 | * struct hl_device - habanalabs device structure. |
| 2383 | 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 | 2471 | * @pci_mem_region: array of memory regions in the PCI |
| 2446 | 2472 | * @state_dump_specs: constants and dictionaries needed to dump system state. |
| 2447 | 2473 | * @multi_cs_completion: array of multi-CS completion. |
| 2474 | + * @clk_throttling: holds information about current/previous clock throttling events | |
| 2448 | 2475 | * @dram_used_mem: current DRAM memory consumption. |
| 2449 | 2476 | * @timeout_jiffies: device CS timeout value. |
| 2450 | 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 | 2501 | * @high_pll: high PLL profile frequency. |
| 2475 | 2502 | * @soft_reset_cnt: number of soft reset since the driver was loaded. |
| 2476 | 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 | 2504 | * @id: device minor. |
| 2479 | 2505 | * @id_control: minor of the control device |
| 2480 | 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 | 2631 | struct multi_cs_completion multi_cs_completion[ |
| 2606 | 2632 | MULTI_CS_MAX_USER_CTX]; |
| 2633 | + struct hl_clk_throttle clk_throttling; | |
| 2634 | + | |
| 2607 | 2635 | u32 *stream_master_qid_arr; |
| 2608 | 2636 | atomic64_t dram_used_mem; |
| 2609 | 2637 | u64 timeout_jiffies; |
| @@ -2622,7 +2650,6 @@ struct hl_device { · 12 unmodified lines | ||
| 2622 | 2650 | u32 high_pll; |
| 2623 | 2651 | u32 soft_reset_cnt; |
| 2624 | 2652 | u32 hard_reset_cnt; |
| 2625 | − u32 clk_throttling_reason; | |
| 2626 | 2653 | u16 id; |
| 2627 | 2654 | u16 id_control; |
| 2628 | 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 | 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 | 317 | struct hl_device *hdev = hpriv->hdev; |
| 317 | 318 | struct hl_info_clk_throttle clk_throttle = {0}; |
| 319 | + ktime_t end_time, zero_time = ktime_set(0, 0); | |
| 318 | 320 | u32 max_size = args->return_size; |
| 319 | − void __user *out = (void __user *) (uintptr_t) args->return_pointer; | |
| 321 | + int i; | |
| 320 | 322 | |
| 321 | 323 | if ((!max_size) || (!out)) |
| 322 | 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 | 349 | return copy_to_user(out, &clk_throttle, |
| 327 | 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 | 7925 | static void gaudi_print_clk_change_info(struct hl_device *hdev, |
| 7926 | 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 | 7932 | switch (event_type) { |
| 7929 | 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 | 7938 | dev_info_ratelimited(hdev->dev, |
| 7932 | 7939 | "Clock throttling due to power consumption\n"); |
| 7933 | 7940 | break; |
| 7934 | 7941 | |
| 7935 | 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 | 7945 | dev_info_ratelimited(hdev->dev, |
| 7938 | 7946 | "Power envelop is safe, back to optimal clock\n"); |
| 7939 | 7947 | break; |
| 7940 | 7948 | |
| 7941 | 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 | 7954 | dev_info_ratelimited(hdev->dev, |
| 7944 | 7955 | "Clock throttling due to overheating\n"); |
| 7945 | 7956 | break; |
| 7946 | 7957 | |
| 7947 | 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 | 7961 | dev_info_ratelimited(hdev->dev, |
| 7950 | 7962 | "Thermal envelop is safe, back to optimal clock\n"); |
| 7951 | 7963 | break; |
| @@ -7955,6 +7967,8 @@ static void gaudi_print_clk_change_info(struct hl_device *hdev, · 3 unmodified lines | ||
| 7955 | 7967 | event_type); |
| 7956 | 7968 | break; |
| 7957 | 7969 | } |
| 7970 | + | |
| 7971 | + mutex_unlock(&hdev->clk_throttling.lock); | |
| 7958 | 7972 | } |
| 7959 | 7973 | |
| 7960 | 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 | 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 | 4775 | switch (event_type) { |
| 4772 | 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 | 4781 | dev_info_ratelimited(hdev->dev, |
| 4775 | 4782 | "Clock throttling due to power consumption\n"); |
| 4776 | 4783 | break; |
| 4784 | + | |
| 4777 | 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 | 4788 | dev_info_ratelimited(hdev->dev, |
| 4780 | 4789 | "Power envelop is safe, back to optimal clock\n"); |
| 4781 | 4790 | break; |
| 4791 | + | |
| 4782 | 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 | 4797 | dev_info_ratelimited(hdev->dev, |
| 4785 | 4798 | "Clock throttling due to overheating\n"); |
| 4786 | 4799 | break; |
| 4800 | + | |
| 4787 | 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 | 4804 | dev_info_ratelimited(hdev->dev, |
| 4790 | 4805 | "Thermal envelop is safe, back to optimal clock\n"); |
| 4791 | 4806 | break; |
| @@ -4795,6 +4810,8 @@ static void goya_print_clk_change_info(struct hl_device *hdev, u16 event_type) · 3 unmodified lines | ||
| 4795 | 4810 | event_type); |
| 4796 | 4811 | break; |
| 4797 | 4812 | } |
| 4813 | + | |
| 4814 | + mutex_unlock(&hdev->clk_throttling.lock); | |
| 4798 | 4815 | } |
| 4799 | 4816 | |
| 4800 | 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 | 473 | __u64 replay_cnt; |
| 474 | 474 | }; |
| 475 | 475 | |
| 476 | −#define HL_CLK_THROTTLE_POWER 0x1 | |
| 477 | −#define HL_CLK_THROTTLE_THERMAL 0x2 | |
| 476 | +enum hl_clk_throttling_type { | |
| 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 | 487 | * struct hl_info_clk_throttle - clock throttling reason |
| 481 | 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 | 492 | struct hl_info_clk_throttle { |
| 484 | 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 | /** |