mirror of
https://github.com/torvalds/linux.git
synced 2026-05-02 13:32:40 -04:00
drm/amd/display: Add new DP tunnel bandwidth validation
[Why & How] Add new function for DP tunnel bandwidth validation. It uses the estimated BW and allocated BW to validate the timings. Reviewed-by: PeiChen Huang <peichen.huang@amd.com> Reviewed-by: Meenakshikumar Somasundaram <meenakshikumar.somasundaram@amd.com> Signed-off-by: Cruise Hung <Cruise.Hung@amd.com> Signed-off-by: Fangzhi Zuo <jerry.zuo@amd.com> Tested-by: Daniel Wheeler <daniel.wheeler@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
committed by
Alex Deucher
parent
0c5f7371dd
commit
7beee6e91c
@@ -75,12 +75,15 @@ enum dc_status dpcd_get_tunneling_device_data(struct dc_link *link)
|
||||
|
||||
if (link->dpcd_caps.usb4_dp_tun_info.dp_tun_cap.bits.dpia_bw_alloc) {
|
||||
status = core_link_read_dpcd(link, USB4_DRIVER_BW_CAPABILITY,
|
||||
dpcd_dp_tun_data, 1);
|
||||
dpcd_dp_tun_data, 2);
|
||||
|
||||
if (status != DC_OK)
|
||||
goto err;
|
||||
|
||||
link->dpcd_caps.usb4_dp_tun_info.driver_bw_cap.raw = dpcd_dp_tun_data[0];
|
||||
link->dpcd_caps.usb4_dp_tun_info.driver_bw_cap.raw =
|
||||
dpcd_dp_tun_data[USB4_DRIVER_BW_CAPABILITY - USB4_DRIVER_BW_CAPABILITY];
|
||||
link->dpcd_caps.usb4_dp_tun_info.dpia_tunnel_info.raw =
|
||||
dpcd_dp_tun_data[DP_IN_ADAPTER_TUNNEL_INFO - USB4_DRIVER_BW_CAPABILITY];
|
||||
}
|
||||
|
||||
DC_LOG_DEBUG("%s: Link[%d] DP tunneling support (RouterId=%d AdapterId=%d) "
|
||||
@@ -155,8 +158,14 @@ void link_decide_dp_tunnel_settings(struct dc_stream_state *stream,
|
||||
link->dpcd_caps.usb4_dp_tun_info.dp_tun_cap.bits.dp_tunneling;
|
||||
|
||||
if (link->dpcd_caps.usb4_dp_tun_info.dp_tun_cap.bits.dpia_bw_alloc
|
||||
&& link->dpcd_caps.usb4_dp_tun_info.driver_bw_cap.bits.driver_bw_alloc_support)
|
||||
&& link->dpcd_caps.usb4_dp_tun_info.driver_bw_cap.bits.driver_bw_alloc_support) {
|
||||
dp_tunnel_setting->should_use_dp_bw_allocation = true;
|
||||
dp_tunnel_setting->cm_id = link->dpcd_caps.usb4_dp_tun_info.usb4_driver_id & 0x0F;
|
||||
dp_tunnel_setting->group_id = link->dpcd_caps.usb4_dp_tun_info.dpia_tunnel_info.bits.group_id;
|
||||
dp_tunnel_setting->estimated_bw = link->dpia_bw_alloc_config.estimated_bw;
|
||||
dp_tunnel_setting->allocated_bw = link->dpia_bw_alloc_config.allocated_bw;
|
||||
dp_tunnel_setting->bw_granularity = link->dpia_bw_alloc_config.bw_granularity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
|
||||
#define Kbps_TO_Gbps (1000 * 1000)
|
||||
|
||||
#define MST_TIME_SLOT_COUNT 64
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// PRIVATE FUNCTIONS
|
||||
// ------------------------------------------------------------------
|
||||
@@ -251,32 +253,40 @@ static void dpia_bw_alloc_unplug(struct dc_link *link)
|
||||
|
||||
static void link_dpia_send_bw_alloc_request(struct dc_link *link, int req_bw)
|
||||
{
|
||||
uint8_t requested_bw;
|
||||
uint32_t temp;
|
||||
uint8_t request_reg_val;
|
||||
uint32_t temp, request_bw;
|
||||
|
||||
/* Error check whether request bw greater than allocated */
|
||||
if (req_bw > link->dpia_bw_alloc_config.estimated_bw) {
|
||||
DC_LOG_ERROR("%s: Request BW greater than estimated BW for link(%d)\n",
|
||||
__func__, link->link_index);
|
||||
req_bw = link->dpia_bw_alloc_config.estimated_bw;
|
||||
if (link->dpia_bw_alloc_config.bw_granularity == 0) {
|
||||
DC_LOG_ERROR("%s: Link[%d]: bw_granularity is zero!", __func__, link->link_index);
|
||||
return;
|
||||
}
|
||||
|
||||
temp = req_bw * link->dpia_bw_alloc_config.bw_granularity;
|
||||
requested_bw = temp / Kbps_TO_Gbps;
|
||||
request_reg_val = temp / Kbps_TO_Gbps;
|
||||
|
||||
/* Always make sure to add more to account for floating points */
|
||||
if (temp % Kbps_TO_Gbps)
|
||||
++requested_bw;
|
||||
++request_reg_val;
|
||||
|
||||
/* Error check whether requested and allocated are equal */
|
||||
req_bw = requested_bw * (Kbps_TO_Gbps / link->dpia_bw_alloc_config.bw_granularity);
|
||||
if (req_bw && (req_bw == link->dpia_bw_alloc_config.allocated_bw)) {
|
||||
DC_LOG_ERROR("%s: Request BW equals to allocated BW for link(%d)\n",
|
||||
__func__, link->link_index);
|
||||
request_bw = request_reg_val * (Kbps_TO_Gbps / link->dpia_bw_alloc_config.bw_granularity);
|
||||
|
||||
if (request_bw > link->dpia_bw_alloc_config.estimated_bw) {
|
||||
DC_LOG_ERROR("%s: Link[%d]: Request BW (%d --> %d) > Estimated BW (%d)... Set to Estimated BW!",
|
||||
__func__, link->link_index,
|
||||
req_bw, request_bw, link->dpia_bw_alloc_config.estimated_bw);
|
||||
req_bw = link->dpia_bw_alloc_config.estimated_bw;
|
||||
|
||||
temp = req_bw * link->dpia_bw_alloc_config.bw_granularity;
|
||||
request_reg_val = temp / Kbps_TO_Gbps;
|
||||
if (temp % Kbps_TO_Gbps)
|
||||
++request_reg_val;
|
||||
}
|
||||
|
||||
link->dpia_bw_alloc_config.allocated_bw = request_bw;
|
||||
DC_LOG_DC("%s: Link[%d]: Request BW: %d", __func__, link->link_index, request_bw);
|
||||
|
||||
core_link_write_dpcd(link, REQUESTED_BW,
|
||||
&requested_bw,
|
||||
&request_reg_val,
|
||||
sizeof(uint8_t));
|
||||
}
|
||||
|
||||
@@ -331,19 +341,17 @@ bool link_dpia_enable_usb4_dp_bw_alloc_mode(struct dc_link *link)
|
||||
*/
|
||||
void link_dp_dpia_handle_bw_alloc_status(struct dc_link *link, uint8_t status)
|
||||
{
|
||||
link->dpia_bw_alloc_config.estimated_bw = get_estimated_bw(link);
|
||||
|
||||
if (status & DP_TUNNELING_BW_REQUEST_SUCCEEDED) {
|
||||
DC_LOG_DEBUG("%s: BW Allocation request succeeded on link(%d)",
|
||||
__func__, link->link_index);
|
||||
} else if (status & DP_TUNNELING_BW_REQUEST_FAILED) {
|
||||
link->dpia_bw_alloc_config.estimated_bw = get_estimated_bw(link);
|
||||
|
||||
DC_LOG_DEBUG("%s: BW Allocation request failed on link(%d) allocated/estimated BW=%d",
|
||||
__func__, link->link_index, link->dpia_bw_alloc_config.estimated_bw);
|
||||
|
||||
link_dpia_send_bw_alloc_request(link, link->dpia_bw_alloc_config.estimated_bw);
|
||||
} else if (status & DP_TUNNELING_ESTIMATED_BW_CHANGED) {
|
||||
link->dpia_bw_alloc_config.estimated_bw = get_estimated_bw(link);
|
||||
|
||||
DC_LOG_DEBUG("%s: Estimated BW changed on link(%d) new estimated BW=%d",
|
||||
__func__, link->link_index, link->dpia_bw_alloc_config.estimated_bw);
|
||||
}
|
||||
@@ -376,9 +384,13 @@ void dpia_handle_usb4_bandwidth_allocation_for_link(struct dc_link *link, int pe
|
||||
|
||||
void link_dp_dpia_allocate_usb4_bandwidth_for_stream(struct dc_link *link, int req_bw)
|
||||
{
|
||||
DC_LOG_DEBUG("%s: ENTER: link(%d), hpd_status(%d), current allocated_bw(%d), req_bw(%d)\n",
|
||||
link->dpia_bw_alloc_config.estimated_bw = get_estimated_bw(link);
|
||||
|
||||
DC_LOG_DEBUG("%s: ENTER: link[%d] hpd(%d) Allocated_BW: %d Estimated_BW: %d Req_BW: %d",
|
||||
__func__, link->link_index, link->hpd_status,
|
||||
link->dpia_bw_alloc_config.allocated_bw, req_bw);
|
||||
link->dpia_bw_alloc_config.allocated_bw,
|
||||
link->dpia_bw_alloc_config.estimated_bw,
|
||||
req_bw);
|
||||
|
||||
if (link_dp_is_bw_alloc_available(link))
|
||||
link_dpia_send_bw_alloc_request(link, req_bw);
|
||||
@@ -389,7 +401,8 @@ void link_dp_dpia_allocate_usb4_bandwidth_for_stream(struct dc_link *link, int r
|
||||
bool dpia_validate_usb4_bw(struct dc_link **link, int *bw_needed_per_dpia, const unsigned int num_dpias)
|
||||
{
|
||||
bool ret = true;
|
||||
int bw_needed_per_hr[MAX_HR_NUM] = { 0, 0 }, host_router_total_dp_bw = 0;
|
||||
int bw_needed_per_hr[MAX_HOST_ROUTERS_NUM] = { 0 };
|
||||
int host_router_total_dp_bw = 0;
|
||||
uint8_t lowest_dpia_index, i, hr_index;
|
||||
|
||||
if (!num_dpias || num_dpias > MAX_DPIA_NUM)
|
||||
@@ -417,7 +430,7 @@ bool dpia_validate_usb4_bw(struct dc_link **link, int *bw_needed_per_dpia, const
|
||||
}
|
||||
|
||||
/* validate against each Host Router max BW */
|
||||
for (hr_index = 0; hr_index < MAX_HR_NUM; ++hr_index) {
|
||||
for (hr_index = 0; hr_index < MAX_HOST_ROUTERS_NUM; ++hr_index) {
|
||||
if (bw_needed_per_hr[hr_index]) {
|
||||
host_router_total_dp_bw = get_host_router_total_dp_tunnel_bw(link[0]->dc, hr_index);
|
||||
if (bw_needed_per_hr[hr_index] > host_router_total_dp_bw) {
|
||||
@@ -430,29 +443,111 @@ bool dpia_validate_usb4_bw(struct dc_link **link, int *bw_needed_per_dpia, const
|
||||
return ret;
|
||||
}
|
||||
|
||||
int link_dp_dpia_get_dp_overhead_in_dp_tunneling(struct dc_link *link)
|
||||
uint32_t link_dpia_get_dp_mst_overhead(const struct dc_link *link)
|
||||
{
|
||||
int dp_overhead = 0, link_mst_overhead = 0;
|
||||
uint32_t link_mst_overhead = 0;
|
||||
|
||||
if (!link_dp_is_bw_alloc_available(link))
|
||||
return dp_overhead;
|
||||
|
||||
/* if its mst link, add MTPH overhead */
|
||||
if ((link->type == dc_connection_mst_branch) &&
|
||||
!link->dpcd_caps.channel_coding_cap.bits.DP_128b_132b_SUPPORTED) {
|
||||
!link->dpcd_caps.channel_coding_cap.bits.DP_128b_132b_SUPPORTED) {
|
||||
/* For 8b/10b encoding: MTP is 64 time slots long, slot 0 is used for MTPH
|
||||
* MST overhead is 1/64 of link bandwidth (excluding any overhead)
|
||||
*/
|
||||
const struct dc_link_settings *link_cap =
|
||||
dc_link_get_link_cap(link);
|
||||
uint32_t link_bw_in_kbps = (uint32_t)link_cap->link_rate *
|
||||
const struct dc_link_settings *link_cap = dc_link_get_link_cap(link);
|
||||
|
||||
if (link_cap) {
|
||||
uint32_t link_bw_in_kbps = (uint32_t)link_cap->link_rate *
|
||||
(uint32_t)link_cap->lane_count *
|
||||
LINK_RATE_REF_FREQ_IN_KHZ * 8;
|
||||
link_mst_overhead = (link_bw_in_kbps / 64) + ((link_bw_in_kbps % 64) ? 1 : 0);
|
||||
link_mst_overhead = (link_bw_in_kbps / MST_TIME_SLOT_COUNT)
|
||||
+ ((link_bw_in_kbps % MST_TIME_SLOT_COUNT) ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* add all the overheads */
|
||||
dp_overhead = link_mst_overhead;
|
||||
|
||||
return dp_overhead;
|
||||
return link_mst_overhead;
|
||||
}
|
||||
|
||||
/*
|
||||
* Aggregates the DPIA bandwidth usage for the respective USB4 Router.
|
||||
* And then validate if the required bandwidth is within the router's capacity.
|
||||
*
|
||||
* @dc_validation_dpia_set: pointer to the dc_validation_dpia_set
|
||||
* @count: number of DPIA validation sets
|
||||
*
|
||||
* return: true if validation is succeeded
|
||||
*/
|
||||
bool link_dpia_validate_dp_tunnel_bandwidth(const struct dc_validation_dpia_set *dpia_link_sets, uint8_t count)
|
||||
{
|
||||
uint32_t granularity_Gbps;
|
||||
const struct dc_link *link;
|
||||
uint32_t link_bw_granularity;
|
||||
uint32_t link_required_bw;
|
||||
struct usb4_router_validation_set router_sets[MAX_HOST_ROUTERS_NUM] = { 0 };
|
||||
uint8_t i;
|
||||
bool is_success = true;
|
||||
uint8_t rounter_count = 0;
|
||||
|
||||
if ((dpia_link_sets == NULL) || (count == 0))
|
||||
return is_success;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
link = dpia_link_sets[i].link;
|
||||
link_required_bw = dpia_link_sets[i].required_bw;
|
||||
const struct dc_tunnel_settings *dp_tunnel_settings = dpia_link_sets[i].tunnel_settings;
|
||||
|
||||
if ((link == NULL) || (dp_tunnel_settings == NULL) || dp_tunnel_settings->bw_granularity == 0)
|
||||
break;
|
||||
|
||||
if (link->type == dc_connection_mst_branch)
|
||||
link_required_bw += link_dpia_get_dp_mst_overhead(link);
|
||||
|
||||
granularity_Gbps = (Kbps_TO_Gbps / dp_tunnel_settings->bw_granularity);
|
||||
link_bw_granularity = (link_required_bw / granularity_Gbps) * granularity_Gbps +
|
||||
((link_required_bw % granularity_Gbps) ? granularity_Gbps : 0);
|
||||
|
||||
for (uint8_t j = 0; j < MAX_HOST_ROUTERS_NUM; j++) {
|
||||
if (router_sets[j].is_valid == false) {
|
||||
router_sets[j].is_valid = true;
|
||||
router_sets[j].cm_id = dp_tunnel_settings->cm_id;
|
||||
rounter_count++;
|
||||
}
|
||||
|
||||
if (router_sets[j].cm_id == dp_tunnel_settings->cm_id) {
|
||||
uint32_t remaining_bw =
|
||||
dp_tunnel_settings->estimated_bw - dp_tunnel_settings->allocated_bw;
|
||||
|
||||
router_sets[j].allocated_bw += dp_tunnel_settings->allocated_bw;
|
||||
|
||||
if (remaining_bw > router_sets[j].remaining_bw)
|
||||
router_sets[j].remaining_bw = remaining_bw;
|
||||
|
||||
// Get the max estimated BW within the same CM_ID
|
||||
if (dp_tunnel_settings->estimated_bw > router_sets[j].estimated_bw)
|
||||
router_sets[j].estimated_bw = dp_tunnel_settings->estimated_bw;
|
||||
|
||||
router_sets[j].required_bw += link_bw_granularity;
|
||||
router_sets[j].dpia_count++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < rounter_count; i++) {
|
||||
uint32_t total_bw = 0;
|
||||
|
||||
if (router_sets[i].is_valid == false)
|
||||
break;
|
||||
|
||||
if ((router_sets[i].dpia_count == 1) || (router_sets[i].allocated_bw == 0))
|
||||
total_bw = router_sets[i].estimated_bw;
|
||||
else
|
||||
total_bw = router_sets[i].allocated_bw + router_sets[i].remaining_bw;
|
||||
|
||||
if (router_sets[i].required_bw > total_bw) {
|
||||
is_success = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return is_success;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,10 +28,6 @@
|
||||
|
||||
#include "link.h"
|
||||
|
||||
/* Number of Host Routers per motherboard is 2 */
|
||||
#define MAX_HR_NUM 2
|
||||
/* Number of DPIA per host router is 2 */
|
||||
#define MAX_DPIA_NUM (MAX_HR_NUM * 2)
|
||||
|
||||
/*
|
||||
* Host Router BW type
|
||||
@@ -42,6 +38,16 @@ enum bw_type {
|
||||
HOST_ROUTER_BW_INVALID,
|
||||
};
|
||||
|
||||
struct usb4_router_validation_set {
|
||||
bool is_valid;
|
||||
uint8_t cm_id;
|
||||
uint8_t dpia_count;
|
||||
uint32_t required_bw;
|
||||
uint32_t allocated_bw;
|
||||
uint32_t estimated_bw;
|
||||
uint32_t remaining_bw;
|
||||
};
|
||||
|
||||
/*
|
||||
* Enable USB4 DP BW allocation mode
|
||||
*
|
||||
@@ -92,7 +98,7 @@ bool dpia_validate_usb4_bw(struct dc_link **link, int *bw_needed, const unsigned
|
||||
*
|
||||
* return: DP overheads in DP tunneling
|
||||
*/
|
||||
int link_dp_dpia_get_dp_overhead_in_dp_tunneling(struct dc_link *link);
|
||||
uint32_t link_dpia_get_dp_mst_overhead(const struct dc_link *link);
|
||||
|
||||
/*
|
||||
* Handle DP BW allocation status register
|
||||
@@ -104,4 +110,15 @@ int link_dp_dpia_get_dp_overhead_in_dp_tunneling(struct dc_link *link);
|
||||
*/
|
||||
void link_dp_dpia_handle_bw_alloc_status(struct dc_link *link, uint8_t status);
|
||||
|
||||
/*
|
||||
* Aggregates the DPIA bandwidth usage for the respective USB4 Router.
|
||||
*
|
||||
* @dc_validation_dpia_set: pointer to the dc_validation_dpia_set
|
||||
* @count: number of DPIA validation sets
|
||||
*
|
||||
* return: true if validation is succeeded
|
||||
*/
|
||||
bool link_dpia_validate_dp_tunnel_bandwidth(const struct dc_validation_dpia_set *dpia_link_sets, uint8_t count);
|
||||
|
||||
#endif /* DC_INC_LINK_DP_DPIA_BW_H_ */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user