334 lines
8.2 KiB
C
334 lines
8.2 KiB
C
/*
|
|
* 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, <B>IO interface need to be set</B>
|
|
*
|
|
* @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_ */
|