Re: [PATCH for drm-misc-fixes v4 2/4] drm/hisilicon/hibmc: fix no showing when no connectors connected
From: Yongbang Shi
Date: Tue Apr 21 2026 - 03:34:30 EST
> Hi
>
> Am 20.04.26 um 16:00 schrieb Yongbang Shi:
>>> Hi
>>>
>>> Am 20.04.26 um 10:40 schrieb Yongbang Shi:
>>> [...]
>>>> From the patch you contributed,,I understand that you are using an
>>>> RH1288H V3 server. I have confirmed with our chief hardware engineer
>>>> that the board design for this series of servers does not connect the
>>>> BMC chip’s DDC I2C to the VGA port.
>>> Thanks a lot for double-checking. That's the info I was missing. I suggest to build a workaround into the driver to
>>> filter out these boards and always return 'connected' on them. IIUC even with these new callbacks, the driver would not
>>> work as expected.
>>>
>> Our BMC chips can distinguish between generations, but since BMC chips of the same generation are used on many different
>
> That's not really much of a problem. Just filter the older boards by some board identifier and handle it separately. We
> use that all over the kernel; including graphics drives. See for example DMI_MATCH. [1]
>
Okay, we'll need to verify this with the BIOS and do some analysis. If necessary, we'll submit a patch as a feature
later on.
> [1] https://elixir.bootlin.com/linux/v7.0/A/ident/DMI_MATCH
>
>> boards, filtering by board type or board id is not feasible. We can only determine whether DDC I2C is present by
>> comparing BMC chips of different generations. We have mandated that the board implementation must connect to DDC I2C on
>> the latest BMC chip.
>>
>>>> [1]https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/drivers/gpu/drm/hisilicon/hibmc/
>>>> hibmc_drm_vdac.c?h=v6.12.82#L60
>>>> [2]https://lore.kernel.org/all/20250320101455.2538835-10-shiyongbang@xxxxxxxxxx/
>>>>
>>>>
>>>>>> Signed-off-by: Lin He <helin52@xxxxxxxxxx>
>>>>>> Signed-off-by: Yongbang Shi <shiyongbang@xxxxxxxxxx>
>>>>>> ---
>>>>> [...]
>>>>>> +static int hibmc_vdac_detect(struct drm_connector *connector,
>>>>>> + struct drm_modeset_acquire_ctx *ctx,
>>>>>> + bool force)
>>>>>> +{
>>>>>> + struct hibmc_drm_private *priv = to_hibmc_drm_private(connector-
>>>>>>> dev);
>>>>>> + struct hibmc_vdac *vdac = to_hibmc_vdac(connector);
>>>>>> +
>>>>>> + vdac->phys_state = drm_connector_helper_detect_from_ddc(connector,
>>>>>> + ctx, force);
>>>>>> +
>>>>>> + /* If the DP connectors are disconnected, the hibmc_vdac_detect
>>>>>> function
>>>>>> + * must return a connected state to ensure KVM display
>>>>>> functionality.
>>>>>> + * Additionally, for previous-generation products that may lack
>>>>>> hardware
>>>>>> + * link support and thus cannot detect the monitor,
>>>>>> hibmc_vdac_detect
>>>>>> + * should also return a connected state.
>>>>>> + */
>>>>>> + if (priv->dp.phys_state != connector_status_connected)
>>>>>> + return connector_status_connected;
>>>>>> +
>>>>>> + return vdac->phys_state;
>>>>> This will break user-space compositors if DP and VGA are connected at
>>>>> the same time. I know, because we had such logic in ast and mgag200.
>>>>>
>>>>> Today's compositors expect a single encoder-connector pair on each CRTC.
>>>>> That's what most contemporary hardware provides. But the server
>>>>> chipsets usually come with one a single CRTC and multiple connectors
>>>>> attached to it. Compositors fail to configure that. When we had this in
>>>>> ast and mgag200, Gnome would display garbage to the screen and mode-
>>>>> setting would fail. The bug report is at [1].
>>>>>
>>>>> In ast and mgag200, only one connector would be installed on a single
>>>>> system. So we could avoid the problem. It looks like that this is not an
>>>>> option with hibmc. VGA always seems to be present and DP seems optional.
>>>>> I would advice to only report one of the connectors as 'connected' if
>>>>> both are installed on a system.
>>>>>
>>>> According to our BMC chip specifications, both VGA and DisplayPort
>>>> outputs are required, but only one connection is allowed at a time,
>>>> which seems impractical.
>>> That's true.
>>>
>>> Yet it needs support form user space to make it work. It's not a kernel problem.
>>>
>>>> Do you have any additional details regarding this issue with the Mutter
>>>> synthesizer? For example, steps to reproduce the issue or more specific
>>>> alert logs. I looked at the issue you submitted to Mutter, which
>>>> describes the phenomenon as "a warning that the configuration is
>>>> incompatible", Could you clarify what this warning specifically refers
>>>> to—is it a message displayed on the screen, or is it a specific entry in
>>>> the logs?
>>> In ast, we used to have at least one connector for the physical output and another connector for the BMC/KVM. Running
>>> Gnome and opening the Settings app did not work correctly. One issue is that display configuration could not be changed
>>> in Gnome. That's the reported error of changes not being applicable.
>>>
>> Great, regarding hibmc-drm's support for DP, my initial idea was also to create separate connectors for DP, VGA, and
>> KVM. However, due to some non-technical reasons, that approach wasn't implemented. Since ast has implemented it this
>> way, we can also consider this solution.
>
> I added a connector for the KVM to ast, but it turned out to be a mistake, as it triggered these user-space bugs. Hence
> the current design in ast. The KVM isn't really a connector. It's more of a bridge, but next to the CRTC instead of next
> to the connector; like this:
>
> Plane -> CRTC -> KVM-bridge -> encoders -> connectors
>
> We have no good way of modelling this pipeline in DRM.
>
> In the case of ast and mgag200, the BMC also cannot be disabled. For a real connector, one would expect that it can be
> disabled. This might also confuse compositors.
>
Okay, got it.
>
>>
>>> IIRC I've also seen distorted output if I really pushed it. But maybe that has meanwhile been mitigated.
>>>
>>> I've been told that other compositors also don't support this scenario well.
>>>
>>> I think you'd run into this case once someone connects the DP and VGA at the same time.
>>>
>> Okay, I understand. However, so far, we have thoroughly tested the scenario where both connector0 (VGA shared with KVM)
>> and connector1 (DP) are displaying at the same time, and we haven’t encountered any similar issues.
>
> If this works for you, then let's keep it. I'm just trying to help you avoid the pitfalls we have seen with other drivers.
>
>
>>
>> I will create a dedicated connector for the KVM and conduct the necessary tests to test for this scenario.
>
> I think the design in the current patch is sound. It just needs to increment epoch_count if the physical status changes;
> and it would trigger these user-space bugs. But we can only work around the latter.
>
Okay, I understand, but there's one more thing I need to confirm: simply adding logic to increment `epoch_count` within
`vdac_detect` isn't enough, is it? We still need to enable the `connector.polled` mechanism for periodic detection, right?
like this:
hibmc_kms_init()
{
...
drm_kms_helper_poll_init(dev);
...
}
a little change like this:
vdac_detect()
{
phys_state = detect_from_hw()
if (dp.phys_state == connected) {
vdac->phys_state = phys_state;
return vdac->phys_state; /* return from here, epoch_counter will be update by drm framework */
}
if (phys_state != vdac->phys_state)
++epoch_counter;
vdac->phys_state = phys_state;
return connector_status_connected;
}
Thanks,
Yongbang.
> Best regards
> Thomas
>
>
>>
>>>> Over the next few days, we will focus on testing relevant scenarios
>>>> while setting both the VGA and DP ports to `connected` to see if we
>>>> encounter similar issues or warnings.
>>>>
>>>>> You also need to increment the connector's epoch_counter if the physical
>>>>> status changed. Doing this will trigger DRM clients to re-read the
>>>>> connector state and reconfigure display.
>>>>>
>>>>> Something like that
>>>>>
>>>>> dp_detect()
>>>>> {
>>>>> dp.phys_state = detect_from_hw()
>>>>>
>>>>> if (dp.phys_state changed)
>>>>> ++epoch_counter
>>>>> return connected
>>>>> }
>>>>>
>>>>> vdac_detect()
>>>>> {
>>>>> if (dp.phys_state == connected)
>>>>> return disconnected
>>>>>
>>>> Only one option is displayed here, but it does not meet our specifications.
>>>>
>>>>> vdac.phys_state = detect_from_hw()
>>>>>
>>>>> if (vdac.phys_state changed)
>>>>> ++epoch_counter
>>>>> return connected
>>>>> }
>>>>>
>>>>> This handles the KVM in each connector's helper. The ast driver is
>>>>> probably the best reference for the current logic. See [2].
>>>>>
>>>> I looked at the implementations of `detect_ctx` in ATS and MGAG200;
>>>> these implementations generally always return `connected`.
>>>>
>>>> If my analysis is correct, the logic should be as follows:
>>>> - If the `detect_ctx` function implemented by each vendor returns the
>>>> actual hardware state, there is no need to modify `epoch_counter`;
>>>> the DRM framework will execute `epoch_counter++` based on the return
>>>> value of the `detect_ctx` function;
>>>>
>>>> - If the `detect_ctx` function in a vendor’s code always returns
>>>> `connected`, then `epoch_counter++` must be performed within the
>>>> vendor’s `detect_ctx` function; the implementations in ATS and
>>>> MGAG200 appear to be like this;
>>> Exactly. In ast/mgag200, we had the case that the VGA got disconnected. We'd still return connected, as the BMC/KVM was
>>> present. We now had to reconfigure for the KVM. That requires modifying epoch_counter. You can see at [1] that we only
>>> increment if the physical status changes. [1] Same goes for re-connecting the VGA display.
>>>
>>> [1] https://elixir.bootlin.com/linux/v7.0/source/drivers/gpu/drm/ast/ast_vga.c#L56
>>>
>>>>
>>>> Here is the pseudocode for our current logic. This logic is indeed a bit
>>>> hard to grasp, so I've added some more comments; it might be a bit
>>>> clearer than the patch:
>>>>
>>>> dp_detect()
>>>> {
>>>> dp.phys_state = detect_from_hw()
>>>> /* epoch_counter update by drm framework */
>>>> return dp.phys_state;
>>>> }
>>>>
>>>> vdac_detect()
>>>> {
>>>> /*
>>>> * Scene 1: The driver runs on an older version of the BMC chip,
>>>> * and `dp.phys_state` is initialized to 0. To maintain
>>>> * consistency with the previous hibmc-drm driver
>>>> * logic, always return `connected`.
>>>> * Scene 2: The driver runs on an new version of the BMC chip,
>>>> * and `dp.phys_state` is real status, witch is real
>>>> * `disconnect`. In this scenario, we must ensure that
>>>> * the VGA is `connected` to guarantee that the KVM
>>>> * displays properly.
>>>> */
>>>> if (dp.phys_state != connected)
>>>> return connected;
>>>>
>>>> /*
>>>> * DP is connected: This driver is definitely running on the
>>>> * latest BMC chip, and the DDC I2C is definitely
>>>> * connected to the VGA port, so we can confirm whether
>>>> * the VGA is present by reading the EDID directly via
>>>> * I2C.
>>>> */
>>>> vdac.phys_state = detect_from_hw()
>>>> /* epoch_counter update by drm framework */
>>>> return vdac.phys_state;
>>> Let's assume the DP is disconnected. If VGA's physical status goes from connected to disconnected, user space will not
>>> know that it needs to reconfigure for the BMC. (or vice versa)
>>>
>>> To give you some context from earlier discussions around the other drivers: We had the scenario that the user boots up
>>> without a connected VGA display. This would enable the BMC, which sometimes picks a large resolution; say >2k per
>>> dimension. That is problematic for KVM over networks. And if the user now plugs in a physical VGA display, they would be
>>> stuck with the large resolution on the framebuffer console. Maybe the VGA display wouldn't even support such a high-res
>>> mode. So we set the default for the BMC to 1024x768. That is well manageable for all of today's VGA displays and does
>>> not impose too much overhead for KVM over networks. As a drawback, it's a bit small on monitors and not nice to look
>>> at. So we modify epoch_counter whenever the physical status changes. This triggers compositors to reconfigure their
>>> screens for the new display.
>>>
>> Yes, this issue does exist. If we uses the `connector.polled` mechanism to monitor the VGA's presence in real time and
>> update the `epoch_counter`, which might resolve the issue. However, upon further consideration, I don't think this is
>> the optimal solution. If we create a separate connector for KVM and distinguish between older-generation BMC chips and
>> newer-generation BMC chips, the problem will be easily solved. In addition, DP and VGA, as well as VGA and KVM, will be
>> decoupled.
>>
>> A temporary solution:
>> /* called by poll work */
>> vdac_detect()
>> {
>> /* Let’s examine this logic on its own to gain a better understanding. */
>> if (older-generation)
>> return connected;
>>
>> vdac.phys_state = detect_from_hw();
>> if (vdac.phys_state changed)
>> ++epoch_counter;
>>
>> if (dp.phys_state != connected) {
>> return connected;
>> }
>>
>> return vdac.phys_state;
>> }
>>
>>
>> A more elegant solution:
>> |--connector0(KVM): always connected, do not update epoch_counter.
>> |
>> crtc--|--connector1(VGA): detect real time by `connector.polled`, update epoch_counter.
>> |
>> |--connector1(DP): detect real time by hpd interrupt, update epoch_counter.
>>
>> kvm_detect()
>> {
>> return connected;
>> }
>>
>> /* called by poll work */
>> vdac_detect()
>> {
>> /* for older-generation */
>> if (older-generation)
>> return connected;
>>
>> /* for newer-generation */
>> vdac.phys_state = detect_from_hw();
>>
>> /* epoch_counter update by drm framework */
>> return vdac.phys_state;
>> }
>>
>> dp_detect()
>> {
>> dp.phys_state = detect_from_hw();
>>
>> /* epoch_counter update by drm framework */
>> return dp.phys_state;
>> }
>>
>> Thanks,
>> Yongbang.
>>
>>> Best regards
>>> Thomas
>>>
>>>> }
>>>>
>>>> Sorry for the delay; it took me a little while to figure out how best to
>>>> explain this bug and our current implementation.
>>>>
>>>> Thanks,
>>>> Yongbang.
>>>>
>>>>> [1] https://gitlab.gnome.org/GNOME/mutter/-/issues/3858
>>>>> [2] https://elixir.bootlin.com/linux/v7.0/source/drivers/gpu/drm/ast/
>>>>> ast_vga.c#L47
>>>>>
>>>>> Best regards
>>>>> Thomas
>>>>>
>>>>>> +}
>>>>>> +
>>>>>> static const struct drm_connector_helper_funcs
>>>>>> hibmc_connector_helper_funcs = {
>>>>>> .get_modes = hibmc_connector_get_modes,
>>>>>> - .detect_ctx = drm_connector_helper_detect_from_ddc,
>>>>>> + .detect_ctx = hibmc_vdac_detect,
>>>>>> };
>>>>>> static const struct drm_connector_funcs hibmc_connector_funcs = {
>>>>>> @@ -130,6 +145,8 @@ int hibmc_vdac_init(struct hibmc_drm_private *priv)
>>>>>> connector->polled = DRM_CONNECTOR_POLL_CONNECT |
>>>>>> DRM_CONNECTOR_POLL_DISCONNECT;
>>>>>> + vdac->phys_state = connector_status_connected;
>>>>>> +
>>>>>> return 0;
>>>>>> err:
>