diff mbox series

lib: sbi: Ensure SBI extension is available

Message ID 20230426172753.70664-1-ajones@ventanamicro.com
State Superseded
Headers show
Series lib: sbi: Ensure SBI extension is available | expand

Commit Message

Andrew Jones April 26, 2023, 5:27 p.m. UTC
Ensure attempts to invoke SBI extension functions fail with
SBI_ERR_NOT_SUPPORTED when the extension's probe function has
reported that the extension is not available. By adding a new
status member to the extension which has three states
(uninitialized, available, unavailable), we ensure that the
probe function is only invoked once, lazily, upon first use.

Signed-off-by: Andrew Jones <ajones@ventanamicro.com>
---
 include/sbi/sbi_ecall.h |  6 ++++++
 lib/sbi/sbi_ecall.c     | 18 ++++++++++++++----
 2 files changed, 20 insertions(+), 4 deletions(-)

Comments

Xiang W April 27, 2023, 1:02 a.m. UTC | #1
在 2023-04-26星期三的 19:27 +0200,Andrew Jones写道:
> Ensure attempts to invoke SBI extension functions fail with
> SBI_ERR_NOT_SUPPORTED when the extension's probe function has
> reported that the extension is not available. By adding a new
> status member to the extension which has three states
> (uninitialized, available, unavailable), we ensure that the
> probe function is only invoked once, lazily, upon first use.

Adding this state may cause errors. For example: the id numberof an extension is from extid_start to extid_end, which has an
unused ID. Searching for an ID in this extension will return NULL
if an unused ID is searched first.

Regards,
Xiang W
> 
> Signed-off-by: Andrew Jones <ajones@ventanamicro.com>
> ---
>  include/sbi/sbi_ecall.h |  6 ++++++
>  lib/sbi/sbi_ecall.c     | 18 ++++++++++++++----
>  2 files changed, 20 insertions(+), 4 deletions(-)
> 
> diff --git a/include/sbi/sbi_ecall.h b/include/sbi/sbi_ecall.h
> index ff9bf8e2b435..8e31d0d91620 100644
> --- a/include/sbi/sbi_ecall.h
> +++ b/include/sbi/sbi_ecall.h
> @@ -20,10 +20,16 @@
>  struct sbi_trap_regs;
>  struct sbi_trap_info;
>  
> +enum sbi_ext_status {
> +       SBI_EXT_AVAILABLE = 1,
> +       SBI_EXT_UNAVAILABLE,
> +};
> +
>  struct sbi_ecall_extension {
>         struct sbi_dlist head;
>         unsigned long extid_start;
>         unsigned long extid_end;
> +       enum sbi_ext_status status;
>         int (* probe)(unsigned long extid, unsigned long *out_val);
>         int (* handle)(unsigned long extid, unsigned long funcid,
>                        const struct sbi_trap_regs *regs,
> diff --git a/lib/sbi/sbi_ecall.c b/lib/sbi/sbi_ecall.c
> index 76a1ae9ab733..20ff06f32dad 100644
> --- a/lib/sbi/sbi_ecall.c
> +++ b/lib/sbi/sbi_ecall.c
> @@ -42,16 +42,26 @@ static SBI_LIST_HEAD(ecall_exts_list);
>  
>  struct sbi_ecall_extension *sbi_ecall_find_extension(unsigned long extid)
>  {
> -       struct sbi_ecall_extension *t, *ret = NULL;
> +       struct sbi_ecall_extension *t;
> +       unsigned long out_val;
>  
>         sbi_list_for_each_entry(t, &ecall_exts_list, head) {
>                 if (t->extid_start <= extid && extid <= t->extid_end) {
> -                       ret = t;
> -                       break;
> +                       if (t->status == SBI_EXT_AVAILABLE)
> +                               return t;
> +                       if (t->status == SBI_EXT_UNAVAILABLE)
> +                               return NULL;
> +                       if (t->probe && (t->probe(extid, &out_val) || !out_val)) {
> +                               t->status = SBI_EXT_UNAVAILABLE;
> +                               return NULL;
> +                       }
> +
> +                       t->status = SBI_EXT_AVAILABLE;
> +                       return t;
>                 }
>         }
>  
> -       return ret;
> +       return NULL;
>  }
>  
>  int sbi_ecall_register_extension(struct sbi_ecall_extension *ext)
> -- 
> 2.39.2
> 
>
Andrew Jones April 27, 2023, 7 a.m. UTC | #2
On Thu, Apr 27, 2023 at 09:02:14AM +0800, Xiang W wrote:
> 在 2023-04-26星期三的 19:27 +0200,Andrew Jones写道:
> > Ensure attempts to invoke SBI extension functions fail with
> > SBI_ERR_NOT_SUPPORTED when the extension's probe function has
> > reported that the extension is not available. By adding a new
> > status member to the extension which has three states
> > (uninitialized, available, unavailable), we ensure that the
> > probe function is only invoked once, lazily, upon first use.
> 
> Adding this state may cause errors. For example: the id numberof an extension is from extid_start to extid_end, which has an
> unused ID. Searching for an ID in this extension will return NULL
> if an unused ID is searched first.

Hi Xiang,

You're right. Either sbi_ecall_extension::status needs to be a function of
extid, like probe is, or we should just always call probe (when it's
available) and leave any optimizations to the individual probe functions.
How about this?

diff --git a/lib/sbi/sbi_ecall.c b/lib/sbi/sbi_ecall.c
index 76a1ae9ab733..c86e4e8c9134 100644
--- a/lib/sbi/sbi_ecall.c
+++ b/lib/sbi/sbi_ecall.c
@@ -42,16 +42,18 @@ static SBI_LIST_HEAD(ecall_exts_list);
 
 struct sbi_ecall_extension *sbi_ecall_find_extension(unsigned long extid)
 {
-	struct sbi_ecall_extension *t, *ret = NULL;
+	struct sbi_ecall_extension *t;
+	unsigned long out_val;
 
 	sbi_list_for_each_entry(t, &ecall_exts_list, head) {
 		if (t->extid_start <= extid && extid <= t->extid_end) {
-			ret = t;
-			break;
+			if (t->probe && (t->probe(extid, &out_val) || !out_val))
+				return NULL;
+			return t;
 		}
 	}
 
-	return ret;
+	return NULL;
 }
 
 int sbi_ecall_register_extension(struct sbi_ecall_extension *ext)

Thanks,
drew

> 
> Regards,
> Xiang W
> > 
> > Signed-off-by: Andrew Jones <ajones@ventanamicro.com>
> > ---
> >  include/sbi/sbi_ecall.h |  6 ++++++
> >  lib/sbi/sbi_ecall.c     | 18 ++++++++++++++----
> >  2 files changed, 20 insertions(+), 4 deletions(-)
> > 
> > diff --git a/include/sbi/sbi_ecall.h b/include/sbi/sbi_ecall.h
> > index ff9bf8e2b435..8e31d0d91620 100644
> > --- a/include/sbi/sbi_ecall.h
> > +++ b/include/sbi/sbi_ecall.h
> > @@ -20,10 +20,16 @@
> >  struct sbi_trap_regs;
> >  struct sbi_trap_info;
> >  
> > +enum sbi_ext_status {
> > +       SBI_EXT_AVAILABLE = 1,
> > +       SBI_EXT_UNAVAILABLE,
> > +};
> > +
> >  struct sbi_ecall_extension {
> >         struct sbi_dlist head;
> >         unsigned long extid_start;
> >         unsigned long extid_end;
> > +       enum sbi_ext_status status;
> >         int (* probe)(unsigned long extid, unsigned long *out_val);
> >         int (* handle)(unsigned long extid, unsigned long funcid,
> >                        const struct sbi_trap_regs *regs,
> > diff --git a/lib/sbi/sbi_ecall.c b/lib/sbi/sbi_ecall.c
> > index 76a1ae9ab733..20ff06f32dad 100644
> > --- a/lib/sbi/sbi_ecall.c
> > +++ b/lib/sbi/sbi_ecall.c
> > @@ -42,16 +42,26 @@ static SBI_LIST_HEAD(ecall_exts_list);
> >  
> >  struct sbi_ecall_extension *sbi_ecall_find_extension(unsigned long extid)
> >  {
> > -       struct sbi_ecall_extension *t, *ret = NULL;
> > +       struct sbi_ecall_extension *t;
> > +       unsigned long out_val;
> >  
> >         sbi_list_for_each_entry(t, &ecall_exts_list, head) {
> >                 if (t->extid_start <= extid && extid <= t->extid_end) {
> > -                       ret = t;
> > -                       break;
> > +                       if (t->status == SBI_EXT_AVAILABLE)
> > +                               return t;
> > +                       if (t->status == SBI_EXT_UNAVAILABLE)
> > +                               return NULL;
> > +                       if (t->probe && (t->probe(extid, &out_val) || !out_val)) {
> > +                               t->status = SBI_EXT_UNAVAILABLE;
> > +                               return NULL;
> > +                       }
> > +
> > +                       t->status = SBI_EXT_AVAILABLE;
> > +                       return t;
> >                 }
> >         }
> >  
> > -       return ret;
> > +       return NULL;
> >  }
> >  
> >  int sbi_ecall_register_extension(struct sbi_ecall_extension *ext)
> > -- 
> > 2.39.2
> > 
> > 
> 
>
Andrew Jones April 27, 2023, 7:18 a.m. UTC | #3
On Thu, Apr 27, 2023 at 09:00:35AM +0200, Andrew Jones wrote:
> z4xshfbykgvcgcozn@rqv44g76lo4w>
> References: <20230426172753.70664-1-ajones@ventanamicro.com>
>  <f798c3f500849d71aba59a06d4c90ea0e4cb2071.camel@126.com>
> MIME-Version: 1.0
> Content-Type: text/plain; charset=utf-8
> Content-Disposition: inline
> Content-Transfer-Encoding: 8bit
> In-Reply-To: <f798c3f500849d71aba59a06d4c90ea0e4cb2071.camel@126.com>
> 
> On Thu, Apr 27, 2023 at 09:02:14AM +0800, Xiang W wrote:
> > 在 2023-04-26星期三的 19:27 +0200,Andrew Jones写道:
> > > Ensure attempts to invoke SBI extension functions fail with
> > > SBI_ERR_NOT_SUPPORTED when the extension's probe function has
> > > reported that the extension is not available. By adding a new
> > > status member to the extension which has three states
> > > (uninitialized, available, unavailable), we ensure that the
> > > probe function is only invoked once, lazily, upon first use.
> > 
> > Adding this state may cause errors. For example: the id numberof an extension is from extid_start to extid_end, which has an
> > unused ID. Searching for an ID in this extension will return NULL
> > if an unused ID is searched first.
> 
> Hi Xiang,
> 
> You're right. Either sbi_ecall_extension::status needs to be a function of
> extid, like probe is, or we should just always call probe (when it's
> available) and leave any optimizations to the individual probe functions.
> How about this?
> 
> diff --git a/lib/sbi/sbi_ecall.c b/lib/sbi/sbi_ecall.c
> index 76a1ae9ab733..c86e4e8c9134 100644
> --- a/lib/sbi/sbi_ecall.c
> +++ b/lib/sbi/sbi_ecall.c
> @@ -42,16 +42,18 @@ static SBI_LIST_HEAD(ecall_exts_list);
>  
>  struct sbi_ecall_extension *sbi_ecall_find_extension(unsigned long extid)
>  {
> -	struct sbi_ecall_extension *t, *ret = NULL;
> +	struct sbi_ecall_extension *t;
> +	unsigned long out_val;
>  
>  	sbi_list_for_each_entry(t, &ecall_exts_list, head) {
>  		if (t->extid_start <= extid && extid <= t->extid_end) {
> -			ret = t;
> -			break;
> +			if (t->probe && (t->probe(extid, &out_val) || !out_val))
> +				return NULL;
> +			return t;
>  		}
>  	}
>  
> -	return ret;
> +	return NULL;
>  }
>  
>  int sbi_ecall_register_extension(struct sbi_ecall_extension *ext)

And, as a separate patch, to optimize probing of srst, which has a single
extid for its range, and therefore doesn't care about it in its probe,

diff --git a/lib/sbi/sbi_ecall_srst.c b/lib/sbi/sbi_ecall_srst.c
index 93b012ce024c..f2690b80775a 100644
--- a/lib/sbi/sbi_ecall_srst.c
+++ b/lib/sbi/sbi_ecall_srst.c
@@ -50,8 +50,15 @@ static int sbi_ecall_srst_handler(unsigned long extid, unsigned long funcid,
 
 static int sbi_ecall_srst_probe(unsigned long extid, unsigned long *out_val)
 {
+	static bool probed = false;
+	static unsigned long val;
 	u32 type, count = 0;
 
+	if (probed) {
+		*out_val = val;
+		return 0;
+	}
+
 	/*
 	 * At least one standard reset types should be supported by
 	 * the platform for SBI SRST extension to be usable.
@@ -63,7 +70,8 @@ static int sbi_ecall_srst_probe(unsigned long extid, unsigned long *out_val)
 			count++;
 	}
 
-	*out_val = (count) ? 1 : 0;
+	*out_val = val = (count) ? 1 : 0;
+	probed = true;
 	return 0;
 }

And susp can be optimized in exactly the same way.

Thanks,
drew
Xiang W April 27, 2023, 7:26 a.m. UTC | #4
在 2023-04-27星期四的 09:00 +0200,Andrew Jones写道:
> On Thu, Apr 27, 2023 at 09:02:14AM +0800, Xiang W wrote:
> > 在 2023-04-26星期三的 19:27 +0200,Andrew Jones写道:
> > > Ensure attempts to invoke SBI extension functions fail with
> > > SBI_ERR_NOT_SUPPORTED when the extension's probe function has
> > > reported that the extension is not available. By adding a new
> > > status member to the extension which has three states
> > > (uninitialized, available, unavailable), we ensure that the
> > > probe function is only invoked once, lazily, upon first use.
> > 
> > Adding this state may cause errors. For example: the id numberof an extension is from extid_start to extid_end, which has an
> > unused ID. Searching for an ID in this extension will return NULL
> > if an unused ID is searched first.
> 
> Hi Xiang,
> 
> You're right. Either sbi_ecall_extension::status needs to be a function of
> extid, like probe is, or we should just always call probe (when it's
> available) and leave any optimizations to the individual probe functions.
> How about this?
> 
> diff --git a/lib/sbi/sbi_ecall.c b/lib/sbi/sbi_ecall.c
> index 76a1ae9ab733..c86e4e8c9134 100644
> --- a/lib/sbi/sbi_ecall.c
> +++ b/lib/sbi/sbi_ecall.c
> @@ -42,16 +42,18 @@ static SBI_LIST_HEAD(ecall_exts_list);
>  
>  struct sbi_ecall_extension *sbi_ecall_find_extension(unsigned long extid)
>  {
> -       struct sbi_ecall_extension *t, *ret = NULL;
> +       struct sbi_ecall_extension *t;
> +       unsigned long out_val;
>  
>         sbi_list_for_each_entry(t, &ecall_exts_list, head) {
>                 if (t->extid_start <= extid && extid <= t->extid_end) {
> -                       ret = t;
> -                       break;
> +                       if (t->probe && (t->probe(extid, &out_val) || !out_val))
> +                               return NULL;
> +                       return t;
>                 }
>         }
>  
> -       return ret;
> +       return NULL;
>  }
>  
>  int sbi_ecall_register_extension(struct sbi_ecall_extension *ext)
> 
> Thanks,
> drew
Good. If so modified we can modify sbi_ecall_base_probe as well.
As follows:

diff --git a/lib/sbi/sbi_ecall_base.c b/lib/sbi/sbi_ecall_base.c
index 786d2ac..e3aa02b 100644
--- a/lib/sbi/sbi_ecall_base.c
+++ b/lib/sbi/sbi_ecall_base.c
@@ -20,15 +20,7 @@ static int sbi_ecall_base_probe(unsigned long extid, unsigned long *out_val)
        struct sbi_ecall_extension *ext;
 
        ext = sbi_ecall_find_extension(extid);
-       if (!ext) {
-               *out_val = 0;
-               return 0;
-       }
-
-       if (ext->probe)
-               return ext->probe(extid, out_val);
-
-       *out_val = 1;
+       *out_val = ext ? 1 : 0;
        return 0;
 }

Regards,
Xiang W
> 
> > 
> > Regards,
> > Xiang W
> > > 
> > > Signed-off-by: Andrew Jones <ajones@ventanamicro.com>
> > > ---
> > >  include/sbi/sbi_ecall.h |  6 ++++++
> > >  lib/sbi/sbi_ecall.c     | 18 ++++++++++++++----
> > >  2 files changed, 20 insertions(+), 4 deletions(-)
> > > 
> > > diff --git a/include/sbi/sbi_ecall.h b/include/sbi/sbi_ecall.h
> > > index ff9bf8e2b435..8e31d0d91620 100644
> > > --- a/include/sbi/sbi_ecall.h
> > > +++ b/include/sbi/sbi_ecall.h
> > > @@ -20,10 +20,16 @@
> > >  struct sbi_trap_regs;
> > >  struct sbi_trap_info;
> > >  
> > > +enum sbi_ext_status {
> > > +       SBI_EXT_AVAILABLE = 1,
> > > +       SBI_EXT_UNAVAILABLE,
> > > +};
> > > +
> > >  struct sbi_ecall_extension {
> > >         struct sbi_dlist head;
> > >         unsigned long extid_start;
> > >         unsigned long extid_end;
> > > +       enum sbi_ext_status status;
> > >         int (* probe)(unsigned long extid, unsigned long *out_val);
> > >         int (* handle)(unsigned long extid, unsigned long funcid,
> > >                        const struct sbi_trap_regs *regs,
> > > diff --git a/lib/sbi/sbi_ecall.c b/lib/sbi/sbi_ecall.c
> > > index 76a1ae9ab733..20ff06f32dad 100644
> > > --- a/lib/sbi/sbi_ecall.c
> > > +++ b/lib/sbi/sbi_ecall.c
> > > @@ -42,16 +42,26 @@ static SBI_LIST_HEAD(ecall_exts_list);
> > >  
> > >  struct sbi_ecall_extension *sbi_ecall_find_extension(unsigned long extid)
> > >  {
> > > -       struct sbi_ecall_extension *t, *ret = NULL;
> > > +       struct sbi_ecall_extension *t;
> > > +       unsigned long out_val;
> > >  
> > >         sbi_list_for_each_entry(t, &ecall_exts_list, head) {
> > >                 if (t->extid_start <= extid && extid <= t->extid_end) {
> > > -                       ret = t;
> > > -                       break;
> > > +                       if (t->status == SBI_EXT_AVAILABLE)
> > > +                               return t;
> > > +                       if (t->status == SBI_EXT_UNAVAILABLE)
> > > +                               return NULL;
> > > +                       if (t->probe && (t->probe(extid, &out_val) || !out_val)) {
> > > +                               t->status = SBI_EXT_UNAVAILABLE;
> > > +                               return NULL;
> > > +                       }
> > > +
> > > +                       t->status = SBI_EXT_AVAILABLE;
> > > +                       return t;
> > >                 }
> > >         }
> > >  
> > > -       return ret;
> > > +       return NULL;
> > >  }
> > >  
> > >  int sbi_ecall_register_extension(struct sbi_ecall_extension *ext)
> > > -- 
> > > 2.39.2
> > > 
> > > 
> > 
> >
Xiang W April 27, 2023, 7:52 a.m. UTC | #5
在 2023-04-27星期四的 09:18 +0200,Andrew Jones写道:
> On Thu, Apr 27, 2023 at 09:00:35AM +0200, Andrew Jones wrote:
> > z4xshfbykgvcgcozn@rqv44g76lo4w>
> > References: <20230426172753.70664-1-ajones@ventanamicro.com>
> >  <f798c3f500849d71aba59a06d4c90ea0e4cb2071.camel@126.com>
> > MIME-Version: 1.0
> > Content-Type: text/plain; charset=utf-8
> > Content-Disposition: inline
> > Content-Transfer-Encoding: 8bit
> > In-Reply-To: <f798c3f500849d71aba59a06d4c90ea0e4cb2071.camel@126.com>
> > 
> > On Thu, Apr 27, 2023 at 09:02:14AM +0800, Xiang W wrote:
> > > 在 2023-04-26星期三的 19:27 +0200,Andrew Jones写道:
> > > > Ensure attempts to invoke SBI extension functions fail with
> > > > SBI_ERR_NOT_SUPPORTED when the extension's probe function has
> > > > reported that the extension is not available. By adding a new
> > > > status member to the extension which has three states
> > > > (uninitialized, available, unavailable), we ensure that the
> > > > probe function is only invoked once, lazily, upon first use.
> > > 
> > > Adding this state may cause errors. For example: the id numberof an extension is from extid_start to extid_end, which has an
> > > unused ID. Searching for an ID in this extension will return NULL
> > > if an unused ID is searched first.
> > 
> > Hi Xiang,
> > 
> > You're right. Either sbi_ecall_extension::status needs to be a function of
> > extid, like probe is, or we should just always call probe (when it's
> > available) and leave any optimizations to the individual probe functions.
> > How about this?
> > 
> > diff --git a/lib/sbi/sbi_ecall.c b/lib/sbi/sbi_ecall.c
> > index 76a1ae9ab733..c86e4e8c9134 100644
> > --- a/lib/sbi/sbi_ecall.c
> > +++ b/lib/sbi/sbi_ecall.c
> > @@ -42,16 +42,18 @@ static SBI_LIST_HEAD(ecall_exts_list);
> >  
> >  struct sbi_ecall_extension *sbi_ecall_find_extension(unsigned long extid)
> >  {
> > -       struct sbi_ecall_extension *t, *ret = NULL;
> > +       struct sbi_ecall_extension *t;
> > +       unsigned long out_val;
> >  
> >         sbi_list_for_each_entry(t, &ecall_exts_list, head) {
> >                 if (t->extid_start <= extid && extid <= t->extid_end) {
> > -                       ret = t;
> > -                       break;
> > +                       if (t->probe && (t->probe(extid, &out_val) || !out_val))
> > +                               return NULL;
> > +                       return t;
> >                 }
> >         }
> >  
> > -       return ret;
> > +       return NULL;
> >  }
> >  
> >  int sbi_ecall_register_extension(struct sbi_ecall_extension *ext)
> 
> And, as a separate patch, to optimize probing of srst, which has a single
> extid for its range, and therefore doesn't care about it in its probe,
> 
> diff --git a/lib/sbi/sbi_ecall_srst.c b/lib/sbi/sbi_ecall_srst.c
> index 93b012ce024c..f2690b80775a 100644
> --- a/lib/sbi/sbi_ecall_srst.c
> +++ b/lib/sbi/sbi_ecall_srst.c
> @@ -50,8 +50,15 @@ static int sbi_ecall_srst_handler(unsigned long extid, unsigned long funcid,
>  
>  static int sbi_ecall_srst_probe(unsigned long extid, unsigned long *out_val)
>  {
> +       static bool probed = false;
> +       static unsigned long val;
>         u32 type, count = 0;
>  
> +       if (probed) {
> +               *out_val = val;
> +               return 0;
> +       }
> +
>         /*
>          * At least one standard reset types should be supported by
>          * the platform for SBI SRST extension to be usable.
> @@ -63,7 +70,8 @@ static int sbi_ecall_srst_probe(unsigned long extid, unsigned long *out_val)
>                         count++;
>         }
>  
> -       *out_val = (count) ? 1 : 0;
> +       *out_val = val = (count) ? 1 : 0;
> +       probed = true;
>         return 0;
>  }
> 
> And susp can be optimized in exactly the same way.
> 
> Thanks,
> drew
> 

This can be a generic optimization. Since most extensions have only
one extension id, here is my suggestion

diff --git a/lib/sbi/sbi_ecall.c b/lib/sbi/sbi_ecall.c
index 76a1ae9..900a4fa 100644
--- a/lib/sbi/sbi_ecall.c
+++ b/lib/sbi/sbi_ecall.c
@@ -42,16 +42,26 @@ static SBI_LIST_HEAD(ecall_exts_list);
 
 struct sbi_ecall_extension *sbi_ecall_find_extension(unsigned long extid)
 {
-       struct sbi_ecall_extension *t, *ret = NULL;
+       struct sbi_ecall_extension *t;
 
        sbi_list_for_each_entry(t, &ecall_exts_list, head) {
                if (t->extid_start <= extid && extid <= t->extid_end) {
-                       ret = t;
-                       break;
+                       if (t->extid_start == t->extid_end) {
+                               if (t->status == SBI_EXT_AVAILABLE)
+                                       return t;
+                               if (t->status == SBI_EXT_UNAVAILABLE)
+                                       return NULL;
+                       }
+                       if (t->probe && (t->probe(extid, &out_val) || !out_val)) {
+                               t->status = SBI_EXT_UNAVAILABLE;
+                               return NULL
+                       }
+                       t->status = SBI_EXT_AVAILABLE;
+                       return t;
                }
        }
 
-       return ret;
+       return NULL;
 }
Andrew Jones April 27, 2023, 8:01 a.m. UTC | #6
On Thu, Apr 27, 2023 at 03:26:20PM +0800, Xiang W wrote:
> 在 2023-04-27星期四的 09:00 +0200,Andrew Jones写道:
> > On Thu, Apr 27, 2023 at 09:02:14AM +0800, Xiang W wrote:
> > > 在 2023-04-26星期三的 19:27 +0200,Andrew Jones写道:
> > > > Ensure attempts to invoke SBI extension functions fail with
> > > > SBI_ERR_NOT_SUPPORTED when the extension's probe function has
> > > > reported that the extension is not available. By adding a new
> > > > status member to the extension which has three states
> > > > (uninitialized, available, unavailable), we ensure that the
> > > > probe function is only invoked once, lazily, upon first use.
> > > 
> > > Adding this state may cause errors. For example: the id numberof an extension is from extid_start to extid_end, which has an
> > > unused ID. Searching for an ID in this extension will return NULL
> > > if an unused ID is searched first.
> > 
> > Hi Xiang,
> > 
> > You're right. Either sbi_ecall_extension::status needs to be a function of
> > extid, like probe is, or we should just always call probe (when it's
> > available) and leave any optimizations to the individual probe functions.
> > How about this?
> > 
> > diff --git a/lib/sbi/sbi_ecall.c b/lib/sbi/sbi_ecall.c
> > index 76a1ae9ab733..c86e4e8c9134 100644
> > --- a/lib/sbi/sbi_ecall.c
> > +++ b/lib/sbi/sbi_ecall.c
> > @@ -42,16 +42,18 @@ static SBI_LIST_HEAD(ecall_exts_list);
> >  
> >  struct sbi_ecall_extension *sbi_ecall_find_extension(unsigned long extid)
> >  {
> > -       struct sbi_ecall_extension *t, *ret = NULL;
> > +       struct sbi_ecall_extension *t;
> > +       unsigned long out_val;
> >  
> >         sbi_list_for_each_entry(t, &ecall_exts_list, head) {
> >                 if (t->extid_start <= extid && extid <= t->extid_end) {
> > -                       ret = t;
> > -                       break;
> > +                       if (t->probe && (t->probe(extid, &out_val) || !out_val))
> > +                               return NULL;
> > +                       return t;
> >                 }
> >         }
> >  
> > -       return ret;
> > +       return NULL;
> >  }
> >  
> >  int sbi_ecall_register_extension(struct sbi_ecall_extension *ext)
> > 
> > Thanks,
> > drew
> Good. If so modified we can modify sbi_ecall_base_probe as well.
> As follows:
> 
> diff --git a/lib/sbi/sbi_ecall_base.c b/lib/sbi/sbi_ecall_base.c
> index 786d2ac..e3aa02b 100644
> --- a/lib/sbi/sbi_ecall_base.c
> +++ b/lib/sbi/sbi_ecall_base.c
> @@ -20,15 +20,7 @@ static int sbi_ecall_base_probe(unsigned long extid, unsigned long *out_val)
>         struct sbi_ecall_extension *ext;
>  
>         ext = sbi_ecall_find_extension(extid);
> -       if (!ext) {
> -               *out_val = 0;
> -               return 0;
> -       }
> -
> -       if (ext->probe)
> -               return ext->probe(extid, out_val);
> -
> -       *out_val = 1;
> +       *out_val = ext ? 1 : 0;
>         return 0;
>  }
>

If we do this, then we lose the return value of the extension's probe
function, which is currently getting propagated all the way back to
the SBI caller. sbi_ecall_base_probe() isn't in a fast path, so even
though probe will get invoked twice, I guess we can afford it.

Thanks,
drew
Andrew Jones April 27, 2023, 8:04 a.m. UTC | #7
On Thu, Apr 27, 2023 at 03:52:16PM +0800, Xiang W wrote:
> 在 2023-04-27星期四的 09:18 +0200,Andrew Jones写道:
> > On Thu, Apr 27, 2023 at 09:00:35AM +0200, Andrew Jones wrote:
> > > z4xshfbykgvcgcozn@rqv44g76lo4w>
> > > References: <20230426172753.70664-1-ajones@ventanamicro.com>
> > >  <f798c3f500849d71aba59a06d4c90ea0e4cb2071.camel@126.com>
> > > MIME-Version: 1.0
> > > Content-Type: text/plain; charset=utf-8
> > > Content-Disposition: inline
> > > Content-Transfer-Encoding: 8bit
> > > In-Reply-To: <f798c3f500849d71aba59a06d4c90ea0e4cb2071.camel@126.com>
> > > 
> > > On Thu, Apr 27, 2023 at 09:02:14AM +0800, Xiang W wrote:
> > > > 在 2023-04-26星期三的 19:27 +0200,Andrew Jones写道:
> > > > > Ensure attempts to invoke SBI extension functions fail with
> > > > > SBI_ERR_NOT_SUPPORTED when the extension's probe function has
> > > > > reported that the extension is not available. By adding a new
> > > > > status member to the extension which has three states
> > > > > (uninitialized, available, unavailable), we ensure that the
> > > > > probe function is only invoked once, lazily, upon first use.
> > > > 
> > > > Adding this state may cause errors. For example: the id numberof an extension is from extid_start to extid_end, which has an
> > > > unused ID. Searching for an ID in this extension will return NULL
> > > > if an unused ID is searched first.
> > > 
> > > Hi Xiang,
> > > 
> > > You're right. Either sbi_ecall_extension::status needs to be a function of
> > > extid, like probe is, or we should just always call probe (when it's
> > > available) and leave any optimizations to the individual probe functions.
> > > How about this?
> > > 
> > > diff --git a/lib/sbi/sbi_ecall.c b/lib/sbi/sbi_ecall.c
> > > index 76a1ae9ab733..c86e4e8c9134 100644
> > > --- a/lib/sbi/sbi_ecall.c
> > > +++ b/lib/sbi/sbi_ecall.c
> > > @@ -42,16 +42,18 @@ static SBI_LIST_HEAD(ecall_exts_list);
> > >  
> > >  struct sbi_ecall_extension *sbi_ecall_find_extension(unsigned long extid)
> > >  {
> > > -       struct sbi_ecall_extension *t, *ret = NULL;
> > > +       struct sbi_ecall_extension *t;
> > > +       unsigned long out_val;
> > >  
> > >         sbi_list_for_each_entry(t, &ecall_exts_list, head) {
> > >                 if (t->extid_start <= extid && extid <= t->extid_end) {
> > > -                       ret = t;
> > > -                       break;
> > > +                       if (t->probe && (t->probe(extid, &out_val) || !out_val))
> > > +                               return NULL;
> > > +                       return t;
> > >                 }
> > >         }
> > >  
> > > -       return ret;
> > > +       return NULL;
> > >  }
> > >  
> > >  int sbi_ecall_register_extension(struct sbi_ecall_extension *ext)
> > 
> > And, as a separate patch, to optimize probing of srst, which has a single
> > extid for its range, and therefore doesn't care about it in its probe,
> > 
> > diff --git a/lib/sbi/sbi_ecall_srst.c b/lib/sbi/sbi_ecall_srst.c
> > index 93b012ce024c..f2690b80775a 100644
> > --- a/lib/sbi/sbi_ecall_srst.c
> > +++ b/lib/sbi/sbi_ecall_srst.c
> > @@ -50,8 +50,15 @@ static int sbi_ecall_srst_handler(unsigned long extid, unsigned long funcid,
> >  
> >  static int sbi_ecall_srst_probe(unsigned long extid, unsigned long *out_val)
> >  {
> > +       static bool probed = false;
> > +       static unsigned long val;
> >         u32 type, count = 0;
> >  
> > +       if (probed) {
> > +               *out_val = val;
> > +               return 0;
> > +       }
> > +
> >         /*
> >          * At least one standard reset types should be supported by
> >          * the platform for SBI SRST extension to be usable.
> > @@ -63,7 +70,8 @@ static int sbi_ecall_srst_probe(unsigned long extid, unsigned long *out_val)
> >                         count++;
> >         }
> >  
> > -       *out_val = (count) ? 1 : 0;
> > +       *out_val = val = (count) ? 1 : 0;
> > +       probed = true;
> >         return 0;
> >  }
> > 
> > And susp can be optimized in exactly the same way.
> > 
> > Thanks,
> > drew
> > 
> 
> This can be a generic optimization. Since most extensions have only
> one extension id, here is my suggestion
> 
> diff --git a/lib/sbi/sbi_ecall.c b/lib/sbi/sbi_ecall.c
> index 76a1ae9..900a4fa 100644
> --- a/lib/sbi/sbi_ecall.c
> +++ b/lib/sbi/sbi_ecall.c
> @@ -42,16 +42,26 @@ static SBI_LIST_HEAD(ecall_exts_list);
>  
>  struct sbi_ecall_extension *sbi_ecall_find_extension(unsigned long extid)
>  {
> -       struct sbi_ecall_extension *t, *ret = NULL;
> +       struct sbi_ecall_extension *t;
>  
>         sbi_list_for_each_entry(t, &ecall_exts_list, head) {
>                 if (t->extid_start <= extid && extid <= t->extid_end) {
> -                       ret = t;
> -                       break;
> +                       if (t->extid_start == t->extid_end) {
> +                               if (t->status == SBI_EXT_AVAILABLE)
> +                                       return t;
> +                               if (t->status == SBI_EXT_UNAVAILABLE)
> +                                       return NULL;
> +                       }
> +                       if (t->probe && (t->probe(extid, &out_val) || !out_val)) {
> +                               t->status = SBI_EXT_UNAVAILABLE;
> +                               return NULL
> +                       }
> +                       t->status = SBI_EXT_AVAILABLE;
> +                       return t;
>                 }
>         }
>  
> -       return ret;
> +       return NULL;
>  }
>

Yeah, LGTM. v2 coming up.

Thanks!
drew
Xiang W April 28, 2023, 1:52 a.m. UTC | #8
在 2023-04-27星期四的 10:01 +0200,Andrew Jones写道:
> On Thu, Apr 27, 2023 at 03:26:20PM +0800, Xiang W wrote:
> > 在 2023-04-27星期四的 09:00 +0200,Andrew Jones写道:
> > > On Thu, Apr 27, 2023 at 09:02:14AM +0800, Xiang W wrote:
> > > > 在 2023-04-26星期三的 19:27 +0200,Andrew Jones写道:
> > > > > Ensure attempts to invoke SBI extension functions fail with
> > > > > SBI_ERR_NOT_SUPPORTED when the extension's probe function has
> > > > > reported that the extension is not available. By adding a new
> > > > > status member to the extension which has three states
> > > > > (uninitialized, available, unavailable), we ensure that the
> > > > > probe function is only invoked once, lazily, upon first use.
> > > > 
> > > > Adding this state may cause errors. For example: the id numberof an extension is from extid_start to extid_end, which has an
> > > > unused ID. Searching for an ID in this extension will return NULL
> > > > if an unused ID is searched first.
> > > 
> > > Hi Xiang,
> > > 
> > > You're right. Either sbi_ecall_extension::status needs to be a function of
> > > extid, like probe is, or we should just always call probe (when it's
> > > available) and leave any optimizations to the individual probe functions.
> > > How about this?
> > > 
> > > diff --git a/lib/sbi/sbi_ecall.c b/lib/sbi/sbi_ecall.c
> > > index 76a1ae9ab733..c86e4e8c9134 100644
> > > --- a/lib/sbi/sbi_ecall.c
> > > +++ b/lib/sbi/sbi_ecall.c
> > > @@ -42,16 +42,18 @@ static SBI_LIST_HEAD(ecall_exts_list);
> > >  
> > >  struct sbi_ecall_extension *sbi_ecall_find_extension(unsigned long extid)
> > >  {
> > > -       struct sbi_ecall_extension *t, *ret = NULL;
> > > +       struct sbi_ecall_extension *t;
> > > +       unsigned long out_val;
> > >  
> > >         sbi_list_for_each_entry(t, &ecall_exts_list, head) {
> > >                 if (t->extid_start <= extid && extid <= t->extid_end) {
> > > -                       ret = t;
> > > -                       break;
> > > +                       if (t->probe && (t->probe(extid, &out_val) || !out_val))
> > > +                               return NULL;
> > > +                       return t;
> > >                 }
> > >         }
> > >  
> > > -       return ret;
> > > +       return NULL;
> > >  }
> > >  
> > >  int sbi_ecall_register_extension(struct sbi_ecall_extension *ext)
> > > 
> > > Thanks,
> > > drew
> > Good. If so modified we can modify sbi_ecall_base_probe as well.
> > As follows:
> > 
> > diff --git a/lib/sbi/sbi_ecall_base.c b/lib/sbi/sbi_ecall_base.c
> > index 786d2ac..e3aa02b 100644
> > --- a/lib/sbi/sbi_ecall_base.c
> > +++ b/lib/sbi/sbi_ecall_base.c
> > @@ -20,15 +20,7 @@ static int sbi_ecall_base_probe(unsigned long extid, unsigned long *out_val)
> >         struct sbi_ecall_extension *ext;
> >  
> >         ext = sbi_ecall_find_extension(extid);
> > -       if (!ext) {
> > -               *out_val = 0;
> > -               return 0;
> > -       }
> > -
> > -       if (ext->probe)
> > -               return ext->probe(extid, out_val);
> > -
> > -       *out_val = 1;
> > +       *out_val = ext ? 1 : 0;
> >         return 0;
> >  }
> > 
> 
> If we do this, then we lose the return value of the extension's probe
> function, which is currently getting propagated all the way back to
> the SBI caller. sbi_ecall_base_probe() isn't in a fast path, so even
> though probe will get invoked twice, I guess we can afford it.
> 
> Thanks,
> drew

If you don't modify sbi_ecall_base_probe, I don't think we need to modify
sbi_ecall_find_extension. sbi_ecall_find_extension just find the structure
of extension. If there is a gap in the id number, the handle and probe
will definitely handle it.

Regards,
Xiang W
Anup Patel April 28, 2023, 4:05 a.m. UTC | #9
On Wed, Apr 26, 2023 at 10:58 PM Andrew Jones <ajones@ventanamicro.com> wrote:
>
> Ensure attempts to invoke SBI extension functions fail with
> SBI_ERR_NOT_SUPPORTED when the extension's probe function has
> reported that the extension is not available. By adding a new
> status member to the extension which has three states
> (uninitialized, available, unavailable), we ensure that the
> probe function is only invoked once, lazily, upon first use.
>
> Signed-off-by: Andrew Jones <ajones@ventanamicro.com>
> ---
>  include/sbi/sbi_ecall.h |  6 ++++++
>  lib/sbi/sbi_ecall.c     | 18 ++++++++++++++----
>  2 files changed, 20 insertions(+), 4 deletions(-)
>
> diff --git a/include/sbi/sbi_ecall.h b/include/sbi/sbi_ecall.h
> index ff9bf8e2b435..8e31d0d91620 100644
> --- a/include/sbi/sbi_ecall.h
> +++ b/include/sbi/sbi_ecall.h
> @@ -20,10 +20,16 @@
>  struct sbi_trap_regs;
>  struct sbi_trap_info;
>
> +enum sbi_ext_status {
> +       SBI_EXT_AVAILABLE = 1,
> +       SBI_EXT_UNAVAILABLE,
> +};
> +
>  struct sbi_ecall_extension {
>         struct sbi_dlist head;
>         unsigned long extid_start;
>         unsigned long extid_end;
> +       enum sbi_ext_status status;
>         int (* probe)(unsigned long extid, unsigned long *out_val);
>         int (* handle)(unsigned long extid, unsigned long funcid,
>                        const struct sbi_trap_regs *regs,
> diff --git a/lib/sbi/sbi_ecall.c b/lib/sbi/sbi_ecall.c
> index 76a1ae9ab733..20ff06f32dad 100644
> --- a/lib/sbi/sbi_ecall.c
> +++ b/lib/sbi/sbi_ecall.c
> @@ -42,16 +42,26 @@ static SBI_LIST_HEAD(ecall_exts_list);
>
>  struct sbi_ecall_extension *sbi_ecall_find_extension(unsigned long extid)
>  {
> -       struct sbi_ecall_extension *t, *ret = NULL;
> +       struct sbi_ecall_extension *t;
> +       unsigned long out_val;
>
>         sbi_list_for_each_entry(t, &ecall_exts_list, head) {
>                 if (t->extid_start <= extid && extid <= t->extid_end) {
> -                       ret = t;
> -                       break;
> +                       if (t->status == SBI_EXT_AVAILABLE)
> +                               return t;
> +                       if (t->status == SBI_EXT_UNAVAILABLE)
> +                               return NULL;
> +                       if (t->probe && (t->probe(extid, &out_val) || !out_val)) {
> +                               t->status = SBI_EXT_UNAVAILABLE;

Setting this `status` flag is a bit racey because two HARTs can end-up
in sbi_ecall_find_extension() at the same time.

I suggest an alternate approach whereby we don't need the `status`
flag and sbi_ecall_find_extension() also does not need to change:

1) Rename `probe()` callback to `init()` callback
2) Remove sbi_ecall_register_extension() call from sbi_ecall_init()
    and instead call `init()` for each extension
3) Implement `init()` for each extension such that each extension
    explicitly register itself using sbi_ecall_register_extension()
    only if the extension is actually available.

In other words, the alternate approach treats SBI extensions are
driver instances which need to be registered by some init() call.

Regards,
Anup

> +                               return NULL;
> +                       }
> +
> +                       t->status = SBI_EXT_AVAILABLE;
> +                       return t;
>                 }
>         }
>
> -       return ret;
> +       return NULL;
>  }
>
>  int sbi_ecall_register_extension(struct sbi_ecall_extension *ext)
> --
> 2.39.2
>
>
> --
> opensbi mailing list
> opensbi@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/opensbi
Andrew Jones April 28, 2023, 10:40 a.m. UTC | #10
On Fri, Apr 28, 2023 at 09:52:00AM +0800, Xiang W wrote:
> 在 2023-04-27星期四的 10:01 +0200,Andrew Jones写道:
> > On Thu, Apr 27, 2023 at 03:26:20PM +0800, Xiang W wrote:
> > > 在 2023-04-27星期四的 09:00 +0200,Andrew Jones写道:
> > > > On Thu, Apr 27, 2023 at 09:02:14AM +0800, Xiang W wrote:
> > > > > 在 2023-04-26星期三的 19:27 +0200,Andrew Jones写道:
> > > > > > Ensure attempts to invoke SBI extension functions fail with
> > > > > > SBI_ERR_NOT_SUPPORTED when the extension's probe function has
> > > > > > reported that the extension is not available. By adding a new
> > > > > > status member to the extension which has three states
> > > > > > (uninitialized, available, unavailable), we ensure that the
> > > > > > probe function is only invoked once, lazily, upon first use.
> > > > > 
> > > > > Adding this state may cause errors. For example: the id numberof an extension is from extid_start to extid_end, which has an
> > > > > unused ID. Searching for an ID in this extension will return NULL
> > > > > if an unused ID is searched first.
> > > > 
> > > > Hi Xiang,
> > > > 
> > > > You're right. Either sbi_ecall_extension::status needs to be a function of
> > > > extid, like probe is, or we should just always call probe (when it's
> > > > available) and leave any optimizations to the individual probe functions.
> > > > How about this?
> > > > 
> > > > diff --git a/lib/sbi/sbi_ecall.c b/lib/sbi/sbi_ecall.c
> > > > index 76a1ae9ab733..c86e4e8c9134 100644
> > > > --- a/lib/sbi/sbi_ecall.c
> > > > +++ b/lib/sbi/sbi_ecall.c
> > > > @@ -42,16 +42,18 @@ static SBI_LIST_HEAD(ecall_exts_list);
> > > >  
> > > >  struct sbi_ecall_extension *sbi_ecall_find_extension(unsigned long extid)
> > > >  {
> > > > -       struct sbi_ecall_extension *t, *ret = NULL;
> > > > +       struct sbi_ecall_extension *t;
> > > > +       unsigned long out_val;
> > > >  
> > > >         sbi_list_for_each_entry(t, &ecall_exts_list, head) {
> > > >                 if (t->extid_start <= extid && extid <= t->extid_end) {
> > > > -                       ret = t;
> > > > -                       break;
> > > > +                       if (t->probe && (t->probe(extid, &out_val) || !out_val))
> > > > +                               return NULL;
> > > > +                       return t;
> > > >                 }
> > > >         }
> > > >  
> > > > -       return ret;
> > > > +       return NULL;
> > > >  }
> > > >  
> > > >  int sbi_ecall_register_extension(struct sbi_ecall_extension *ext)
> > > > 
> > > > Thanks,
> > > > drew
> > > Good. If so modified we can modify sbi_ecall_base_probe as well.
> > > As follows:
> > > 
> > > diff --git a/lib/sbi/sbi_ecall_base.c b/lib/sbi/sbi_ecall_base.c
> > > index 786d2ac..e3aa02b 100644
> > > --- a/lib/sbi/sbi_ecall_base.c
> > > +++ b/lib/sbi/sbi_ecall_base.c
> > > @@ -20,15 +20,7 @@ static int sbi_ecall_base_probe(unsigned long extid, unsigned long *out_val)
> > >         struct sbi_ecall_extension *ext;
> > >  
> > >         ext = sbi_ecall_find_extension(extid);
> > > -       if (!ext) {
> > > -               *out_val = 0;
> > > -               return 0;
> > > -       }
> > > -
> > > -       if (ext->probe)
> > > -               return ext->probe(extid, out_val);
> > > -
> > > -       *out_val = 1;
> > > +       *out_val = ext ? 1 : 0;
> > >         return 0;
> > >  }
> > > 
> > 
> > If we do this, then we lose the return value of the extension's probe
> > function, which is currently getting propagated all the way back to
> > the SBI caller. sbi_ecall_base_probe() isn't in a fast path, so even
> > though probe will get invoked twice, I guess we can afford it.
> > 
> > Thanks,
> > drew
> 
> If you don't modify sbi_ecall_base_probe, I don't think we need to modify
> sbi_ecall_find_extension. sbi_ecall_find_extension just find the structure
> of extension. If there is a gap in the id number, the handle and probe
> will definitely handle it.

I'm not sure I follow. The main goal of modifying sbi_ecall_find_extension
is to ensure that we don't call handle unless probe says we can.

Thanks,
drew
Andrew Jones April 28, 2023, 10:51 a.m. UTC | #11
On Fri, Apr 28, 2023 at 09:35:45AM +0530, Anup Patel wrote:
> On Wed, Apr 26, 2023 at 10:58 PM Andrew Jones <ajones@ventanamicro.com> wrote:
> >
> > Ensure attempts to invoke SBI extension functions fail with
> > SBI_ERR_NOT_SUPPORTED when the extension's probe function has
> > reported that the extension is not available. By adding a new
> > status member to the extension which has three states
> > (uninitialized, available, unavailable), we ensure that the
> > probe function is only invoked once, lazily, upon first use.
> >
> > Signed-off-by: Andrew Jones <ajones@ventanamicro.com>
> > ---
> >  include/sbi/sbi_ecall.h |  6 ++++++
> >  lib/sbi/sbi_ecall.c     | 18 ++++++++++++++----
> >  2 files changed, 20 insertions(+), 4 deletions(-)
> >
> > diff --git a/include/sbi/sbi_ecall.h b/include/sbi/sbi_ecall.h
> > index ff9bf8e2b435..8e31d0d91620 100644
> > --- a/include/sbi/sbi_ecall.h
> > +++ b/include/sbi/sbi_ecall.h
> > @@ -20,10 +20,16 @@
> >  struct sbi_trap_regs;
> >  struct sbi_trap_info;
> >
> > +enum sbi_ext_status {
> > +       SBI_EXT_AVAILABLE = 1,
> > +       SBI_EXT_UNAVAILABLE,
> > +};
> > +
> >  struct sbi_ecall_extension {
> >         struct sbi_dlist head;
> >         unsigned long extid_start;
> >         unsigned long extid_end;
> > +       enum sbi_ext_status status;
> >         int (* probe)(unsigned long extid, unsigned long *out_val);
> >         int (* handle)(unsigned long extid, unsigned long funcid,
> >                        const struct sbi_trap_regs *regs,
> > diff --git a/lib/sbi/sbi_ecall.c b/lib/sbi/sbi_ecall.c
> > index 76a1ae9ab733..20ff06f32dad 100644
> > --- a/lib/sbi/sbi_ecall.c
> > +++ b/lib/sbi/sbi_ecall.c
> > @@ -42,16 +42,26 @@ static SBI_LIST_HEAD(ecall_exts_list);
> >
> >  struct sbi_ecall_extension *sbi_ecall_find_extension(unsigned long extid)
> >  {
> > -       struct sbi_ecall_extension *t, *ret = NULL;
> > +       struct sbi_ecall_extension *t;
> > +       unsigned long out_val;
> >
> >         sbi_list_for_each_entry(t, &ecall_exts_list, head) {
> >                 if (t->extid_start <= extid && extid <= t->extid_end) {
> > -                       ret = t;
> > -                       break;
> > +                       if (t->status == SBI_EXT_AVAILABLE)
> > +                               return t;
> > +                       if (t->status == SBI_EXT_UNAVAILABLE)
> > +                               return NULL;
> > +                       if (t->probe && (t->probe(extid, &out_val) || !out_val)) {
> > +                               t->status = SBI_EXT_UNAVAILABLE;
> 
> Setting this `status` flag is a bit racey because two HARTs can end-up
> in sbi_ecall_find_extension() at the same time.

It's racy, but it shouldn't matter, since the result will be the
same whether a second hart ends up calling probe itself or not.

> 
> I suggest an alternate approach whereby we don't need the `status`
> flag and sbi_ecall_find_extension() also does not need to change:
> 
> 1) Rename `probe()` callback to `init()` callback
> 2) Remove sbi_ecall_register_extension() call from sbi_ecall_init()
>     and instead call `init()` for each extension
> 3) Implement `init()` for each extension such that each extension
>     explicitly register itself using sbi_ecall_register_extension()
>     only if the extension is actually available.
> 
> In other words, the alternate approach treats SBI extensions are
> driver instances which need to be registered by some init() call.

I mostly like that, but probe is specified as "Returns 0 if the
given SBI extension ID (EID) is not available, or 1 if it is available
unless defined as any other non-zero value by the implementation.",
which means a future extension may want to return some nonzero value
from its probe function to inform the caller of something. So, maybe
we keep probe, add init, and call probe from init to decide if we
register the extension?

Thanks,
drew
Anup Patel April 28, 2023, 11:05 a.m. UTC | #12
On Fri, Apr 28, 2023 at 4:21 PM Andrew Jones <ajones@ventanamicro.com> wrote:
>
> On Fri, Apr 28, 2023 at 09:35:45AM +0530, Anup Patel wrote:
> > On Wed, Apr 26, 2023 at 10:58 PM Andrew Jones <ajones@ventanamicro.com> wrote:
> > >
> > > Ensure attempts to invoke SBI extension functions fail with
> > > SBI_ERR_NOT_SUPPORTED when the extension's probe function has
> > > reported that the extension is not available. By adding a new
> > > status member to the extension which has three states
> > > (uninitialized, available, unavailable), we ensure that the
> > > probe function is only invoked once, lazily, upon first use.
> > >
> > > Signed-off-by: Andrew Jones <ajones@ventanamicro.com>
> > > ---
> > >  include/sbi/sbi_ecall.h |  6 ++++++
> > >  lib/sbi/sbi_ecall.c     | 18 ++++++++++++++----
> > >  2 files changed, 20 insertions(+), 4 deletions(-)
> > >
> > > diff --git a/include/sbi/sbi_ecall.h b/include/sbi/sbi_ecall.h
> > > index ff9bf8e2b435..8e31d0d91620 100644
> > > --- a/include/sbi/sbi_ecall.h
> > > +++ b/include/sbi/sbi_ecall.h
> > > @@ -20,10 +20,16 @@
> > >  struct sbi_trap_regs;
> > >  struct sbi_trap_info;
> > >
> > > +enum sbi_ext_status {
> > > +       SBI_EXT_AVAILABLE = 1,
> > > +       SBI_EXT_UNAVAILABLE,
> > > +};
> > > +
> > >  struct sbi_ecall_extension {
> > >         struct sbi_dlist head;
> > >         unsigned long extid_start;
> > >         unsigned long extid_end;
> > > +       enum sbi_ext_status status;
> > >         int (* probe)(unsigned long extid, unsigned long *out_val);
> > >         int (* handle)(unsigned long extid, unsigned long funcid,
> > >                        const struct sbi_trap_regs *regs,
> > > diff --git a/lib/sbi/sbi_ecall.c b/lib/sbi/sbi_ecall.c
> > > index 76a1ae9ab733..20ff06f32dad 100644
> > > --- a/lib/sbi/sbi_ecall.c
> > > +++ b/lib/sbi/sbi_ecall.c
> > > @@ -42,16 +42,26 @@ static SBI_LIST_HEAD(ecall_exts_list);
> > >
> > >  struct sbi_ecall_extension *sbi_ecall_find_extension(unsigned long extid)
> > >  {
> > > -       struct sbi_ecall_extension *t, *ret = NULL;
> > > +       struct sbi_ecall_extension *t;
> > > +       unsigned long out_val;
> > >
> > >         sbi_list_for_each_entry(t, &ecall_exts_list, head) {
> > >                 if (t->extid_start <= extid && extid <= t->extid_end) {
> > > -                       ret = t;
> > > -                       break;
> > > +                       if (t->status == SBI_EXT_AVAILABLE)
> > > +                               return t;
> > > +                       if (t->status == SBI_EXT_UNAVAILABLE)
> > > +                               return NULL;
> > > +                       if (t->probe && (t->probe(extid, &out_val) || !out_val)) {
> > > +                               t->status = SBI_EXT_UNAVAILABLE;
> >
> > Setting this `status` flag is a bit racey because two HARTs can end-up
> > in sbi_ecall_find_extension() at the same time.
>
> It's racy, but it shouldn't matter, since the result will be the
> same whether a second hart ends up calling probe itself or not.
>
> >
> > I suggest an alternate approach whereby we don't need the `status`
> > flag and sbi_ecall_find_extension() also does not need to change:
> >
> > 1) Rename `probe()` callback to `init()` callback
> > 2) Remove sbi_ecall_register_extension() call from sbi_ecall_init()
> >     and instead call `init()` for each extension
> > 3) Implement `init()` for each extension such that each extension
> >     explicitly register itself using sbi_ecall_register_extension()
> >     only if the extension is actually available.
> >
> > In other words, the alternate approach treats SBI extensions are
> > driver instances which need to be registered by some init() call.
>
> I mostly like that, but probe is specified as "Returns 0 if the
> given SBI extension ID (EID) is not available, or 1 if it is available
> unless defined as any other non-zero value by the implementation.",
> which means a future extension may want to return some nonzero value
> from its probe function to inform the caller of something. So, maybe
> we keep probe, add init, and call probe from init to decide if we
> register the extension?

I am okay to keep the probe() callback but currently none of the
extensions have custom probe return value.

Regards,
Anup
diff mbox series

Patch

diff --git a/include/sbi/sbi_ecall.h b/include/sbi/sbi_ecall.h
index ff9bf8e2b435..8e31d0d91620 100644
--- a/include/sbi/sbi_ecall.h
+++ b/include/sbi/sbi_ecall.h
@@ -20,10 +20,16 @@ 
 struct sbi_trap_regs;
 struct sbi_trap_info;
 
+enum sbi_ext_status {
+	SBI_EXT_AVAILABLE = 1,
+	SBI_EXT_UNAVAILABLE,
+};
+
 struct sbi_ecall_extension {
 	struct sbi_dlist head;
 	unsigned long extid_start;
 	unsigned long extid_end;
+	enum sbi_ext_status status;
 	int (* probe)(unsigned long extid, unsigned long *out_val);
 	int (* handle)(unsigned long extid, unsigned long funcid,
 		       const struct sbi_trap_regs *regs,
diff --git a/lib/sbi/sbi_ecall.c b/lib/sbi/sbi_ecall.c
index 76a1ae9ab733..20ff06f32dad 100644
--- a/lib/sbi/sbi_ecall.c
+++ b/lib/sbi/sbi_ecall.c
@@ -42,16 +42,26 @@  static SBI_LIST_HEAD(ecall_exts_list);
 
 struct sbi_ecall_extension *sbi_ecall_find_extension(unsigned long extid)
 {
-	struct sbi_ecall_extension *t, *ret = NULL;
+	struct sbi_ecall_extension *t;
+	unsigned long out_val;
 
 	sbi_list_for_each_entry(t, &ecall_exts_list, head) {
 		if (t->extid_start <= extid && extid <= t->extid_end) {
-			ret = t;
-			break;
+			if (t->status == SBI_EXT_AVAILABLE)
+				return t;
+			if (t->status == SBI_EXT_UNAVAILABLE)
+				return NULL;
+			if (t->probe && (t->probe(extid, &out_val) || !out_val)) {
+				t->status = SBI_EXT_UNAVAILABLE;
+				return NULL;
+			}
+
+			t->status = SBI_EXT_AVAILABLE;
+			return t;
 		}
 	}
 
-	return ret;
+	return NULL;
 }
 
 int sbi_ecall_register_extension(struct sbi_ecall_extension *ext)