/* * Copyright(c) 2012-2021 Intel Corporation * SPDX-License-Identifier: BSD-3-Clause-Clear */ #ifndef ENGINE_COMMON_H_ #define ENGINE_COMMON_H_ #include "../ocf_request.h" #include "../utils/utils_cache_line.h" /** * @file engine_common.h * @brief OCF cache engine common module */ /** * @brief Signal and handle OCF request error * * @param req OCF request * @param stop_cache Indicates if OCF cache engine need to be stopped * @param msg Error message to be printed into log */ void ocf_engine_error(struct ocf_request *req, bool stop_cache, const char *msg); /** * @brief Check if OCF request is hit * * @param req OCF request * * @retval true HIT * @retval false MISS */ static inline bool ocf_engine_is_hit(struct ocf_request *req) { return req->info.hit_no == req->core_line_count; } /** * @brief Check if OCF request is miss * * @param req OCF request * * @retval true MISS * @retval false HIT */ #define ocf_engine_is_miss(req) (!ocf_engine_is_hit(req)) /** * @brief Check if all the cache lines are assigned to a good partition * * @param req OCF request * * @retval true request's cache lines are assigned to a good partition * @retval false some of the request's cache lines needs to be reassigned to * a target partition */ static inline bool ocf_engine_needs_repart(struct ocf_request *req) { return req->info.re_part_no > 0; } /** * @brief Check if all cache lines are mapped fully * * @param req OCF request * * @retval true request is mapped fully * @retval false request is not mapped fully and eviction might be run in * order to complete mapping */ static inline bool ocf_engine_is_mapped(struct ocf_request *req) { return req->info.hit_no + req->info.invalid_no == req->core_line_count; } /** * @brief Check if all cache lines are dirty * * @param req OCF request * * @retval true request is dirty fully * @retval false request is not dirty fully */ static inline bool ocf_engine_is_dirty_all(struct ocf_request *req) { return req->info.dirty_all == req->core_line_count; } /** * @brief Get number of mapped cache lines * * @param req OCF request * * @return Number of mapped cache lines */ static inline uint32_t ocf_engine_mapped_count(struct ocf_request *req) { return req->info.hit_no + req->info.invalid_no; } /** * @brief Get number of unmapped cache lines * * @param req OCF request * * @return Number of unmapped cache lines */ static inline uint32_t ocf_engine_unmapped_count(struct ocf_request *req) { return req->core_line_count - (req->info.hit_no + req->info.invalid_no); } void ocf_map_cache_line(struct ocf_request *req, unsigned int idx, ocf_cache_line_t cache_line); /** * @brief Get number of cache lines to repart * * @param req OCF request * * @retval Number of cache lines to repart */ static inline uint32_t ocf_engine_repart_count(struct ocf_request *req) { return req->info.re_part_no; } static inline uint32_t ocf_engine_is_sequential(struct ocf_request *req) { return req->info.hit_no + req->info.insert_no == req->core_line_count && req->info.seq_no == req->core_line_count - 1; } /** * @brief Get number of IOs to perform cache read or write * * @param req OCF request * * @return Count of cache IOs */ static inline uint32_t ocf_engine_io_count(struct ocf_request *req) { return ocf_engine_is_sequential(req) ? 1 : req->core_line_count; } static inline bool ocf_engine_map_all_sec_dirty(struct ocf_request *req, uint32_t line) { uint8_t start = ocf_map_line_start_sector(req, line); uint8_t end = ocf_map_line_end_sector(req, line); if (req->map[line].status != LOOKUP_HIT) return false; return metadata_test_dirty_all_sec(req->cache, req->map[line].coll_idx, start, end); } static inline bool ocf_engine_map_all_sec_clean(struct ocf_request *req, uint32_t line) { uint8_t start = ocf_map_line_start_sector(req, line); uint8_t end = ocf_map_line_end_sector(req, line); if (req->map[line].status != LOOKUP_HIT) return false; if (!metadata_test_valid_sec(req->cache, req->map[line].coll_idx, start, end)) { return false; } return !metadata_test_dirty_sec(req->cache, req->map[line].coll_idx, start, end); } static inline bool ocf_engine_map_all_sec_valid(struct ocf_request *req, uint32_t line) { uint8_t start = ocf_map_line_start_sector(req, line); uint8_t end = ocf_map_line_end_sector(req, line); if (req->map[line].status != LOOKUP_HIT) return false; return metadata_test_valid_sec(req->cache, req->map[line].coll_idx, start, end); } /** * @brief Clean request (flush dirty data to the core device) * * @param req OCF request * * @note After successful cleaning: * - Dirty status bits in request info will be cleared * - Request will be pushed front, IO interface need to be set * * @note In case of failure: * - unlock request * - complete request to the application * - free request */ void ocf_engine_clean(struct ocf_request *req); void ocf_engine_lookup_map_entry(struct ocf_cache *cache, struct ocf_map_info *entry, ocf_core_id_t core_id, uint64_t core_line); /** * @brief Request cacheline lock type */ enum ocf_engine_lock_type { /** No lock */ ocf_engine_lock_none = 0, /** Write lock */ ocf_engine_lock_write, /** Read lock */ ocf_engine_lock_read, }; /** * @brief Engine-specific callbacks for common request handling rountine * * TODO(arutk): expand this structure to fit all engines and all steps */ struct ocf_engine_callbacks { /** Specify locking requirements after request is mapped */ enum ocf_engine_lock_type (*get_lock_type)(struct ocf_request *req); /** Resume handling after acquiring asynchronous lock */ ocf_req_async_lock_cb resume; }; /** * @brief Map and lock cachelines * * @param req OCF request * * @returns eviction status * @retval LOOKUP_INSERTED successfully evicted required number of cachelines * @retval LOOKUP_MISS eviction failure */ int ocf_engine_prepare_clines(struct ocf_request *req); /** * @brief Traverse OCF request (lookup cache) * * @note This function does not evict cachelines. Only lookup in metadata is * performed. Main purpose of this function is to check if there is a HIT. * * @param req OCF request */ void ocf_engine_traverse(struct ocf_request *req); /** * @brief Check if OCF request mapping is still valid * * @note If mapping entries is invalid it will be marked * * @param req OCF request * * @retval 0 - OCF request mapping is valid * @return Non zero - OCF request mapping is invalid and need to call re-mapping */ int ocf_engine_check(struct ocf_request *req); /** * @brief Update OCF request info after evicting a cacheline * * @param cache OCF cache instance * @param req OCF request * @param idx cacheline index within the request */ void ocf_engine_patch_req_info(struct ocf_cache *cache, struct ocf_request *req, uint32_t idx); /** * @brief Update OCF request block statistics for an exported object * * @param req OCF request */ void ocf_engine_update_block_stats(struct ocf_request *req); /** * @brief Update OCF request request statistics for an exported object * (not applicable to write wi and to read wt * * @param req OCF request */ void ocf_engine_update_request_stats(struct ocf_request *req); /** * @brief Push front OCF request to the OCF thread worker queue * * @param req OCF request * @param allow_sync caller allows for request from queue to be ran immediately from push function in caller context */ void ocf_engine_push_req_back(struct ocf_request *req, bool allow_sync); /** * @brief Push back OCF request to the OCF thread worker queue * * @param req OCF request * @param allow_sync caller allows for request from queue to be ran immediately from push function in caller context */ void ocf_engine_push_req_front(struct ocf_request *req, bool allow_sync); /** * @brief Set interface and push from request to the OCF thread worker queue * * @param req OCF request * @param io_if IO interface * @param allow_sync caller allows for request from queue to be ran immediately from push function in caller context */ void ocf_engine_push_req_front_if(struct ocf_request *req, const struct ocf_io_if *io_if, bool allow_sync); void inc_fallback_pt_error_counter(ocf_cache_t cache); void ocf_engine_on_resume(struct ocf_request *req); #endif /* ENGINE_COMMON_H_ */