* [Qemu-devel] [PATCH v4 0/5] ppc: compute cpu_dt_id in the machine code
@ 2016-07-12 11:14 Greg Kurz
2016-07-12 11:15 ` [Qemu-devel] [PATCH v4 1/5] ppc: different creation paths for cpus in system and user mode Greg Kurz
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Greg Kurz @ 2016-07-12 11:14 UTC (permalink / raw)
To: David Gibson; +Cc: qemu-ppc, qemu-devel, Bharata B Rao
Here's the current patchset I have before I go on vacation, in case it is
needed. It is nearly the same as v3: I've just dropped patches that received
a negative review, fixed a bug and rebased.
The patches are also available here:
git://github.com/gkurz/qemu.git ppc-vcpu-dt-id-rework
Cheers.
---
Greg Kurz (5):
ppc: different creation paths for cpus in system and user mode
ppc: parse cpu features once
ppc: open code cpu creation for machine types
ppc: each machine type to provide vcpu_dt_id
ppc: drop vcpu_idt_id bits from the target code
hw/ppc/e500.c | 4 ++-
hw/ppc/mac_newworld.c | 3 +-
hw/ppc/mac_oldworld.c | 3 +-
hw/ppc/ppc.c | 64 +++++++++++++++++++++++++++++++++++++++++++
hw/ppc/ppc440_bamboo.c | 3 +-
hw/ppc/ppc4xx_devs.c | 3 +-
hw/ppc/prep.c | 3 +-
hw/ppc/spapr.c | 7 ++++-
hw/ppc/spapr_cpu_core.c | 7 +++--
hw/ppc/virtex_ml507.c | 3 +-
include/hw/ppc/ppc.h | 2 +
target-ppc/cpu.h | 5 ++-
target-ppc/translate_init.c | 20 -------------
13 files changed, 95 insertions(+), 32 deletions(-)
--
Greg
^ permalink raw reply [flat|nested] 4+ messages in thread
* [Qemu-devel] [PATCH v4 1/5] ppc: different creation paths for cpus in system and user mode
2016-07-12 11:14 [Qemu-devel] [PATCH v4 0/5] ppc: compute cpu_dt_id in the machine code Greg Kurz
@ 2016-07-12 11:15 ` Greg Kurz
2016-07-12 11:16 ` [Qemu-devel] [PATCH v4 2/5] ppc: parse cpu features once Greg Kurz
2016-07-12 12:07 ` [Qemu-devel] [Qemu-ppc] [PATCH v4 0/5] ppc: compute cpu_dt_id in the machine code Greg Kurz
2 siblings, 0 replies; 4+ messages in thread
From: Greg Kurz @ 2016-07-12 11:15 UTC (permalink / raw)
To: David Gibson; +Cc: qemu-ppc, qemu-devel, Bharata B Rao
The machine code currently uses the same cpu_ppc_init() function to
create cpus as the user mode. This function also triggers the cpu
realization.
It is okay for user mode but with system mode we may want to do other
things between initialization and realization, like generating cpu
ids for the DT for example.
With this patch, each mode has its own creation helper:
- ppc_cpu_init() is for system mode only
- cpu_init() is for user mode only
Suggested-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Greg Kurz <groug@kaod.org>
---
v4: added David's R-b tag
---
hw/ppc/e500.c | 2 +-
hw/ppc/mac_newworld.c | 2 +-
hw/ppc/mac_oldworld.c | 2 +-
hw/ppc/ppc.c | 5 +++++
hw/ppc/ppc440_bamboo.c | 2 +-
hw/ppc/ppc4xx_devs.c | 2 +-
hw/ppc/prep.c | 2 +-
hw/ppc/spapr.c | 2 +-
hw/ppc/virtex_ml507.c | 2 +-
include/hw/ppc/ppc.h | 1 +
target-ppc/cpu.h | 5 +++--
target-ppc/translate_init.c | 5 -----
12 files changed, 17 insertions(+), 15 deletions(-)
diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index 0cd534df55f8..ff5d92e48dd9 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -821,7 +821,7 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
CPUState *cs;
qemu_irq *input;
- cpu = cpu_ppc_init(machine->cpu_model);
+ cpu = ppc_cpu_init(machine->cpu_model);
if (cpu == NULL) {
fprintf(stderr, "Unable to initialize CPU!\n");
exit(1);
diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c
index 7d2510658d0f..ecd40914be45 100644
--- a/hw/ppc/mac_newworld.c
+++ b/hw/ppc/mac_newworld.c
@@ -193,7 +193,7 @@ static void ppc_core99_init(MachineState *machine)
#endif
}
for (i = 0; i < smp_cpus; i++) {
- cpu = cpu_ppc_init(machine->cpu_model);
+ cpu = ppc_cpu_init(machine->cpu_model);
if (cpu == NULL) {
fprintf(stderr, "Unable to find PowerPC CPU definition\n");
exit(1);
diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c
index 447948746b1a..77fbdfffd4e2 100644
--- a/hw/ppc/mac_oldworld.c
+++ b/hw/ppc/mac_oldworld.c
@@ -113,7 +113,7 @@ static void ppc_heathrow_init(MachineState *machine)
if (machine->cpu_model == NULL)
machine->cpu_model = "G3";
for (i = 0; i < smp_cpus; i++) {
- cpu = cpu_ppc_init(machine->cpu_model);
+ cpu = ppc_cpu_init(machine->cpu_model);
if (cpu == NULL) {
fprintf(stderr, "Unable to find PowerPC CPU definition\n");
exit(1);
diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c
index e4252528a69d..dc3d214009c5 100644
--- a/hw/ppc/ppc.c
+++ b/hw/ppc/ppc.c
@@ -1350,3 +1350,8 @@ PowerPCCPU *ppc_get_vcpu_by_dt_id(int cpu_dt_id)
return NULL;
}
+
+PowerPCCPU *ppc_cpu_init(const char *cpu_model)
+{
+ return POWERPC_CPU(cpu_generic_init(TYPE_POWERPC_CPU, cpu_model));
+}
diff --git a/hw/ppc/ppc440_bamboo.c b/hw/ppc/ppc440_bamboo.c
index 5c535b18a20d..7f22433c8e91 100644
--- a/hw/ppc/ppc440_bamboo.c
+++ b/hw/ppc/ppc440_bamboo.c
@@ -186,7 +186,7 @@ static void bamboo_init(MachineState *machine)
if (machine->cpu_model == NULL) {
machine->cpu_model = "440EP";
}
- cpu = cpu_ppc_init(machine->cpu_model);
+ cpu = ppc_cpu_init(machine->cpu_model);
if (cpu == NULL) {
fprintf(stderr, "Unable to initialize CPU!\n");
exit(1);
diff --git a/hw/ppc/ppc4xx_devs.c b/hw/ppc/ppc4xx_devs.c
index e7f413e49d08..d48b61f04910 100644
--- a/hw/ppc/ppc4xx_devs.c
+++ b/hw/ppc/ppc4xx_devs.c
@@ -56,7 +56,7 @@ PowerPCCPU *ppc4xx_init(const char *cpu_model,
CPUPPCState *env;
/* init CPUs */
- cpu = cpu_ppc_init(cpu_model);
+ cpu = ppc_cpu_init(cpu_model);
if (cpu == NULL) {
fprintf(stderr, "Unable to find PowerPC %s CPU definition\n",
cpu_model);
diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c
index 054af1e8b481..e62fe643f492 100644
--- a/hw/ppc/prep.c
+++ b/hw/ppc/prep.c
@@ -509,7 +509,7 @@ static void ppc_prep_init(MachineState *machine)
if (machine->cpu_model == NULL)
machine->cpu_model = "602";
for (i = 0; i < smp_cpus; i++) {
- cpu = cpu_ppc_init(machine->cpu_model);
+ cpu = ppc_cpu_init(machine->cpu_model);
if (cpu == NULL) {
fprintf(stderr, "Unable to find PowerPC CPU definition\n");
exit(1);
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 7f33a1b2b57d..d134eb2f338e 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -1835,7 +1835,7 @@ static void ppc_spapr_init(MachineState *machine)
g_free(type);
} else {
for (i = 0; i < smp_cpus; i++) {
- PowerPCCPU *cpu = cpu_ppc_init(machine->cpu_model);
+ PowerPCCPU *cpu = ppc_cpu_init(machine->cpu_model);
if (cpu == NULL) {
error_report("Unable to find PowerPC CPU definition");
exit(1);
diff --git a/hw/ppc/virtex_ml507.c b/hw/ppc/virtex_ml507.c
index b97d96685cf1..7e4445b6879a 100644
--- a/hw/ppc/virtex_ml507.c
+++ b/hw/ppc/virtex_ml507.c
@@ -96,7 +96,7 @@ static PowerPCCPU *ppc440_init_xilinx(ram_addr_t *ram_size,
CPUPPCState *env;
qemu_irq *irqs;
- cpu = cpu_ppc_init(cpu_model);
+ cpu = ppc_cpu_init(cpu_model);
if (cpu == NULL) {
fprintf(stderr, "Unable to initialize CPU!\n");
exit(1);
diff --git a/include/hw/ppc/ppc.h b/include/hw/ppc/ppc.h
index 5617dc4a2c04..a4db1db82e1b 100644
--- a/include/hw/ppc/ppc.h
+++ b/include/hw/ppc/ppc.h
@@ -106,4 +106,5 @@ enum {
/* ppc_booke.c */
void ppc_booke_timers_init(PowerPCCPU *cpu, uint32_t freq, uint32_t flags);
+PowerPCCPU *ppc_cpu_init(const char *cpu_model);
#endif
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 2666a3f80d00..63e586298296 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1198,7 +1198,6 @@ extern const struct VMStateDescription vmstate_ppc_cpu;
#endif
/*****************************************************************************/
-PowerPCCPU *cpu_ppc_init(const char *cpu_model);
void ppc_translate_init(void);
void gen_update_current_nip(void *opaque);
/* you can call this signal handler from your SIGBUS and SIGSEGV
@@ -1277,7 +1276,9 @@ static inline uint64_t ppc_dump_gpr(CPUPPCState *env, int gprn)
int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp);
int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val);
-#define cpu_init(cpu_model) CPU(cpu_ppc_init(cpu_model))
+#if defined(CONFIG_USER_ONLY)
+#define cpu_init(cpu_model) cpu_generic_init(TYPE_POWERPC_CPU, cpu_model)
+#endif
#define cpu_signal_handler cpu_ppc_signal_handler
#define cpu_list ppc_cpu_list
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 8f257fb74aa7..31120a5aaf33 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -10012,11 +10012,6 @@ static ObjectClass *ppc_cpu_class_by_name(const char *name)
return NULL;
}
-PowerPCCPU *cpu_ppc_init(const char *cpu_model)
-{
- return POWERPC_CPU(cpu_generic_init(TYPE_POWERPC_CPU, cpu_model));
-}
-
/* Sort by PVR, ordering special case "host" last. */
static gint ppc_cpu_list_compare(gconstpointer a, gconstpointer b)
{
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [Qemu-devel] [PATCH v4 2/5] ppc: parse cpu features once
2016-07-12 11:14 [Qemu-devel] [PATCH v4 0/5] ppc: compute cpu_dt_id in the machine code Greg Kurz
2016-07-12 11:15 ` [Qemu-devel] [PATCH v4 1/5] ppc: different creation paths for cpus in system and user mode Greg Kurz
@ 2016-07-12 11:16 ` Greg Kurz
2016-07-12 12:07 ` [Qemu-devel] [Qemu-ppc] [PATCH v4 0/5] ppc: compute cpu_dt_id in the machine code Greg Kurz
2 siblings, 0 replies; 4+ messages in thread
From: Greg Kurz @ 2016-07-12 11:16 UTC (permalink / raw)
To: David Gibson; +Cc: qemu-ppc, qemu-devel, Bharata B Rao
Considering that features are converted to global properties and
global properties are automatically applied to every new instance
of created CPU (at object_new() time), there is no point in
parsing cpu_model string every time a CPU created. So move
parsing outside CPU creation loop and do it only once.
Parsing also should be done before any CPU is created so that
features would affect the first CPU a well.
This patch does that for all PowerPC machine types.
It is based on previous work from Bharata:
https://lists.nongnu.org/archive/html/qemu-devel/2016-06/msg07564.html
Signed-off-by: Greg Kurz <groug@kaod.org>
---
hw/ppc/e500.c | 2 ++
hw/ppc/mac_newworld.c | 1 +
hw/ppc/mac_oldworld.c | 1 +
hw/ppc/ppc.c | 26 ++++++++++++++++++++++++++
hw/ppc/ppc440_bamboo.c | 1 +
hw/ppc/ppc4xx_devs.c | 1 +
hw/ppc/prep.c | 1 +
hw/ppc/spapr.c | 2 ++
hw/ppc/virtex_ml507.c | 1 +
include/hw/ppc/ppc.h | 1 +
10 files changed, 37 insertions(+)
diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index ff5d92e48dd9..b9221cc2c14a 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -814,6 +814,8 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
machine->cpu_model = "e500v2_v30";
}
+ ppc_cpu_parse_features(machine->cpu_model);
+
irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *));
irqs[0] = g_malloc0(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
for (i = 0; i < smp_cpus; i++) {
diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c
index ecd40914be45..366089085844 100644
--- a/hw/ppc/mac_newworld.c
+++ b/hw/ppc/mac_newworld.c
@@ -192,6 +192,7 @@ static void ppc_core99_init(MachineState *machine)
machine->cpu_model = "G4";
#endif
}
+ ppc_cpu_parse_features(machine->cpu_model);
for (i = 0; i < smp_cpus; i++) {
cpu = ppc_cpu_init(machine->cpu_model);
if (cpu == NULL) {
diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c
index 77fbdfffd4e2..5c2dc53cb584 100644
--- a/hw/ppc/mac_oldworld.c
+++ b/hw/ppc/mac_oldworld.c
@@ -112,6 +112,7 @@ static void ppc_heathrow_init(MachineState *machine)
/* init CPUs */
if (machine->cpu_model == NULL)
machine->cpu_model = "G3";
+ ppc_cpu_parse_features(machine->cpu_model);
for (i = 0; i < smp_cpus; i++) {
cpu = ppc_cpu_init(machine->cpu_model);
if (cpu == NULL) {
diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c
index dc3d214009c5..313b3f0b9a51 100644
--- a/hw/ppc/ppc.c
+++ b/hw/ppc/ppc.c
@@ -33,6 +33,7 @@
#include "hw/timer/m48t59.h"
#include "qemu/log.h"
#include "qemu/error-report.h"
+#include "qapi/error.h"
#include "hw/loader.h"
#include "sysemu/kvm.h"
#include "kvm_ppc.h"
@@ -1355,3 +1356,28 @@ PowerPCCPU *ppc_cpu_init(const char *cpu_model)
{
return POWERPC_CPU(cpu_generic_init(TYPE_POWERPC_CPU, cpu_model));
}
+
+void ppc_cpu_parse_features(const char *cpu_model)
+{
+ CPUClass *cc;
+ ObjectClass *oc;
+ const char *typename;
+ gchar **model_pieces;
+
+ model_pieces = g_strsplit(cpu_model, ",", 2);
+ if (!model_pieces[0]) {
+ error_report("Invalid/empty CPU model name");
+ exit(1);
+ }
+
+ oc = cpu_class_by_name(TYPE_POWERPC_CPU, model_pieces[0]);
+ if (oc == NULL) {
+ error_report("Unable to find CPU definition: %s", model_pieces[0]);
+ exit(1);
+ }
+
+ typename = object_class_get_name(oc);
+ cc = CPU_CLASS(oc);
+ cc->parse_features(typename, model_pieces[1], &error_fatal);
+ g_strfreev(model_pieces);
+}
diff --git a/hw/ppc/ppc440_bamboo.c b/hw/ppc/ppc440_bamboo.c
index 7f22433c8e91..709a779cba7e 100644
--- a/hw/ppc/ppc440_bamboo.c
+++ b/hw/ppc/ppc440_bamboo.c
@@ -186,6 +186,7 @@ static void bamboo_init(MachineState *machine)
if (machine->cpu_model == NULL) {
machine->cpu_model = "440EP";
}
+ ppc_cpu_parse_features(machine->cpu_model);
cpu = ppc_cpu_init(machine->cpu_model);
if (cpu == NULL) {
fprintf(stderr, "Unable to initialize CPU!\n");
diff --git a/hw/ppc/ppc4xx_devs.c b/hw/ppc/ppc4xx_devs.c
index d48b61f04910..8cbe50361e86 100644
--- a/hw/ppc/ppc4xx_devs.c
+++ b/hw/ppc/ppc4xx_devs.c
@@ -56,6 +56,7 @@ PowerPCCPU *ppc4xx_init(const char *cpu_model,
CPUPPCState *env;
/* init CPUs */
+ ppc_cpu_parse_features(cpu_model);
cpu = ppc_cpu_init(cpu_model);
if (cpu == NULL) {
fprintf(stderr, "Unable to find PowerPC %s CPU definition\n",
diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c
index e62fe643f492..99409a09f0ef 100644
--- a/hw/ppc/prep.c
+++ b/hw/ppc/prep.c
@@ -508,6 +508,7 @@ static void ppc_prep_init(MachineState *machine)
/* init CPUs */
if (machine->cpu_model == NULL)
machine->cpu_model = "602";
+ ppc_cpu_parse_features(machine->cpu_model);
for (i = 0; i < smp_cpus; i++) {
cpu = ppc_cpu_init(machine->cpu_model);
if (cpu == NULL) {
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index d134eb2f338e..658ccee799c0 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -1803,6 +1803,8 @@ static void ppc_spapr_init(MachineState *machine)
machine->cpu_model = kvm_enabled() ? "host" : "POWER7";
}
+ ppc_cpu_parse_features(machine->cpu_model);
+
if (smc->dr_cpu_enabled) {
char *type = spapr_get_cpu_core_type(machine->cpu_model);
diff --git a/hw/ppc/virtex_ml507.c b/hw/ppc/virtex_ml507.c
index 7e4445b6879a..a19dd17addda 100644
--- a/hw/ppc/virtex_ml507.c
+++ b/hw/ppc/virtex_ml507.c
@@ -96,6 +96,7 @@ static PowerPCCPU *ppc440_init_xilinx(ram_addr_t *ram_size,
CPUPPCState *env;
qemu_irq *irqs;
+ ppc_cpu_parse_features(cpu_model);
cpu = ppc_cpu_init(cpu_model);
if (cpu == NULL) {
fprintf(stderr, "Unable to initialize CPU!\n");
diff --git a/include/hw/ppc/ppc.h b/include/hw/ppc/ppc.h
index a4db1db82e1b..2ed063e09bec 100644
--- a/include/hw/ppc/ppc.h
+++ b/include/hw/ppc/ppc.h
@@ -107,4 +107,5 @@ enum {
void ppc_booke_timers_init(PowerPCCPU *cpu, uint32_t freq, uint32_t flags);
PowerPCCPU *ppc_cpu_init(const char *cpu_model);
+void ppc_cpu_parse_features(const char *cpu_model);
#endif
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [Qemu-devel] [Qemu-ppc] [PATCH v4 0/5] ppc: compute cpu_dt_id in the machine code
2016-07-12 11:14 [Qemu-devel] [PATCH v4 0/5] ppc: compute cpu_dt_id in the machine code Greg Kurz
2016-07-12 11:15 ` [Qemu-devel] [PATCH v4 1/5] ppc: different creation paths for cpus in system and user mode Greg Kurz
2016-07-12 11:16 ` [Qemu-devel] [PATCH v4 2/5] ppc: parse cpu features once Greg Kurz
@ 2016-07-12 12:07 ` Greg Kurz
2 siblings, 0 replies; 4+ messages in thread
From: Greg Kurz @ 2016-07-12 12:07 UTC (permalink / raw)
To: David Gibson; +Cc: qemu-ppc, qemu-devel, Bharata B Rao
On Tue, 12 Jul 2016 13:14:30 +0200
Greg Kurz <groug@kaod.org> wrote:
> Here's the current patchset I have before I go on vacation, in case it is
> needed. It is nearly the same as v3: I've just dropped patches that received
> a negative review, fixed a bug and rebased.
>
> The patches are also available here:
>
> git://github.com/gkurz/qemu.git ppc-vcpu-dt-id-rework
>
> Cheers.
>
Ugh I've fumbled *again*... I'll repost shortly.
> ---
>
> Greg Kurz (5):
> ppc: different creation paths for cpus in system and user mode
> ppc: parse cpu features once
> ppc: open code cpu creation for machine types
> ppc: each machine type to provide vcpu_dt_id
> ppc: drop vcpu_idt_id bits from the target code
>
>
> hw/ppc/e500.c | 4 ++-
> hw/ppc/mac_newworld.c | 3 +-
> hw/ppc/mac_oldworld.c | 3 +-
> hw/ppc/ppc.c | 64 +++++++++++++++++++++++++++++++++++++++++++
> hw/ppc/ppc440_bamboo.c | 3 +-
> hw/ppc/ppc4xx_devs.c | 3 +-
> hw/ppc/prep.c | 3 +-
> hw/ppc/spapr.c | 7 ++++-
> hw/ppc/spapr_cpu_core.c | 7 +++--
> hw/ppc/virtex_ml507.c | 3 +-
> include/hw/ppc/ppc.h | 2 +
> target-ppc/cpu.h | 5 ++-
> target-ppc/translate_init.c | 20 -------------
> 13 files changed, 95 insertions(+), 32 deletions(-)
>
> --
> Greg
>
>
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2016-07-12 12:07 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-07-12 11:14 [Qemu-devel] [PATCH v4 0/5] ppc: compute cpu_dt_id in the machine code Greg Kurz
2016-07-12 11:15 ` [Qemu-devel] [PATCH v4 1/5] ppc: different creation paths for cpus in system and user mode Greg Kurz
2016-07-12 11:16 ` [Qemu-devel] [PATCH v4 2/5] ppc: parse cpu features once Greg Kurz
2016-07-12 12:07 ` [Qemu-devel] [Qemu-ppc] [PATCH v4 0/5] ppc: compute cpu_dt_id in the machine code Greg Kurz
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).