]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
drm/amd/display: Add new DP tunnel bandwidth validation
authorCruise Hung <Cruise.Hung@amd.com>
Tue, 3 Jun 2025 06:30:59 +0000 (14:30 +0800)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 24 Jun 2025 13:55:35 +0000 (09:55 -0400)
[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>
14 files changed:
drivers/gpu/drm/amd/display/dc/core/dc_debug.c
drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c
drivers/gpu/drm/amd/display/dc/dc.h
drivers/gpu/drm/amd/display/dc/dc_dp_types.h
drivers/gpu/drm/amd/display/dc/dc_types.h
drivers/gpu/drm/amd/display/dc/inc/core_status.h
drivers/gpu/drm/amd/display/dc/inc/link.h
drivers/gpu/drm/amd/display/dc/link/link_dpms.c
drivers/gpu/drm/amd/display/dc/link/link_factory.c
drivers/gpu/drm/amd/display/dc/link/link_validation.c
drivers/gpu/drm/amd/display/dc/link/link_validation.h
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia.c
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.c
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.h

index 7551d0a3fe8223b2396357da0741b7c45e57d552..bbce751b485fdcfd2df0aeb03165ce9b7e818af1 100644 (file)
@@ -268,6 +268,8 @@ char *dc_status_to_str(enum dc_status status)
                return "Insufficient DP link bandwidth";
        case DC_FAIL_HW_CURSOR_SUPPORT:
                return "HW Cursor not supported";
+       case DC_FAIL_DP_TUNNEL_BW_VALIDATE:
+               return "Fail DP Tunnel BW validation";
        case DC_ERROR_UNEXPECTED:
                return "Unexpected error";
        }
index 71e15da4bb69af110d9f90c70457cb875f0ced7a..90c595e88aa029b2273e21f0d478e4b66933d034 100644 (file)
@@ -519,3 +519,9 @@ bool dc_link_dp_dpia_validate(struct dc *dc, const struct dc_stream_state *strea
 {
        return dc->link_srv->validate_dpia_bandwidth(streams, count);
 }
+
+enum dc_status dc_link_validate_dp_tunneling_bandwidth(const struct dc *dc, const struct dc_state *new_ctx)
+{
+       return dc->link_srv->validate_dp_tunnel_bandwidth(dc, new_ctx);
+}
+
index 44aed03c37f2043e79e1a94d5b9bfc5404a1aeff..f5df271c8d1a04d2ddd8cdb4bc283af86bc457c4 100644 (file)
@@ -68,10 +68,12 @@ struct dmub_notification;
 #define MAX_STREAMS 6
 #define MIN_VIEWPORT_SIZE 12
 #define MAX_NUM_EDP 2
-#define MAX_HOST_ROUTERS_NUM 3
-#define MAX_DPIA_PER_HOST_ROUTER 2
 #define MAX_SUPPORTED_FORMATS 7
 
+#define MAX_HOST_ROUTERS_NUM 3
+#define MAX_DPIA_PER_HOST_ROUTER 3
+#define MAX_DPIA_NUM  (MAX_HOST_ROUTERS_NUM * MAX_DPIA_PER_HOST_ROUTER)
+
 /* Display Core Interfaces */
 struct dc_versions {
        const char *dc_ver;
@@ -2427,6 +2429,14 @@ void dc_link_dp_dpia_handle_usb4_bandwidth_allocation_for_link(
 bool dc_link_dp_dpia_validate(struct dc *dc, const struct dc_stream_state *streams,
                const unsigned int count);
 
+/*
+ * Calculates the DP tunneling bandwidth required for the stream timing
+ * and aggregates the stream bandwidth for the respective DP tunneling link
+ *
+ * return: dc_status
+ */
+enum dc_status dc_link_validate_dp_tunneling_bandwidth(const struct dc *dc, const struct dc_state *new_ctx);
+
 /* Sink Interfaces - A sink corresponds to a display output device */
 
 struct dc_container_id {
index d346f8ae163466fb9003c529d8aeb69c38340292..5ce1be362534dc97329409c6b08adeb64e80e84f 100644 (file)
@@ -162,6 +162,11 @@ struct dc_link_settings {
 struct dc_tunnel_settings {
        bool should_enable_dp_tunneling;
        bool should_use_dp_bw_allocation;
+       uint8_t cm_id;
+       uint8_t group_id;
+       uint32_t bw_granularity;
+       uint32_t estimated_bw;
+       uint32_t allocated_bw;
 };
 
 union dc_dp_ffe_preset {
@@ -957,11 +962,21 @@ union usb4_driver_bw_cap {
        uint8_t raw;
 };
 
+/* DPCD[0xE0021] DP_IN_ADAPTER_TUNNEL_INFORMATION register. */
+union dpia_tunnel_info {
+       struct {
+               uint8_t group_id :3;
+               uint8_t rsvd :5;
+       } bits;
+       uint8_t raw;
+};
+
 /* DP Tunneling over USB4 */
 struct dpcd_usb4_dp_tunneling_info {
        union dp_tun_cap_support dp_tun_cap;
        union dpia_info dpia_info;
        union usb4_driver_bw_cap driver_bw_cap;
+       union dpia_tunnel_info dpia_tunnel_info;
        uint8_t usb4_driver_id;
        uint8_t usb4_topology_id[DPCD_USB4_TOPOLOGY_ID_LEN];
 };
index a8afbe5eaf1d9b5bc38518fcec0c01f54b437c4b..b203ed020cd5746b35098182f822835d9f69c898 100644 (file)
@@ -1378,4 +1378,11 @@ enum dc_validate_mode {
        /* validate the mode and get the max state (voltage level) */
        DC_VALIDATE_MODE_AND_STATE_INDEX = 2,
 };
+
+struct dc_validation_dpia_set {
+       const struct dc_link *link;
+       const struct dc_tunnel_settings *tunnel_settings;
+       uint32_t required_bw;
+};
+
 #endif /* DC_TYPES_H_ */
index f3696143590c446d31cfd69f4cc19f655e450e9f..82085d9c3f407801f3b7921e6e8afd3d92889bc0 100644 (file)
@@ -59,6 +59,7 @@ enum dc_status {
        DC_FAIL_DP_PAYLOAD_ALLOCATION = 27,
        DC_FAIL_DP_LINK_BANDWIDTH = 28,
        DC_FAIL_HW_CURSOR_SUPPORT = 29,
+       DC_FAIL_DP_TUNNEL_BW_VALIDATE = 30,
        DC_ERROR_UNEXPECTED = -1
 };
 
index 7d16351bba9902cc1ede31094d5884b578cb4b08..c92f11095254d17602e8ad173cedbf1a5cbcbf70 100644 (file)
@@ -147,6 +147,9 @@ struct link_service {
        bool (*validate_dpia_bandwidth)(
                        const struct dc_stream_state *stream,
                        const unsigned int num_streams);
+       enum dc_status (*validate_dp_tunnel_bandwidth)(
+               const struct dc *dc,
+               const struct dc_state *new_ctx);
 
        uint32_t (*dp_required_hblank_size_bytes)(
                const struct dc_link *link,
index f16cba4b9119dff4d076b474c5ed5da9113264a1..e15631bead09171942fbc1d89c368dfea5831956 100644 (file)
@@ -2295,12 +2295,10 @@ static bool allocate_usb4_bandwidth_for_stream(struct dc_stream_state *stream, i
                }
 
                link->dpia_bw_alloc_config.remote_sink_req_bw[sink_index] = bw;
+               link->dpia_bw_alloc_config.dp_overhead = link_dpia_get_dp_mst_overhead(link);
+               req_bw += link->dpia_bw_alloc_config.dp_overhead;
        }
 
-       /* get dp overhead for dp tunneling */
-       link->dpia_bw_alloc_config.dp_overhead = link_dp_dpia_get_dp_overhead_in_dp_tunneling(link);
-       req_bw += link->dpia_bw_alloc_config.dp_overhead;
-
        link_dp_dpia_allocate_usb4_bandwidth_for_stream(link, req_bw);
 
        if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
index 1a04f4b7458593ed5560b143cd4fabc3c3cec425..3ef2013508a4503d5bcaa818ea03601d86a45dc1 100644 (file)
@@ -101,6 +101,7 @@ static void construct_link_service_validation(struct link_service *link_srv)
        link_srv->validate_mode_timing = link_validate_mode_timing;
        link_srv->dp_link_bandwidth_kbps = dp_link_bandwidth_kbps;
        link_srv->validate_dpia_bandwidth = link_validate_dpia_bandwidth;
+       link_srv->validate_dp_tunnel_bandwidth = link_validate_dp_tunnel_bandwidth;
        link_srv->dp_required_hblank_size_bytes = dp_required_hblank_size_bytes;
 }
 
index e2235fd32998c94eb6716995092db83c2e9bde50..5b88a1c48dace55fa23f476633c9167e392880f0 100644 (file)
@@ -263,6 +263,14 @@ uint32_t dp_link_bandwidth_kbps(
        return link_rate_per_lane_kbps * link_settings->lane_count / 10000 * total_data_bw_efficiency_x10000;
 }
 
+static uint32_t dp_get_timing_bandwidth_kbps(
+       const struct dc_crtc_timing *timing,
+       const struct dc_link *link)
+{
+       return dc_bandwidth_in_kbps_from_timing(timing,
+                       dc_link_get_highest_encoding_format(link));
+}
+
 static bool dp_validate_mode_timing(
        struct dc_link *link,
        const struct dc_crtc_timing *timing)
@@ -411,13 +419,88 @@ bool link_validate_dpia_bandwidth(const struct dc_stream_state *stream, const un
        for (uint8_t i = 0; i < num_dpias; ++i) {
                int dp_overhead = 0;
 
-               dp_overhead = link_dp_dpia_get_dp_overhead_in_dp_tunneling(dpia_link[i]);
+               dp_overhead = link_dpia_get_dp_mst_overhead(dpia_link[i]);
                bw_needed[i] += dp_overhead;
        }
 
        return dpia_validate_usb4_bw(dpia_link, bw_needed, num_dpias);
 }
 
+static const struct dc_tunnel_settings *get_dp_tunnel_settings(const struct dc_state *context,
+               const struct dc_stream_state *stream)
+{
+       int i;
+       const struct dc_tunnel_settings *dp_tunnel_settings = NULL;
+
+       for (i = 0; i < MAX_PIPES; i++) {
+               if (context->res_ctx.pipe_ctx[i].stream && (context->res_ctx.pipe_ctx[i].stream == stream)) {
+                       dp_tunnel_settings = &context->res_ctx.pipe_ctx[i].link_config.dp_tunnel_settings;
+                       break;
+               }
+       }
+
+       return dp_tunnel_settings;
+}
+
+/*
+ * Calculates the DP tunneling bandwidth required for the stream timing
+ * and aggregates the stream bandwidth for the respective DP tunneling link
+ *
+ * return: dc_status
+ */
+enum dc_status link_validate_dp_tunnel_bandwidth(const struct dc *dc, const struct dc_state *new_ctx)
+{
+       struct dc_validation_dpia_set dpia_link_sets[MAX_DPIA_NUM] = { 0 };
+       uint8_t link_count = 0;
+       enum dc_status result = DC_OK;
+
+       for (uint8_t i = 0; (i < MAX_PIPES && i < new_ctx->stream_count); i++) {
+               const struct dc_stream_state *stream = new_ctx->streams[i];
+               const struct dc_link *link;
+               const struct dc_tunnel_settings *dp_tunnel_settings;
+               uint32_t timing_bw;
+
+               if (stream == NULL)
+                       continue;
+
+               link = stream->link;
+
+               if (!(link && (stream->signal == SIGNAL_TYPE_DISPLAY_PORT
+                               || stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
+                               && link->hpd_status))
+                       continue;
+
+               dp_tunnel_settings = get_dp_tunnel_settings(new_ctx, stream);
+
+               if ((dp_tunnel_settings == NULL) || (dp_tunnel_settings->should_use_dp_bw_allocation == false))
+                       continue;
+
+               timing_bw = dp_get_timing_bandwidth_kbps(&stream->timing, link);
+
+               for (uint8_t j = 0; j < MAX_DPIA_NUM; j++) {
+                       bool is_new_slot = false;
+
+                       if (dpia_link_sets[j].link == NULL) {
+                               is_new_slot = true;
+                               link_count++;
+                               dpia_link_sets[j].required_bw = 0;
+                               dpia_link_sets[j].link = link;
+                       }
+
+                       if (is_new_slot || (dpia_link_sets[j].link == link)) {
+                               dpia_link_sets[j].tunnel_settings = dp_tunnel_settings;
+                               dpia_link_sets[j].required_bw += timing_bw;
+                               break;
+                       }
+               }
+       }
+
+       if (link_count && link_dpia_validate_dp_tunnel_bandwidth(dpia_link_sets, link_count) == false)
+               result = DC_FAIL_DP_TUNNEL_BW_VALIDATE;
+
+       return result;
+}
+
 struct dp_audio_layout_config {
        uint8_t layouts_per_sample_denom;
        uint8_t symbols_per_layout;
index bf398c49c3e8674d48b2aff732ad270e0546b331..2a6ccded23df67c3a722eba19c0ebb686b3c5206 100644 (file)
@@ -33,6 +33,9 @@ enum dc_status link_validate_mode_timing(
 bool link_validate_dpia_bandwidth(
                const struct dc_stream_state *stream,
                const unsigned int num_streams);
+enum dc_status link_validate_dp_tunnel_bandwidth(
+               const struct dc *dc,
+               const struct dc_state *new_ctx);
 uint32_t dp_link_bandwidth_kbps(
        const struct dc_link *link,
        const struct dc_link_settings *link_settings);
index 22bfdced64ab6afb82f82a143890b1be70e294dc..9b2f1a7da1d12f67c974f3a94e259d7d63cbdb96 100644 (file)
@@ -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;
+               }
        }
 }
 
index 642feac5a6737eaa68d526ac28acb15d51cb02b1..cc1f4e6196edb47d347b4993993c1b9f18a5ecaa 100644 (file)
@@ -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;
-
-       if (!link_dp_is_bw_alloc_available(link))
-               return dp_overhead;
+       uint32_t link_mst_overhead = 0;
 
-       /* 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 link_mst_overhead;
+}
 
-       return dp_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;
 }
+
index 801965b5f9a4addb174a93b23c190386c838e9b8..5b5b37486b89f1d23d30ca2901dbfd513a7a09f2 100644 (file)
 
 #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_ */
+