0c76f22ef1
- bnc#633573 - System fail to boot after running several warm reboot tests 22749-vtd-workarounds.patch - Upstream patches from Jan 22744-ept-pod-locking.patch 22777-vtd-ats-fixes.patch 22781-pod-hap-logdirty.patch 22782-x86-emul-smsw.patch 22789-i386-no-x2apic.patch 22790-svm-resume-migrate-pirqs.patch 22816-x86-pirq-drop-priv-check.patch OBS-URL: https://build.opensuse.org/package/show/Virtualization/xen?expand=0&rev=94
484 lines
15 KiB
Diff
484 lines
15 KiB
Diff
# HG changeset patch
|
|
# User Keir Fraser <keir.fraser@citrix.com>
|
|
# Date 1279284738 -3600
|
|
# Node ID fedab6367c9a0141d49853c77a23d6642ba70ff6
|
|
# Parent 1f7c2418e58c7d1d5650ea211016b30114de48f2
|
|
ACPI: add support for x2APIC ACPI extensions
|
|
References: bnc#656369, bnc#658704
|
|
|
|
All logical processors with APIC ID values of 255 and greater will
|
|
have their APIC reported through Processor X2APIC structure (type-9
|
|
entry type) and all logical processors with APIC ID less than 255 will
|
|
have their APIC reported through legacy Processor Local APIC (type-0
|
|
entry type) only. This is the same case even for NMI structure
|
|
reporting.
|
|
|
|
The Processor X2APIC Affinity structure provides the association
|
|
between the X2APIC ID of a logical processor and the proximity domain
|
|
to which the logical processor belongs.
|
|
|
|
This patch adds 2 new subtables to MADT and one new subtable to SRAT.
|
|
|
|
This patch also changes x86_acpiid_to_apicid from u8 to u32 for x2APIC
|
|
ID, and changes mp_register_lapic to accept 32-bit id. But there are
|
|
still some 8-bit apic id hardcode and assumptions in Xen code, it
|
|
needs to be fixed in future.
|
|
|
|
Signed-off-by: Weidong Han <weidong.han@intel.com>
|
|
|
|
Index: xen-4.0.2-testing/xen/arch/x86/acpi/boot.c
|
|
===================================================================
|
|
--- xen-4.0.2-testing.orig/xen/arch/x86/acpi/boot.c
|
|
+++ xen-4.0.2-testing/xen/arch/x86/acpi/boot.c
|
|
@@ -81,7 +81,7 @@ u8 acpi_enable_value, acpi_disable_value
|
|
#warning ACPI uses CMPXCHG, i486 and later hardware
|
|
#endif
|
|
|
|
-u8 x86_acpiid_to_apicid[MAX_MADT_ENTRIES] =
|
|
+u32 x86_acpiid_to_apicid[MAX_MADT_ENTRIES] =
|
|
{[0 ... MAX_MADT_ENTRIES - 1] = 0xff };
|
|
EXPORT_SYMBOL(x86_acpiid_to_apicid);
|
|
|
|
@@ -156,6 +156,35 @@ static int __init acpi_parse_madt(struct
|
|
}
|
|
|
|
static int __init
|
|
+acpi_parse_x2apic(struct acpi_subtable_header *header, const unsigned long end)
|
|
+{
|
|
+ struct acpi_table_x2apic *processor = NULL;
|
|
+
|
|
+ processor = (struct acpi_table_x2apic *)header;
|
|
+
|
|
+ if (BAD_MADT_ENTRY(processor, end))
|
|
+ return -EINVAL;
|
|
+
|
|
+ acpi_table_print_madt_entry(header);
|
|
+
|
|
+ /* Record local apic id only when enabled */
|
|
+ if (processor->flags.enabled)
|
|
+ x86_acpiid_to_apicid[processor->acpi_uid] = processor->id;
|
|
+
|
|
+ /*
|
|
+ * We need to register disabled CPU as well to permit
|
|
+ * counting disabled CPUs. This allows us to size
|
|
+ * cpus_possible_map more accurately, to permit
|
|
+ * to not preallocating memory for all NR_CPUS
|
|
+ * when we use CPU hotplug.
|
|
+ */
|
|
+ mp_register_lapic(processor->id, /* X2APIC ID */
|
|
+ processor->flags.enabled); /* Enabled? */
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int __init
|
|
acpi_parse_lapic(struct acpi_subtable_header * header, const unsigned long end)
|
|
{
|
|
struct acpi_table_lapic *processor = NULL;
|
|
@@ -201,6 +230,25 @@ acpi_parse_lapic_addr_ovr(struct acpi_su
|
|
}
|
|
|
|
static int __init
|
|
+acpi_parse_x2apic_nmi(struct acpi_subtable_header *header,
|
|
+ const unsigned long end)
|
|
+{
|
|
+ struct acpi_table_x2apic_nmi *x2apic_nmi = NULL;
|
|
+
|
|
+ x2apic_nmi = (struct acpi_table_x2apic_nmi *)header;
|
|
+
|
|
+ if (BAD_MADT_ENTRY(x2apic_nmi, end))
|
|
+ return -EINVAL;
|
|
+
|
|
+ acpi_table_print_madt_entry(header);
|
|
+
|
|
+ if (x2apic_nmi->lint != 1)
|
|
+ printk(KERN_WARNING PREFIX "NMI not connected to LINT 1!\n");
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int __init
|
|
acpi_parse_lapic_nmi(struct acpi_subtable_header * header, const unsigned long end)
|
|
{
|
|
struct acpi_table_lapic_nmi *lapic_nmi = NULL;
|
|
@@ -465,7 +513,7 @@ static int __init acpi_parse_fadt(struct
|
|
*/
|
|
static int __init acpi_parse_madt_lapic_entries(void)
|
|
{
|
|
- int count;
|
|
+ int count, x2count;
|
|
|
|
if (!cpu_has_apic)
|
|
return -ENODEV;
|
|
@@ -488,11 +536,13 @@ static int __init acpi_parse_madt_lapic_
|
|
|
|
count = acpi_table_parse_madt(ACPI_MADT_LAPIC, acpi_parse_lapic,
|
|
MAX_APICS);
|
|
- if (!count) {
|
|
+ x2count = acpi_table_parse_madt(ACPI_MADT_X2APIC, acpi_parse_x2apic,
|
|
+ MAX_APICS);
|
|
+ if (!count && !x2count) {
|
|
printk(KERN_ERR PREFIX "No LAPIC entries present\n");
|
|
/* TBD: Cleanup to allow fallback to MPS */
|
|
return -ENODEV;
|
|
- } else if (count < 0) {
|
|
+ } else if (count < 0 || x2count < 0) {
|
|
printk(KERN_ERR PREFIX "Error parsing LAPIC entry\n");
|
|
/* TBD: Cleanup to allow fallback to MPS */
|
|
return count;
|
|
@@ -500,7 +550,10 @@ static int __init acpi_parse_madt_lapic_
|
|
|
|
count =
|
|
acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi, 0);
|
|
- if (count < 0) {
|
|
+ x2count =
|
|
+ acpi_table_parse_madt(ACPI_MADT_X2APIC_NMI,
|
|
+ acpi_parse_x2apic_nmi, 0);
|
|
+ if (count < 0 || x2count < 0) {
|
|
printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n");
|
|
/* TBD: Cleanup to allow fallback to MPS */
|
|
return count;
|
|
Index: xen-4.0.2-testing/xen/arch/x86/mpparse.c
|
|
===================================================================
|
|
--- xen-4.0.2-testing.orig/xen/arch/x86/mpparse.c
|
|
+++ xen-4.0.2-testing/xen/arch/x86/mpparse.c
|
|
@@ -838,7 +838,7 @@ void __init mp_register_lapic_address (
|
|
|
|
|
|
int __devinit mp_register_lapic (
|
|
- u8 id,
|
|
+ u32 id,
|
|
u8 enabled)
|
|
{
|
|
struct mpc_config_processor processor;
|
|
Index: xen-4.0.2-testing/xen/arch/x86/srat.c
|
|
===================================================================
|
|
--- xen-4.0.2-testing.orig/xen/arch/x86/srat.c
|
|
+++ xen-4.0.2-testing/xen/arch/x86/srat.c
|
|
@@ -164,6 +164,36 @@ void __init acpi_numa_slit_init(struct a
|
|
}
|
|
#endif
|
|
|
|
+/* Callback for Proximity Domain -> x2APIC mapping */
|
|
+void __init
|
|
+acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa)
|
|
+{
|
|
+ int pxm, node;
|
|
+ int apic_id;
|
|
+
|
|
+ if (srat_disabled())
|
|
+ return;
|
|
+ if (pa->header.length < sizeof(struct acpi_srat_x2apic_cpu_affinity)) {
|
|
+ bad_srat();
|
|
+ return;
|
|
+ }
|
|
+ if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0)
|
|
+ return;
|
|
+ pxm = pa->proximity_domain;
|
|
+ node = setup_node(pxm);
|
|
+ if (node < 0) {
|
|
+ printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm);
|
|
+ bad_srat();
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ apic_id = pa->apic_id;
|
|
+ apicid_to_node[apic_id] = node;
|
|
+ acpi_numa = 1;
|
|
+ printk(KERN_INFO "SRAT: PXM %u -> APIC %u -> Node %u\n",
|
|
+ pxm, apic_id, node);
|
|
+}
|
|
+
|
|
/* Callback for Proximity Domain -> LAPIC mapping */
|
|
void __init
|
|
acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa)
|
|
Index: xen-4.0.2-testing/xen/drivers/acpi/numa.c
|
|
===================================================================
|
|
--- xen-4.0.2-testing.orig/xen/drivers/acpi/numa.c
|
|
+++ xen-4.0.2-testing/xen/drivers/acpi/numa.c
|
|
@@ -90,6 +90,21 @@ void __init acpi_table_print_srat_entry(
|
|
#endif /* ACPI_DEBUG_OUTPUT */
|
|
break;
|
|
|
|
+ case ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY:
|
|
+#ifdef ACPI_DEBUG_OUTPUT
|
|
+ {
|
|
+ struct acpi_srat_x2apic_cpu_affinity *p =
|
|
+ (struct acpi_srat_x2apic_cpu_affinity *)header;
|
|
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
|
+ "SRAT Processor (x2apicid[0x%08x]) in"
|
|
+ " proximity domain %d %s\n",
|
|
+ p->apic_id,
|
|
+ p->proximity_domain,
|
|
+ (p->flags & ACPI_SRAT_CPU_ENABLED) ?
|
|
+ "enabled" : "disabled"));
|
|
+ }
|
|
+#endif /* ACPI_DEBUG_OUTPUT */
|
|
+ break;
|
|
default:
|
|
printk(KERN_WARNING PREFIX
|
|
"Found unsupported SRAT entry (type = 0x%x)\n",
|
|
@@ -105,6 +120,33 @@ static int __init acpi_parse_slit(struct
|
|
return 0;
|
|
}
|
|
|
|
+void __init __attribute__ ((weak))
|
|
+acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa)
|
|
+{
|
|
+ printk(KERN_WARNING PREFIX
|
|
+ "Found unsupported x2apic [0x%08x] SRAT entry\n", pa->apic_id);
|
|
+ return;
|
|
+}
|
|
+
|
|
+
|
|
+static int __init
|
|
+acpi_parse_x2apic_affinity(struct acpi_subtable_header *header,
|
|
+ const unsigned long end)
|
|
+{
|
|
+ struct acpi_srat_x2apic_cpu_affinity *processor_affinity;
|
|
+
|
|
+ processor_affinity = (struct acpi_srat_x2apic_cpu_affinity *)header;
|
|
+ if (!processor_affinity)
|
|
+ return -EINVAL;
|
|
+
|
|
+ acpi_table_print_srat_entry(header);
|
|
+
|
|
+ /* let architecture-dependent part to do it */
|
|
+ acpi_numa_x2apic_affinity_init(processor_affinity);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static int __init
|
|
acpi_parse_processor_affinity(struct acpi_subtable_header * header,
|
|
const unsigned long end)
|
|
@@ -164,6 +206,8 @@ int __init acpi_numa_init(void)
|
|
{
|
|
/* SRAT: Static Resource Affinity Table */
|
|
if (!acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat)) {
|
|
+ acpi_table_parse_srat(ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY,
|
|
+ acpi_parse_x2apic_affinity, NR_CPUS);
|
|
acpi_table_parse_srat(ACPI_SRAT_PROCESSOR_AFFINITY,
|
|
acpi_parse_processor_affinity,
|
|
NR_CPUS);
|
|
Index: xen-4.0.2-testing/xen/drivers/acpi/tables.c
|
|
===================================================================
|
|
--- xen-4.0.2-testing.orig/xen/drivers/acpi/tables.c
|
|
+++ xen-4.0.2-testing/xen/drivers/acpi/tables.c
|
|
@@ -63,6 +63,18 @@ void __init acpi_table_print_madt_entry(
|
|
}
|
|
break;
|
|
|
|
+ case ACPI_MADT_TYPE_LOCAL_X2APIC:
|
|
+ {
|
|
+ struct acpi_madt_local_x2apic *p =
|
|
+ (struct acpi_madt_local_x2apic *)header;
|
|
+ printk(KERN_INFO PREFIX
|
|
+ "X2APIC (apic_id[0x%02x] uid[0x%02x] %s)\n",
|
|
+ p->local_apic_id, p->uid,
|
|
+ (p->lapic_flags & ACPI_MADT_ENABLED) ?
|
|
+ "enabled" : "disabled");
|
|
+ }
|
|
+ break;
|
|
+
|
|
case ACPI_MADT_TYPE_IO_APIC:
|
|
{
|
|
struct acpi_madt_io_apic *p =
|
|
@@ -116,6 +128,24 @@ void __init acpi_table_print_madt_entry(
|
|
p->lint);
|
|
}
|
|
break;
|
|
+
|
|
+ case ACPI_MADT_TYPE_LOCAL_X2APIC_NMI:
|
|
+ {
|
|
+ u16 polarity, trigger;
|
|
+ struct acpi_madt_local_x2apic_nmi *p =
|
|
+ (struct acpi_madt_local_x2apic_nmi *)header;
|
|
+
|
|
+ polarity = p->inti_flags & ACPI_MADT_POLARITY_MASK;
|
|
+ trigger = (p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2;
|
|
+
|
|
+ printk(KERN_INFO PREFIX
|
|
+ "X2APIC_NMI (uid[0x%02x] %s %s lint[0x%x])\n",
|
|
+ p->uid,
|
|
+ mps_inti_flags_polarity[polarity],
|
|
+ mps_inti_flags_trigger[trigger],
|
|
+ p->lint);
|
|
+ }
|
|
+ break;
|
|
|
|
case ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE:
|
|
{
|
|
Index: xen-4.0.2-testing/xen/include/acpi/actbl1.h
|
|
===================================================================
|
|
--- xen-4.0.2-testing.orig/xen/include/acpi/actbl1.h
|
|
+++ xen-4.0.2-testing/xen/include/acpi/actbl1.h
|
|
@@ -404,7 +404,9 @@ enum acpi_madt_type {
|
|
ACPI_MADT_TYPE_IO_SAPIC = 6,
|
|
ACPI_MADT_TYPE_LOCAL_SAPIC = 7,
|
|
ACPI_MADT_TYPE_INTERRUPT_SOURCE = 8,
|
|
- ACPI_MADT_TYPE_RESERVED = 9 /* 9 and greater are reserved */
|
|
+ ACPI_MADT_TYPE_LOCAL_X2APIC = 9,
|
|
+ ACPI_MADT_TYPE_LOCAL_X2APIC_NMI = 10,
|
|
+ ACPI_MADT_TYPE_RESERVED = 11 /* 11 and greater are reserved */
|
|
};
|
|
|
|
/*
|
|
@@ -505,6 +507,26 @@ struct acpi_madt_interrupt_source {
|
|
|
|
#define ACPI_MADT_CPEI_OVERRIDE (1)
|
|
|
|
+/* 9: Processor Local X2APIC (ACPI 4.0) */
|
|
+
|
|
+struct acpi_madt_local_x2apic {
|
|
+ struct acpi_subtable_header header;
|
|
+ u16 reserved; /* Reserved - must be zero */
|
|
+ u32 local_apic_id; /* Processor X2_APIC ID */
|
|
+ u32 lapic_flags;
|
|
+ u32 uid; /* Extended X2_APIC processor ID */
|
|
+};
|
|
+
|
|
+/* 10: Local X2APIC NMI (ACPI 4.0) */
|
|
+
|
|
+struct acpi_madt_local_x2apic_nmi {
|
|
+ struct acpi_subtable_header header;
|
|
+ u16 inti_flags;
|
|
+ u32 uid; /* Processor X2_APIC ID */
|
|
+ u8 lint; /* LINTn to which NMI is connected */
|
|
+ u8 reserved[3];
|
|
+};
|
|
+
|
|
/*
|
|
* Common flags fields for MADT subtables
|
|
*/
|
|
@@ -646,11 +668,14 @@ struct acpi_table_srat {
|
|
enum acpi_srat_type {
|
|
ACPI_SRAT_TYPE_CPU_AFFINITY = 0,
|
|
ACPI_SRAT_TYPE_MEMORY_AFFINITY = 1,
|
|
- ACPI_SRAT_TYPE_RESERVED = 2
|
|
+ ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY = 2,
|
|
+ ACPI_SRAT_TYPE_RESERVED = 3 /* 3 and greater are reserved */
|
|
};
|
|
|
|
/* SRAT sub-tables */
|
|
|
|
+/* 0: Processor Local APIC/SAPIC Affinity */
|
|
+
|
|
struct acpi_srat_cpu_affinity {
|
|
struct acpi_subtable_header header;
|
|
u8 proximity_domain_lo;
|
|
@@ -661,9 +686,7 @@ struct acpi_srat_cpu_affinity {
|
|
u32 reserved; /* Reserved, must be zero */
|
|
};
|
|
|
|
-/* Flags */
|
|
-
|
|
-#define ACPI_SRAT_CPU_ENABLED (1) /* 00: Use affinity structure */
|
|
+/* 1: Memory Affinity */
|
|
|
|
struct acpi_srat_mem_affinity {
|
|
struct acpi_subtable_header header;
|
|
@@ -682,6 +705,22 @@ struct acpi_srat_mem_affinity {
|
|
#define ACPI_SRAT_MEM_HOT_PLUGGABLE (1<<1) /* 01: Memory region is hot pluggable */
|
|
#define ACPI_SRAT_MEM_NON_VOLATILE (1<<2) /* 02: Memory region is non-volatile */
|
|
|
|
+/* 2: Processor Local X2_APIC Affinity (ACPI 4.0) */
|
|
+
|
|
+struct acpi_srat_x2apic_cpu_affinity {
|
|
+ struct acpi_subtable_header header;
|
|
+ u16 reserved; /* Reserved, must be zero */
|
|
+ u32 proximity_domain;
|
|
+ u32 apic_id;
|
|
+ u32 flags;
|
|
+ u32 clock_domain;
|
|
+ u32 reserved2;
|
|
+};
|
|
+
|
|
+/* Flags for struct acpi_srat_cpu_affinity and struct acpi_srat_x2apic_cpu_affinity */
|
|
+
|
|
+#define ACPI_SRAT_CPU_ENABLED (1) /* 00: Use affinity structure */
|
|
+
|
|
/*******************************************************************************
|
|
*
|
|
* TCPA - Trusted Computing Platform Alliance table
|
|
Index: xen-4.0.2-testing/xen/include/asm-x86/acpi.h
|
|
===================================================================
|
|
--- xen-4.0.2-testing.orig/xen/include/asm-x86/acpi.h
|
|
+++ xen-4.0.2-testing/xen/include/asm-x86/acpi.h
|
|
@@ -151,7 +151,7 @@ struct acpi_sleep_info {
|
|
#endif /* CONFIG_ACPI_SLEEP */
|
|
|
|
#define MAX_MADT_ENTRIES 256
|
|
-extern u8 x86_acpiid_to_apicid[];
|
|
+extern u32 x86_acpiid_to_apicid[];
|
|
#define MAX_LOCAL_APIC 256
|
|
|
|
extern u32 pmtmr_ioport;
|
|
Index: xen-4.0.2-testing/xen/include/asm-x86/mpspec.h
|
|
===================================================================
|
|
--- xen-4.0.2-testing.orig/xen/include/asm-x86/mpspec.h
|
|
+++ xen-4.0.2-testing/xen/include/asm-x86/mpspec.h
|
|
@@ -24,7 +24,7 @@ extern int pic_mode;
|
|
extern int using_apic_timer;
|
|
|
|
#ifdef CONFIG_ACPI
|
|
-extern int mp_register_lapic (u8 id, u8 enabled);
|
|
+extern int mp_register_lapic (u32 id, u8 enabled);
|
|
extern void mp_unregister_lapic(uint32_t apic_id, uint32_t cpu);
|
|
extern void mp_register_lapic_address (u64 address);
|
|
extern void mp_register_ioapic (u8 id, u32 address, u32 gsi_base);
|
|
Index: xen-4.0.2-testing/xen/include/xen/acpi.h
|
|
===================================================================
|
|
--- xen-4.0.2-testing.orig/xen/include/xen/acpi.h
|
|
+++ xen-4.0.2-testing/xen/include/xen/acpi.h
|
|
@@ -57,6 +57,8 @@ enum acpi_madt_entry_id {
|
|
ACPI_MADT_IOSAPIC,
|
|
ACPI_MADT_LSAPIC,
|
|
ACPI_MADT_PLAT_INT_SRC,
|
|
+ ACPI_MADT_X2APIC,
|
|
+ ACPI_MADT_X2APIC_NMI,
|
|
ACPI_MADT_ENTRY_COUNT
|
|
};
|
|
|
|
@@ -76,6 +78,17 @@ struct acpi_table_lapic {
|
|
} flags;
|
|
} __attribute__ ((packed));
|
|
|
|
+struct acpi_table_x2apic {
|
|
+ struct acpi_subtable_header header;
|
|
+ u16 reserved;
|
|
+ u32 id;
|
|
+ struct {
|
|
+ u32 enabled:1;
|
|
+ u32 reserved:31;
|
|
+ } flags;
|
|
+ u32 acpi_uid;
|
|
+} __attribute__ ((packed));
|
|
+
|
|
struct acpi_table_ioapic {
|
|
struct acpi_subtable_header header;
|
|
u8 id;
|
|
@@ -105,6 +118,14 @@ struct acpi_table_lapic_nmi {
|
|
u8 lint;
|
|
} __attribute__ ((packed));
|
|
|
|
+struct acpi_table_x2apic_nmi {
|
|
+ struct acpi_subtable_header header;
|
|
+ acpi_interrupt_flags flags;
|
|
+ u32 acpi_uid;
|
|
+ u8 lint;
|
|
+ u8 reserved[3];
|
|
+} __attribute__ ((packed));
|
|
+
|
|
struct acpi_table_lapic_addr_ovr {
|
|
struct acpi_subtable_header header;
|
|
u8 reserved[2];
|
|
@@ -280,6 +301,7 @@ void acpi_table_print_srat_entry (struct
|
|
/* the following four functions are architecture-dependent */
|
|
void acpi_numa_slit_init (struct acpi_table_slit *slit);
|
|
void acpi_numa_processor_affinity_init (struct acpi_srat_cpu_affinity *pa);
|
|
+void acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa);
|
|
void acpi_numa_memory_affinity_init (struct acpi_srat_mem_affinity *ma);
|
|
void acpi_numa_arch_fixup(void);
|
|
|