// SPDX-License-Identifier: GPL-2.0 /** * Copyright (c) 2024-2025 CALCULET Technologies Ltd. All rights reserved. */ #ifndef _CALCULET_UTILS_H_ #define _CALCULET_UTILS_H_ #include #include #include #include #include #include #include #include #include // 日志级别定义 #define CALCULET_LOG_EMERG 0 #define CALCULET_LOG_ALERT 1 #define CALCULET_LOG_CRIT 2 #define CALCULET_LOG_ERROR 3 #define CALCULET_LOG_WARN 4 #define CALCULET_LOG_NOTICE 5 #define CALCULET_LOG_INFO 6 #define CALCULET_LOG_DEBUG 7 // 编译时日志级别控制(通过Makefile设置) #ifndef CALCULET_LOG_LEVEL #ifdef DEBUG #define CALCULET_LOG_LEVEL CALCULET_LOG_DEBUG #else #define CALCULET_LOG_LEVEL CALCULET_LOG_INFO #endif #endif // 统一的日志函数声明 extern int calculet_log_level; // 主要的日志宏 #define calculet_log(level, fmt, ...) \ do { \ if ((level) <= CALCULET_LOG_LEVEL && (level) <= calculet_log_level) { \ const char *level_str; \ switch (level) { \ case CALCULET_LOG_EMERG: level_str = KERN_EMERG; break; \ case CALCULET_LOG_ALERT: level_str = KERN_ALERT; break; \ case CALCULET_LOG_CRIT: level_str = KERN_CRIT; break; \ case CALCULET_LOG_ERROR: level_str = KERN_ERR; break; \ case CALCULET_LOG_WARN: level_str = KERN_WARNING; break; \ case CALCULET_LOG_NOTICE: level_str = KERN_NOTICE; break; \ case CALCULET_LOG_INFO: level_str = KERN_INFO; break; \ case CALCULET_LOG_DEBUG: level_str = KERN_DEBUG; break; \ default: level_str = KERN_INFO; break; \ } \ printk("%s" "calculet: " fmt "\n", level_str, ##__VA_ARGS__); \ } \ } while (0) // 带板卡信息的日志宏 #define calculet_board_log(level, board, fmt, ...) \ do { \ if ((level) <= CALCULET_LOG_LEVEL && (level) <= calculet_log_level && (board)) { \ const char *level_str; \ switch (level) { \ case CALCULET_LOG_EMERG: level_str = KERN_EMERG; break; \ case CALCULET_LOG_ALERT: level_str = KERN_ALERT; break; \ case CALCULET_LOG_CRIT: level_str = KERN_CRIT; break; \ case CALCULET_LOG_ERROR: level_str = KERN_ERR; break; \ case CALCULET_LOG_WARN: level_str = KERN_WARNING; break; \ case CALCULET_LOG_NOTICE: level_str = KERN_NOTICE; break; \ case CALCULET_LOG_INFO: level_str = KERN_INFO; break; \ case CALCULET_LOG_DEBUG: level_str = KERN_DEBUG; break; \ default: level_str = KERN_INFO; break; \ } \ if (board && (board)->pDev && &(board)->pDev->dev) { \ dev_printk(level_str, &(board)->pDev->dev, fmt, ##__VA_ARGS__); \ } else { \ printk("%s" "calculet: [board error] " fmt "\n", level_str, ##__VA_ARGS__); \ } \ } \ } while (0) // 带设备信息的日志宏 #define calculet_dev_log(level, dev, fmt, ...) \ do { \ if ((level) <= CALCULET_LOG_LEVEL && (level) <= calculet_log_level && (dev)) { \ const char *level_str; \ switch (level) { \ case CALCULET_LOG_EMERG: level_str = KERN_EMERG; break; \ case CALCULET_LOG_ALERT: level_str = KERN_ALERT; break; \ case CALCULET_LOG_CRIT: level_str = KERN_CRIT; break; \ case CALCULET_LOG_ERROR: level_str = KERN_ERR; break; \ case CALCULET_LOG_WARN: level_str = KERN_WARNING; break; \ case CALCULET_LOG_NOTICE: level_str = KERN_NOTICE; break; \ case CALCULET_LOG_INFO: level_str = KERN_INFO; break; \ case CALCULET_LOG_DEBUG: level_str = KERN_DEBUG; break; \ default: level_str = KERN_INFO; break; \ } \ if (dev) { \ dev_printk(level_str, dev, fmt, ##__VA_ARGS__); \ } else { \ printk("%s" "calculet: [dev error] " fmt "\n", level_str, ##__VA_ARGS__); \ } \ } \ } while (0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0) #define class_create_compat class_create #elif defined(RHEL_MAJOR) && RHEL_MAJOR >= 9 #define class_create_compat class_create #else #define class_create_compat(name) class_create(THIS_MODULE, name) #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 16, 0) #define pci_printk(level, pdev, fmt, arg...) \ dev_printk(level, &(pdev)->dev, fmt, ##arg) #define pci_emerg(pdev, fmt, arg...) dev_emerg(&(pdev)->dev, fmt, ##arg) #define pci_alert(pdev, fmt, arg...) dev_alert(&(pdev)->dev, fmt, ##arg) #define pci_crit(pdev, fmt, arg...) dev_crit(&(pdev)->dev, fmt, ##arg) #define pci_err(pdev, fmt, arg...) dev_err(&(pdev)->dev, fmt, ##arg) #define pci_warn(pdev, fmt, arg...) dev_warn(&(pdev)->dev, fmt, ##arg) #define pci_notice(pdev, fmt, arg...) dev_notice(&(pdev)->dev, fmt, ##arg) #define pci_info(pdev, fmt, arg...) dev_info(&(pdev)->dev, fmt, ##arg) #define pci_dbg(pdev, fmt, arg...) dev_dbg(&(pdev)->dev, fmt, ##arg) #endif // 性能测量宏(简化) #ifdef CALCULET_PERF_ANALYSIS #define CALCULET_PERF_START(name) \ ktime_t __perf_start_##name = ktime_get() #define CALCULET_PERF_END(name, fmt, ...) \ do { \ ktime_t __perf_end_##name = ktime_get(); \ s64 __perf_delta_##name = ktime_to_ns(ktime_sub(__perf_end_##name, __perf_start_##name)); \ calculet_log(CALCULET_LOG_DEBUG, "PERF %s: %lld ns - " fmt, #name, __perf_delta_##name, ##__VA_ARGS__); \ } while (0) #else #define CALCULET_PERF_START(name) do { } while (0) #define CALCULET_PERF_END(name, fmt, ...) do { } while (0) #endif // 调试断言宏 #ifdef CALCULET_DEBUG_MODE #define CALCULET_ASSERT(cond) \ do { \ if (unlikely(!(cond))) { \ calculet_log(CALCULET_LOG_CRIT, "ASSERTION FAILED: %s at %s:%d", #cond, __FILE__, __LINE__); \ dump_stack(); \ } \ } while (0) #define CALCULET_ASSERT_MSG(cond, fmt, ...) \ do { \ if (unlikely(!(cond))) { \ calculet_log(CALCULET_LOG_CRIT, "ASSERTION FAILED: %s at %s:%d - " fmt, \ #cond, __FILE__, __LINE__, ##__VA_ARGS__); \ dump_stack(); \ } \ } while (0) #else #define CALCULET_ASSERT(cond) do { } while (0) #define CALCULET_ASSERT_MSG(cond, fmt, ...) do { } while (0) #endif // 更多兼容性定义 #if LINUX_VERSION_CODE >= KERNEL_VERSION( 5, 0, 0 ) #define compatible_access_ok(a,b,c) access_ok(b, c) #else #define compatible_access_ok(a,b,c) access_ok(a, b, c) #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 5, 0) #define get_user_pages_compact get_user_pages #elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0) #define get_user_pages_compact(start, nr_pages, gup_flags, pages) \ get_user_pages(start, nr_pages, gup_flags, pages, NULL) #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 168)) && (LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0)) #define get_user_pages_compact(start, nr_pages, gup_flags, pages) \ get_user_pages(current, current->mm, start, nr_pages, gup_flags, pages, NULL) #else static inline int get_user_pages_compact(struct task_struct *current, struct mm_struct *mm, unsigned long start, int nr_pages, int write, int force, struct page **pages, struct vm_area_struct **vmas) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,6,0) return get_user_pages(start, nr_pages, write ? FOLL_WRITE : 0, pages, vmas); #else return get_user_pages(current, mm, start, nr_pages, write, force, pages, vmas); #endif } #endif #ifndef _LINUX_MMAP_LOCK_H static inline void mmap_read_lock(struct mm_struct *mm) { down_read(&mm->mmap_sem); } static inline void mmap_read_unlock(struct mm_struct *mm) { up_read(&mm->mmap_sem); } #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION( 4, 13, 0 ) #define wait_queue_t wait_queue_entry_t #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION( 4, 15, 0 ) #define ACCESS_ONCE READ_ONCE #endif #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)) #define CALCULET_IRQ_FLAGS (SA_SHIRQ | SA_INTERRUPT) #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) && LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0)) #define CALCULET_IRQ_FLAGS (IRQF_SHARED | IRQF_DISABLED) #else #define CALCULET_IRQ_FLAGS (IRQF_SHARED) #endif // 实用工具宏 #define CALCULET_ALIGN_UP(value, align) \ (((value) + (align) - 1) & ~((align) - 1)) #define CALCULET_ALIGN_DOWN(value, align) \ ((value) & ~((align) - 1)) #define CALCULET_DIV_ROUND_UP(n, d) \ (((n) + (d) - 1) / (d)) #define CALCULET_IS_POWER_OF_2(x) \ ((x) != 0 && (((x) & ((x) - 1)) == 0)) // 错误处理工具 #define CALCULET_RETURN_IF_NULL(ptr, ret) \ do { if (unlikely(!(ptr))) return (ret); } while (0) #define CALCULET_RETURN_IF_ERROR(expr) \ do { \ int __ret = (expr); \ if (unlikely(__ret < 0)) return __ret; \ } while (0) // 时间转换工具 static inline u64 calculet_ktime_to_us(ktime_t kt) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0) return ktime_divns(kt, NSEC_PER_USEC); #else u64 ns = ktime_to_ns(kt); do_div(ns, NSEC_PER_USEC); return ns; #endif } static inline u64 calculet_ktime_to_ms(ktime_t kt) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0) return ktime_divns(kt, NSEC_PER_MSEC); #else u64 ns = ktime_to_ns(kt); do_div(ns, NSEC_PER_MSEC); return ns; #endif } // 延迟和等待工具 static inline void calculet_udelay_range(unsigned long min_us, unsigned long max_us) { if (min_us == max_us) { udelay(min_us); } else { usleep_range(min_us, max_us); } } // 统计工具(简化的原子版本) struct calculet_stats_counter { atomic64_t count; atomic64_t total; atomic64_t min; atomic64_t max; }; static inline void calculet_stats_init(struct calculet_stats_counter *stats) { atomic64_set(&stats->count, 0); atomic64_set(&stats->total, 0); atomic64_set(&stats->min, LLONG_MAX); atomic64_set(&stats->max, 0); } static inline void calculet_stats_update(struct calculet_stats_counter *stats, s64 value) { s64 old_min, old_max; atomic64_inc(&stats->count); atomic64_add(value, &stats->total); // 使用简单的CAS来更新min/max do { old_min = atomic64_read(&stats->min); } while (value < old_min && atomic64_cmpxchg(&stats->min, old_min, value) != old_min); do { old_max = atomic64_read(&stats->max); } while (value > old_max && atomic64_cmpxchg(&stats->max, old_max, value) != old_max); } static inline s64 calculet_stats_avg(struct calculet_stats_counter *stats) { s64 count = atomic64_read(&stats->count); return count ? atomic64_read(&stats->total) / count : 0; } // 函数声明 int calculet_utils_init(void); void calculet_utils_cleanup(void); void calculet_global_stats_init(void); void calculet_global_stats_update(s64 value); void calculet_global_stats_get(s64 *count, s64 *total, s64 *min, s64 *max, s64 *avg); void calculet_global_stats_cleanup(void); void calculet_random_delay_us(unsigned int min_us, unsigned int max_us); #endif /* _CALCULET_UTILS_H_ */