[PATCH linux dev-5.10 v3 10/18] ipmi: kcs_bmc: Don't enforce single-open policy in the kernel

William Kennington wak at google.com
Mon May 10 18:56:40 AEST 2021


Why would we want to change this? I personally think the original
mutual exclusion policy makes even more sense with multiple client
types, so that the upstack programs actually know when they are being
locked out. Having clients that are able to open the fd but remain
broken if they don't do higher level synchronization just feels like a
good way to have hard to understand behavior.

On Sun, May 9, 2021 at 11:56 PM Andrew Jeffery <andrew at aj.id.au> wrote:
>
> Soon it will be possible for one KCS device to have multiple associated
> chardevs exposed to userspace (for IPMI and raw-style access). However,
> don't prevent userspace from:
>
> 1. Opening more than one chardev at a time, or
> 2. Opening the same chardev more than once.
>
> System behaviour is undefined for both classes of multiple access, so
> userspace must manage itself accordingly.
>
> The implementation delivers IBF and OBF events to the first chardev
> client to associate with the KCS device. An open on a related chardev
> cannot associate its client with the KCS device and so will not
> receive notification of events. However, any fd on any chardev may race
> their accesses to the data and status registers.
>
> Signed-off-by: Andrew Jeffery <andrew at aj.id.au>
> ---
>  drivers/char/ipmi/kcs_bmc.c         | 34 ++++++++++-------------------
>  drivers/char/ipmi/kcs_bmc_aspeed.c  |  3 +--
>  drivers/char/ipmi/kcs_bmc_npcm7xx.c |  3 +--
>  3 files changed, 14 insertions(+), 26 deletions(-)
>
> diff --git a/drivers/char/ipmi/kcs_bmc.c b/drivers/char/ipmi/kcs_bmc.c
> index 7081541bb6ce..ad9ff13ba831 100644
> --- a/drivers/char/ipmi/kcs_bmc.c
> +++ b/drivers/char/ipmi/kcs_bmc.c
> @@ -55,24 +55,12 @@ EXPORT_SYMBOL(kcs_bmc_update_status);
>  irqreturn_t kcs_bmc_handle_event(struct kcs_bmc_device *kcs_bmc)
>  {
>         struct kcs_bmc_client *client;
> -       irqreturn_t rc;
> +       irqreturn_t rc = IRQ_NONE;
>
>         spin_lock(&kcs_bmc->lock);
>         client = kcs_bmc->client;
> -       if (client) {
> +       if (client)
>                 rc = client->ops->event(client);
> -       } else {
> -               u8 status;
> -
> -               status = kcs_bmc_read_status(kcs_bmc);
> -               if (status & KCS_BMC_STR_IBF) {
> -                       /* Ack the event by reading the data */
> -                       kcs_bmc_read_data(kcs_bmc);
> -                       rc = IRQ_HANDLED;
> -               } else {
> -                       rc = IRQ_NONE;
> -               }
> -       }
>         spin_unlock(&kcs_bmc->lock);
>
>         return rc;
> @@ -81,26 +69,28 @@ EXPORT_SYMBOL(kcs_bmc_handle_event);
>
>  int kcs_bmc_enable_device(struct kcs_bmc_device *kcs_bmc, struct kcs_bmc_client *client)
>  {
> -       int rc;
> -
>         spin_lock_irq(&kcs_bmc->lock);
> -       if (kcs_bmc->client) {
> -               rc = -EBUSY;
> -       } else {
> +       if (!kcs_bmc->client) {
> +               u8 mask = KCS_BMC_EVENT_TYPE_IBF;
> +
>                 kcs_bmc->client = client;
> -               rc = 0;
> +               kcs_bmc_update_event_mask(kcs_bmc, mask, mask);
>         }
>         spin_unlock_irq(&kcs_bmc->lock);
>
> -       return rc;
> +       return 0;
>  }
>  EXPORT_SYMBOL(kcs_bmc_enable_device);
>
>  void kcs_bmc_disable_device(struct kcs_bmc_device *kcs_bmc, struct kcs_bmc_client *client)
>  {
>         spin_lock_irq(&kcs_bmc->lock);
> -       if (client == kcs_bmc->client)
> +       if (client == kcs_bmc->client) {
> +               u8 mask = KCS_BMC_EVENT_TYPE_IBF | KCS_BMC_EVENT_TYPE_OBE;
> +
> +               kcs_bmc_update_event_mask(kcs_bmc, mask, 0);
>                 kcs_bmc->client = NULL;
> +       }
>         spin_unlock_irq(&kcs_bmc->lock);
>  }
>  EXPORT_SYMBOL(kcs_bmc_disable_device);
> diff --git a/drivers/char/ipmi/kcs_bmc_aspeed.c b/drivers/char/ipmi/kcs_bmc_aspeed.c
> index fade0e2faf2c..2c88b34b803c 100644
> --- a/drivers/char/ipmi/kcs_bmc_aspeed.c
> +++ b/drivers/char/ipmi/kcs_bmc_aspeed.c
> @@ -414,8 +414,7 @@ static int aspeed_kcs_probe(struct platform_device *pdev)
>
>         platform_set_drvdata(pdev, priv);
>
> -       aspeed_kcs_irq_mask_update(kcs_bmc, (KCS_BMC_EVENT_TYPE_IBF | KCS_BMC_EVENT_TYPE_OBE),
> -                                  KCS_BMC_EVENT_TYPE_IBF);
> +       aspeed_kcs_irq_mask_update(kcs_bmc, (KCS_BMC_EVENT_TYPE_IBF | KCS_BMC_EVENT_TYPE_OBE), 0);
>         aspeed_kcs_enable_channel(kcs_bmc, true);
>
>         kcs_bmc_add_device(&priv->kcs_bmc);
> diff --git a/drivers/char/ipmi/kcs_bmc_npcm7xx.c b/drivers/char/ipmi/kcs_bmc_npcm7xx.c
> index f8b7162fb830..ab4a8caf1270 100644
> --- a/drivers/char/ipmi/kcs_bmc_npcm7xx.c
> +++ b/drivers/char/ipmi/kcs_bmc_npcm7xx.c
> @@ -202,8 +202,7 @@ static int npcm7xx_kcs_probe(struct platform_device *pdev)
>         if (rc)
>                 return rc;
>
> -       npcm7xx_kcs_irq_mask_update(kcs_bmc, (KCS_BMC_EVENT_TYPE_IBF | KCS_BMC_EVENT_TYPE_OBE),
> -                                   KCS_BMC_EVENT_TYPE_IBF);
> +       npcm7xx_kcs_irq_mask_update(kcs_bmc, (KCS_BMC_EVENT_TYPE_IBF | KCS_BMC_EVENT_TYPE_OBE), 0);
>         npcm7xx_kcs_enable_channel(kcs_bmc, true);
>
>         pr_info("channel=%u idr=0x%x odr=0x%x str=0x%x\n",
> --
> 2.27.0
>


More information about the openbmc mailing list