drm/amd/display: Fix minor issues in BW Allocation Phase2

[Why]
Fix minor issues in BW Allocation Phase2.

[How]
- In set_usb4_req_bw_req(), link->dpia_bw_alloc_config.response_ready
  flag should be reset before writing DPCD REQUEST_BW.
- Fix the granularity for value of 2 in get_bw_granularity().
- Removed bandwidth allocation support display fw boot option as
  the fw would read feature enable status from bios.
- Clean up DPIA_EST_BW_CHANGED and DPIA_BW_REQ_SUCCESS cases in
  dpia_handle_bw_alloc_response().
- Removed allocate_usb4_bw and deallocate_usb4_bw.
- Optimized loop in get_lowest_dpia_index().
- Updated link_dp_dpia_allocate_usb4_bandwidth_for_stream() and
  set_usb4_req_bw_req() to always issue request bw.

Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Reviewed-by: PeiChen Huang <peichen.huang@amd.com>
Acked-by: Rodrigo Siqueira <rodrigo.siqueira@amd.com>
Signed-off-by: Meenakshikumar Somasundaram <meenakshikumar.somasundaram@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Meenakshikumar Somasundaram 2023-12-04 10:57:45 -05:00 committed by Alex Deucher
parent ca1ecae145
commit aa5dc05340
2 changed files with 101 additions and 124 deletions

View file

@ -50,6 +50,7 @@ static bool get_bw_alloc_proceed_flag(struct dc_link *tmp)
&& tmp->hpd_status && tmp->hpd_status
&& tmp->dpia_bw_alloc_config.bw_alloc_enabled); && tmp->dpia_bw_alloc_config.bw_alloc_enabled);
} }
static void reset_bw_alloc_struct(struct dc_link *link) static void reset_bw_alloc_struct(struct dc_link *link)
{ {
link->dpia_bw_alloc_config.bw_alloc_enabled = false; link->dpia_bw_alloc_config.bw_alloc_enabled = false;
@ -59,6 +60,11 @@ static void reset_bw_alloc_struct(struct dc_link *link)
link->dpia_bw_alloc_config.bw_granularity = 0; link->dpia_bw_alloc_config.bw_granularity = 0;
link->dpia_bw_alloc_config.response_ready = false; link->dpia_bw_alloc_config.response_ready = false;
} }
#define BW_GRANULARITY_0 4 // 0.25 Gbps
#define BW_GRANULARITY_1 2 // 0.5 Gbps
#define BW_GRANULARITY_2 1 // 1 Gbps
static uint8_t get_bw_granularity(struct dc_link *link) static uint8_t get_bw_granularity(struct dc_link *link)
{ {
uint8_t bw_granularity = 0; uint8_t bw_granularity = 0;
@ -71,16 +77,20 @@ static uint8_t get_bw_granularity(struct dc_link *link)
switch (bw_granularity & 0x3) { switch (bw_granularity & 0x3) {
case 0: case 0:
bw_granularity = 4; bw_granularity = BW_GRANULARITY_0;
break; break;
case 1: case 1:
bw_granularity = BW_GRANULARITY_1;
break;
case 2:
default: default:
bw_granularity = 2; bw_granularity = BW_GRANULARITY_2;
break; break;
} }
return bw_granularity; return bw_granularity;
} }
static int get_estimated_bw(struct dc_link *link) static int get_estimated_bw(struct dc_link *link)
{ {
uint8_t bw_estimated_bw = 0; uint8_t bw_estimated_bw = 0;
@ -93,31 +103,7 @@ static int get_estimated_bw(struct dc_link *link)
return bw_estimated_bw * (Kbps_TO_Gbps / link->dpia_bw_alloc_config.bw_granularity); return bw_estimated_bw * (Kbps_TO_Gbps / link->dpia_bw_alloc_config.bw_granularity);
} }
static bool allocate_usb4_bw(int *stream_allocated_bw, int bw_needed, struct dc_link *link)
{
if (bw_needed > 0)
*stream_allocated_bw += bw_needed;
return true;
}
static bool deallocate_usb4_bw(int *stream_allocated_bw, int bw_to_dealloc, struct dc_link *link)
{
bool ret = false;
if (*stream_allocated_bw > 0) {
*stream_allocated_bw -= bw_to_dealloc;
ret = true;
} else {
//Do nothing for now
ret = true;
}
// Unplug so reset values
if (!link->hpd_status)
reset_bw_alloc_struct(link);
return ret;
}
/* /*
* Read all New BW alloc configuration ex: estimated_bw, allocated_bw, * Read all New BW alloc configuration ex: estimated_bw, allocated_bw,
* granuality, Driver_ID, CM_Group, & populate the BW allocation structs * granuality, Driver_ID, CM_Group, & populate the BW allocation structs
@ -128,7 +114,12 @@ static void init_usb4_bw_struct(struct dc_link *link)
// Init the known values // Init the known values
link->dpia_bw_alloc_config.bw_granularity = get_bw_granularity(link); link->dpia_bw_alloc_config.bw_granularity = get_bw_granularity(link);
link->dpia_bw_alloc_config.estimated_bw = get_estimated_bw(link); link->dpia_bw_alloc_config.estimated_bw = get_estimated_bw(link);
DC_LOG_DEBUG("%s: bw_granularity(%d), estimated_bw(%d)\n",
__func__, link->dpia_bw_alloc_config.bw_granularity,
link->dpia_bw_alloc_config.estimated_bw);
} }
static uint8_t get_lowest_dpia_index(struct dc_link *link) static uint8_t get_lowest_dpia_index(struct dc_link *link)
{ {
const struct dc *dc_struct = link->dc; const struct dc *dc_struct = link->dc;
@ -141,12 +132,15 @@ static uint8_t get_lowest_dpia_index(struct dc_link *link)
dc_struct->links[i]->ep_type != DISPLAY_ENDPOINT_USB4_DPIA) dc_struct->links[i]->ep_type != DISPLAY_ENDPOINT_USB4_DPIA)
continue; continue;
if (idx > dc_struct->links[i]->link_index) if (idx > dc_struct->links[i]->link_index) {
idx = dc_struct->links[i]->link_index; idx = dc_struct->links[i]->link_index;
break;
}
} }
return idx; return idx;
} }
/* /*
* Get the Max Available BW or Max Estimated BW for each Host Router * Get the Max Available BW or Max Estimated BW for each Host Router
* *
@ -186,6 +180,7 @@ static int get_host_router_total_bw(struct dc_link *link, uint8_t type)
return total_bw; return total_bw;
} }
/* /*
* Cleanup function for when the dpia is unplugged to reset struct * Cleanup function for when the dpia is unplugged to reset struct
* and perform any required clean up * and perform any required clean up
@ -194,42 +189,50 @@ static int get_host_router_total_bw(struct dc_link *link, uint8_t type)
* *
* return: none * return: none
*/ */
static bool dpia_bw_alloc_unplug(struct dc_link *link) static void dpia_bw_alloc_unplug(struct dc_link *link)
{ {
if (!link) if (link) {
return true; DC_LOG_DEBUG("%s: resetting bw alloc config for link(%d)\n",
__func__, link->link_index);
return deallocate_usb4_bw(&link->dpia_bw_alloc_config.sink_allocated_bw, link->dpia_bw_alloc_config.sink_allocated_bw = 0;
link->dpia_bw_alloc_config.sink_allocated_bw, link); reset_bw_alloc_struct(link);
}
} }
static void set_usb4_req_bw_req(struct dc_link *link, int req_bw) static void set_usb4_req_bw_req(struct dc_link *link, int req_bw)
{ {
uint8_t requested_bw; uint8_t requested_bw;
uint32_t temp; uint32_t temp;
// 1. Add check for this corner case #1 /* Error check whether request bw greater than allocated */
if (req_bw > link->dpia_bw_alloc_config.estimated_bw) 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; req_bw = link->dpia_bw_alloc_config.estimated_bw;
}
temp = req_bw * link->dpia_bw_alloc_config.bw_granularity; temp = req_bw * link->dpia_bw_alloc_config.bw_granularity;
requested_bw = temp / Kbps_TO_Gbps; requested_bw = temp / Kbps_TO_Gbps;
// Always make sure to add more to account for floating points /* Always make sure to add more to account for floating points */
if (temp % Kbps_TO_Gbps) if (temp % Kbps_TO_Gbps)
++requested_bw; ++requested_bw;
// 2. Add check for this corner case #2 /* Error check whether requested and allocated are equal */
req_bw = requested_bw * (Kbps_TO_Gbps / link->dpia_bw_alloc_config.bw_granularity); req_bw = requested_bw * (Kbps_TO_Gbps / link->dpia_bw_alloc_config.bw_granularity);
if (req_bw == link->dpia_bw_alloc_config.sink_allocated_bw) if (req_bw == link->dpia_bw_alloc_config.sink_allocated_bw) {
return; DC_LOG_ERROR("%s: Request bw equals to allocated bw for link(%d)\n",
__func__, link->link_index);
}
if (core_link_write_dpcd( link->dpia_bw_alloc_config.response_ready = false; // Reset flag
core_link_write_dpcd(
link, link,
REQUESTED_BW, REQUESTED_BW,
&requested_bw, &requested_bw,
sizeof(uint8_t)) == DC_OK) sizeof(uint8_t));
link->dpia_bw_alloc_config.response_ready = false; // Reset flag
} }
/* /*
* Return the response_ready flag from dc_link struct * Return the response_ready flag from dc_link struct
* *
@ -241,6 +244,7 @@ static bool get_cm_response_ready_flag(struct dc_link *link)
{ {
return link->dpia_bw_alloc_config.response_ready; return link->dpia_bw_alloc_config.response_ready;
} }
// ------------------------------------------------------------------ // ------------------------------------------------------------------
// PUBLIC FUNCTIONS // PUBLIC FUNCTIONS
// ------------------------------------------------------------------ // ------------------------------------------------------------------
@ -277,27 +281,27 @@ bool link_dp_dpia_set_dptx_usb4_bw_alloc_support(struct dc_link *link)
DPTX_BW_ALLOCATION_MODE_CONTROL, DPTX_BW_ALLOCATION_MODE_CONTROL,
&response, &response,
sizeof(uint8_t)) != DC_OK) { sizeof(uint8_t)) != DC_OK) {
DC_LOG_DEBUG("%s: **** FAILURE Enabling DPtx BW Allocation Mode Support ***\n", DC_LOG_DEBUG("%s: FAILURE Enabling DPtx BW Allocation Mode Support for link(%d)\n",
__func__); __func__, link->link_index);
} else { } else {
// SUCCESS Enabled DPtx BW Allocation Mode Support // SUCCESS Enabled DPtx BW Allocation Mode Support
link->dpia_bw_alloc_config.bw_alloc_enabled = true; DC_LOG_DEBUG("%s: SUCCESS Enabling DPtx BW Allocation Mode Support for link(%d)\n",
DC_LOG_DEBUG("%s: **** SUCCESS Enabling DPtx BW Allocation Mode Support ***\n", __func__, link->link_index);
__func__);
ret = true; ret = true;
init_usb4_bw_struct(link); init_usb4_bw_struct(link);
link->dpia_bw_alloc_config.bw_alloc_enabled = true;
} }
} }
out: out:
return ret; return ret;
} }
void dpia_handle_bw_alloc_response(struct dc_link *link, uint8_t bw, uint8_t result) void dpia_handle_bw_alloc_response(struct dc_link *link, uint8_t bw, uint8_t result)
{ {
int bw_needed = 0; int bw_needed = 0;
int estimated = 0; int estimated = 0;
int host_router_total_estimated_bw = 0;
if (!get_bw_alloc_proceed_flag((link))) if (!get_bw_alloc_proceed_flag((link)))
return; return;
@ -306,14 +310,22 @@ void dpia_handle_bw_alloc_response(struct dc_link *link, uint8_t bw, uint8_t res
case DPIA_BW_REQ_FAILED: case DPIA_BW_REQ_FAILED:
DC_LOG_DEBUG("%s: *** *** BW REQ FAILURE for DP-TX Request *** ***\n", __func__); /*
* Ideally, we shouldn't run into this case as we always validate available
* bandwidth and request within that limit
*/
estimated = bw * (Kbps_TO_Gbps / link->dpia_bw_alloc_config.bw_granularity);
// Update the new Estimated BW value updated by CM DC_LOG_ERROR("%s: BW REQ FAILURE for DP-TX Request for link(%d)\n",
link->dpia_bw_alloc_config.estimated_bw = __func__, link->link_index);
bw * (Kbps_TO_Gbps / link->dpia_bw_alloc_config.bw_granularity); DC_LOG_ERROR("%s: current estimated_bw(%d), new estimated_bw(%d)\n",
__func__, link->dpia_bw_alloc_config.estimated_bw, estimated);
/* Update the new Estimated BW value updated by CM */
link->dpia_bw_alloc_config.estimated_bw = estimated;
/* Allocate the previously requested bandwidth */
set_usb4_req_bw_req(link, link->dpia_bw_alloc_config.estimated_bw); set_usb4_req_bw_req(link, link->dpia_bw_alloc_config.estimated_bw);
link->dpia_bw_alloc_config.response_ready = false;
/* /*
* If FAIL then it is either: * If FAIL then it is either:
@ -326,68 +338,34 @@ void dpia_handle_bw_alloc_response(struct dc_link *link, uint8_t bw, uint8_t res
case DPIA_BW_REQ_SUCCESS: case DPIA_BW_REQ_SUCCESS:
DC_LOG_DEBUG("%s: *** BW REQ SUCCESS for DP-TX Request ***\n", __func__);
// 1. SUCCESS 1st time before any Pruning is done
// 2. SUCCESS after prev. FAIL before any Pruning is done
// 3. SUCCESS after Pruning is done but before enabling link
bw_needed = bw * (Kbps_TO_Gbps / link->dpia_bw_alloc_config.bw_granularity); bw_needed = bw * (Kbps_TO_Gbps / link->dpia_bw_alloc_config.bw_granularity);
// 1. DC_LOG_DEBUG("%s: BW REQ SUCCESS for DP-TX Request for link(%d)\n",
if (!link->dpia_bw_alloc_config.sink_allocated_bw) { __func__, link->link_index);
DC_LOG_DEBUG("%s: current allocated_bw(%d), new allocated_bw(%d)\n",
__func__, link->dpia_bw_alloc_config.sink_allocated_bw, bw_needed);
allocate_usb4_bw(&link->dpia_bw_alloc_config.sink_allocated_bw, bw_needed, link); link->dpia_bw_alloc_config.sink_allocated_bw = bw_needed;
link->dpia_bw_alloc_config.sink_verified_bw =
link->dpia_bw_alloc_config.sink_allocated_bw;
// SUCCESS from first attempt
if (link->dpia_bw_alloc_config.sink_allocated_bw >
link->dpia_bw_alloc_config.sink_max_bw)
link->dpia_bw_alloc_config.sink_verified_bw =
link->dpia_bw_alloc_config.sink_max_bw;
}
// 3.
else if (link->dpia_bw_alloc_config.sink_allocated_bw) {
// Find out how much do we need to de-alloc
if (link->dpia_bw_alloc_config.sink_allocated_bw > bw_needed)
deallocate_usb4_bw(&link->dpia_bw_alloc_config.sink_allocated_bw,
link->dpia_bw_alloc_config.sink_allocated_bw - bw_needed, link);
else
allocate_usb4_bw(&link->dpia_bw_alloc_config.sink_allocated_bw,
bw_needed - link->dpia_bw_alloc_config.sink_allocated_bw, link);
}
// 4. If this is the 2nd sink then any unused bw will be reallocated to master DPIA
// => check if estimated_bw changed
link->dpia_bw_alloc_config.response_ready = true; link->dpia_bw_alloc_config.response_ready = true;
break; break;
case DPIA_EST_BW_CHANGED: case DPIA_EST_BW_CHANGED:
DC_LOG_DEBUG("%s: *** ESTIMATED BW CHANGED for DP-TX Request ***\n", __func__);
estimated = bw * (Kbps_TO_Gbps / link->dpia_bw_alloc_config.bw_granularity); estimated = bw * (Kbps_TO_Gbps / link->dpia_bw_alloc_config.bw_granularity);
host_router_total_estimated_bw = get_host_router_total_bw(link, HOST_ROUTER_BW_ESTIMATED);
// 1. If due to unplug of other sink DC_LOG_DEBUG("%s: ESTIMATED BW CHANGED for link(%d)\n",
if (estimated == host_router_total_estimated_bw) { __func__, link->link_index);
// First update the estimated & max_bw fields DC_LOG_DEBUG("%s: current estimated_bw(%d), new estimated_bw(%d)\n",
if (link->dpia_bw_alloc_config.estimated_bw < estimated) __func__, link->dpia_bw_alloc_config.estimated_bw, estimated);
link->dpia_bw_alloc_config.estimated_bw = estimated;
} link->dpia_bw_alloc_config.estimated_bw = estimated;
// 2. If due to realloc bw btw 2 dpia due to plug OR realloc unused Bw
else {
// We lost estimated bw usually due to plug event of other dpia
link->dpia_bw_alloc_config.estimated_bw = estimated;
}
break; break;
case DPIA_BW_ALLOC_CAPS_CHANGED: case DPIA_BW_ALLOC_CAPS_CHANGED:
DC_LOG_DEBUG("%s: *** BW ALLOC CAPABILITY CHANGED for DP-TX Request ***\n", __func__); DC_LOG_ERROR("%s: BW ALLOC CAPABILITY CHANGED to Disabled for link(%d)\n",
__func__, link->link_index);
link->dpia_bw_alloc_config.bw_alloc_enabled = false; link->dpia_bw_alloc_config.bw_alloc_enabled = false;
break; break;
} }
@ -409,11 +387,11 @@ int dpia_handle_usb4_bandwidth_allocation_for_link(struct dc_link *link, int pea
set_usb4_req_bw_req(link, link->dpia_bw_alloc_config.sink_max_bw); set_usb4_req_bw_req(link, link->dpia_bw_alloc_config.sink_max_bw);
do { do {
if (!(timeout > 0)) if (timeout > 0)
timeout--; timeout--;
else else
break; break;
fsleep(10 * 1000); msleep(10);
} while (!get_cm_response_ready_flag(link)); } while (!get_cm_response_ready_flag(link));
if (!timeout) if (!timeout)
@ -428,37 +406,36 @@ int dpia_handle_usb4_bandwidth_allocation_for_link(struct dc_link *link, int pea
out: out:
return ret; return ret;
} }
int link_dp_dpia_allocate_usb4_bandwidth_for_stream(struct dc_link *link, int req_bw)
bool link_dp_dpia_allocate_usb4_bandwidth_for_stream(struct dc_link *link, int req_bw)
{ {
int ret = 0; bool ret = false;
uint8_t timeout = 10; uint8_t timeout = 10;
DC_LOG_DEBUG("%s: ENTER: link(%d), hpd_status(%d), current allocated_bw(%d), req_bw(%d)\n",
__func__, link->link_index, link->hpd_status,
link->dpia_bw_alloc_config.sink_allocated_bw, req_bw);
if (!get_bw_alloc_proceed_flag(link)) if (!get_bw_alloc_proceed_flag(link))
goto out; goto out;
/* set_usb4_req_bw_req(link, req_bw);
* Sometimes stream uses same timing parameters as the already do {
* allocated max sink bw so no need to re-alloc if (timeout > 0)
*/ timeout--;
if (req_bw != link->dpia_bw_alloc_config.sink_allocated_bw) { else
set_usb4_req_bw_req(link, req_bw); break;
do { msleep(10);
if (!(timeout > 0)) } while (!get_cm_response_ready_flag(link));
timeout--;
else
break;
udelay(10 * 1000);
} while (!get_cm_response_ready_flag(link));
if (!timeout) if (timeout)
ret = 0;// ERROR TIMEOUT waiting for response for allocating bw ret = true;
else if (link->dpia_bw_alloc_config.sink_allocated_bw > 0)
ret = get_host_router_total_bw(link, HOST_ROUTER_BW_ALLOCATED);
}
out: out:
DC_LOG_DEBUG("%s: EXIT: timeout(%d), ret(%d)\n", __func__, timeout, ret);
return ret; return ret;
} }
bool dpia_validate_usb4_bw(struct dc_link **link, int *bw_needed_per_dpia, const unsigned int num_dpias) bool dpia_validate_usb4_bw(struct dc_link **link, int *bw_needed_per_dpia, const unsigned int num_dpias)
{ {
bool ret = true; bool ret = true;

View file

@ -59,9 +59,9 @@ bool link_dp_dpia_set_dptx_usb4_bw_alloc_support(struct dc_link *link);
* @link: pointer to the dc_link struct instance * @link: pointer to the dc_link struct instance
* @req_bw: Bw requested by the stream * @req_bw: Bw requested by the stream
* *
* return: allocated bw else return 0 * return: true if allocated successfully
*/ */
int link_dp_dpia_allocate_usb4_bandwidth_for_stream(struct dc_link *link, int req_bw); bool link_dp_dpia_allocate_usb4_bandwidth_for_stream(struct dc_link *link, int req_bw);
/* /*
* Handle the USB4 BW Allocation related functionality here: * Handle the USB4 BW Allocation related functionality here: