patch-2.3.99-pre4 linux/arch/i386/kernel/acpi.c
Next file: linux/arch/i386/kernel/head.S
Previous file: linux/arch/i386/kernel/Makefile
Back to the patch index
Back to the overall index
- Lines: 560
- Date:
Wed Apr 5 17:04:37 2000
- Orig file:
v2.3.99-pre3/linux/arch/i386/kernel/acpi.c
- Orig date:
Sun Mar 19 18:35:30 2000
diff -u --recursive --new-file v2.3.99-pre3/linux/arch/i386/kernel/acpi.c linux/arch/i386/kernel/acpi.c
@@ -103,13 +103,57 @@
enum
{
- ACPI_ENABLED,
- ACPI_TABLES_ONLY,
- ACPI_CHIPSET_ONLY,
- ACPI_DISABLED,
+ ACPI_ENABLED = 0x00000000, // use ACPI if present
+ ACPI_DISABLED = 0x00000001, // never use ACPI
+ ACPI_TABLES_ONLY = 0x00000002, // never use chipset-specific driver
+ ACPI_CHIPSET_ONLY = 0x00000004, // always use chipset-specific driver
+ ACPI_IGNORE_ERRATA = 0x00000008, // ignore any listed platform errata
+ ACPI_COPY_TABLES = 0x00000010, // copy ACPI tables before use
+ ACPI_TRUST_TABLES = 0x00000020, // use tables even after ioremap fails
+ ACPI_SCI_DISABLED = 0x00000040, // never enable ACPI (info. only)
+ ACPI_C2_DISABLED = 0x00000080, // never enter C2
+ ACPI_C3_DISABLED = 0x00000100, // never enter C3
+ ACPI_S1_DISABLED = 0x00000200, // never enter S1
+ ACPI_S5_DISABLED = 0x00000400, // never enter S5
};
-static int acpi_enabled = ACPI_ENABLED;
+struct acpi_option_info
+{
+ const char *name;
+ unsigned long value;
+};
+
+static struct acpi_option_info acpi_options[] =
+{
+ {"on", ACPI_ENABLED},
+ {"off", ACPI_DISABLED},
+ {"tables", ACPI_TABLES_ONLY},
+ {"chipset", ACPI_CHIPSET_ONLY},
+ {"no-errata", ACPI_IGNORE_ERRATA},
+ {"copy-tables", ACPI_COPY_TABLES},
+ {"trust-tables", ACPI_TRUST_TABLES},
+ {"no-sci", ACPI_SCI_DISABLED},
+ {"no-c2", ACPI_C2_DISABLED},
+ {"no-c3", ACPI_C3_DISABLED},
+ {"no-s1", ACPI_S1_DISABLED},
+ {"no-s5", ACPI_S5_DISABLED},
+ {NULL, 0},
+};
+
+static unsigned long acpi_opts = ACPI_ENABLED;
+
+struct acpi_errata_info
+{
+ const char *oem;
+ const char *oem_table;
+ u32 oem_rev;
+ unsigned long options;
+};
+
+struct acpi_errata_info acpi_errata[] =
+{
+ {NULL, NULL, 0, 0},
+};
// bits 8-15 are SLP_TYPa, bits 0-7 are SLP_TYPb
static unsigned long acpi_slp_typ[] =
@@ -171,7 +215,7 @@
&acpi_p_lvl3_lat, sizeof(acpi_p_lvl3_lat),
0644, NULL, &acpi_do_ulong},
- {ACPI_P_LVL2_LAT, "enter_lvl2_lat",
+ {ACPI_ENTER_LVL2_LAT, "enter_lvl2_lat",
&acpi_enter_lvl2_lat, sizeof(acpi_enter_lvl2_lat),
0644, NULL, &acpi_do_ulong},
@@ -405,6 +449,16 @@
printk(KERN_ERR
"ACPI: unreserved table memory @ 0x%p!\n",
(void*) addr);
+
+ if (acpi_opts & ACPI_TRUST_TABLES) {
+ /* OK, trust that the table is there
+ * if it isn't you'll get an OOPS here
+ */
+ static u32 sig;
+ table = (struct acpi_table *)
+ phys_to_virt(addr);
+ sig = table->signature;
+ }
}
}
return table;
@@ -423,14 +477,33 @@
/*
* Initialize an ACPI table
*/
-static void acpi_init_table(struct acpi_table_info *info,
- void *data,
- int mapped)
+static int acpi_init_table(struct acpi_table_info *info,
+ void *data,
+ int mapped)
{
struct acpi_table *table = (struct acpi_table*) data;
+
+ info->table = NULL;
+ info->size = 0;
+ info->mapped = 0;
+
+ if (!table || table->signature != info->expected_signature)
+ return -EINVAL;
+
+ if (mapped && (acpi_opts & ACPI_COPY_TABLES)) {
+ struct acpi_table *copy
+ = kmalloc(table->length, GFP_KERNEL);
+ if (!copy)
+ return -ENOMEM;
+ memcpy(copy, table, table->length);
+ table = copy;
+ mapped = 0;
+ }
+
info->table = table;
- info->size = (size_t)(table ? table->length:0);
+ info->size = (size_t) table->length;
info->mapped = mapped;
+ return 0;
}
/*
@@ -502,22 +575,13 @@
rsdt_entry_count = (int) ((rsdt->length - sizeof(*rsdt)) >> 2);
while (rsdt_entry_count) {
struct acpi_table *dt = acpi_map_table(*rsdt_entry);
- if (dt && dt->signature == ACPI_FACP_SIG) {
- struct acpi_facp *facp = (struct acpi_facp*) dt;
- acpi_init_table(&acpi_facp, dt, 1);
+ if (!acpi_init_table(&acpi_facp, dt, 1)) {
+ struct acpi_facp *facp
+ = (struct acpi_facp*) acpi_facp.table;
// map DSDT if it exists
dt = acpi_map_table(facp->dsdt);
- if (dt && dt->signature == ACPI_DSDT_SIG)
- acpi_init_table(&acpi_dsdt, dt, 1);
- else
- acpi_unmap_table(dt);
-
- // map FACS if it exists
- dt = acpi_map_table(facp->facs);
- if (dt && dt->signature == ACPI_FACS_SIG)
- acpi_init_table(&acpi_facs, dt, 1);
- else
+ if (acpi_init_table(&acpi_dsdt, dt, 1))
acpi_unmap_table(dt);
}
else {
@@ -769,6 +833,15 @@
}
/*
+ * Is SCI to be enabled?
+ */
+static inline int
+acpi_sci_enabled(void)
+{
+ return !(acpi_opts & ACPI_SCI_DISABLED);
+}
+
+/*
* Is ACPI enabled or not?
*/
static inline int acpi_is_enabled(struct acpi_facp *facp)
@@ -781,7 +854,7 @@
*/
static int acpi_enable(struct acpi_facp *facp)
{
- if (facp->smi_cmd)
+ if (facp->smi_cmd && acpi_sci_enabled())
outb(facp->acpi_enable, facp->smi_cmd);
return (acpi_is_enabled(facp) ? 0:-1);
}
@@ -791,16 +864,20 @@
*/
static int acpi_disable(struct acpi_facp *facp)
{
- // disable and clear any pending events
- acpi_write_gpe_enable(facp, 0);
- while (acpi_read_gpe_status(facp))
- acpi_write_gpe_status(facp, acpi_read_gpe_status(facp));
- acpi_write_pm1_enable(facp, 0);
- acpi_write_pm1_status(facp, acpi_read_pm1_status(facp));
-
- /* writing acpi_disable to smi_cmd would be appropriate
- * here but this causes a nasty crash on many systems
- */
+ if (facp->smi_cmd && acpi_sci_enabled()) {
+ // disable and clear any pending events
+ acpi_write_gpe_enable(facp, 0);
+ while (acpi_read_gpe_status(facp)) {
+ acpi_write_gpe_status(facp,
+ acpi_read_gpe_status(facp));
+ }
+ acpi_write_pm1_enable(facp, 0);
+ acpi_write_pm1_status(facp, acpi_read_pm1_status(facp));
+
+ /* writing acpi_disable to smi_cmd would be appropriate
+ * here but this causes a nasty crash on many systems
+ */
+ }
return 0;
}
@@ -860,7 +937,7 @@
sleep3:
sleep_level = 3;
if (!acpi_p_lvl3_tested) {
- printk("ACPI C3 works\n");
+ printk(KERN_INFO "ACPI C3 works\n");
acpi_p_lvl3_tested = 1;
}
wake_on_busmaster(facp);
@@ -916,7 +993,7 @@
sleep2:
sleep_level = 2;
if (!acpi_p_lvl2_tested) {
- printk("ACPI C2 works\n");
+ printk(KERN_INFO "ACPI C2 works\n");
acpi_p_lvl2_tested = 1;
}
wake_on_busmaster(facp); /* Required to track BM activity.. */
@@ -1006,47 +1083,52 @@
}
}
-
/*
* Enter system sleep state
*/
-static void acpi_enter_sx(acpi_sstate_t state)
+static int acpi_enter_sx(acpi_sstate_t state)
{
- unsigned long slp_typ = acpi_slp_typ[(int) state];
- if (slp_typ != ACPI_SLP_TYP_DISABLED) {
- struct acpi_facp *facp = (struct acpi_facp*) acpi_facp.table;
- u16 typa, typb, value;
-
- // bits 8-15 are SLP_TYPa, bits 0-7 are SLP_TYPb
- typa = (slp_typ >> 8) & 0xff;
- typb = slp_typ & 0xff;
-
- typa = ((typa << ACPI_SLP_TYP_SHIFT) & ACPI_SLP_TYP_MASK);
- typb = ((typb << ACPI_SLP_TYP_SHIFT) & ACPI_SLP_TYP_MASK);
-
- acpi_sleep_start = get_cmos_time();
- acpi_enter_dx(ACPI_D3);
- acpi_sleep_state = state;
-
- // clear wake status
- acpi_write_pm1_status(facp, ACPI_WAK);
-
- // set SLP_TYPa/b and SLP_EN
- if (facp->pm1a_cnt) {
- value = inw(facp->pm1a_cnt) & ~ACPI_SLP_TYP_MASK;
- outw(value | typa | ACPI_SLP_EN, facp->pm1a_cnt);
- }
- if (facp->pm1b_cnt) {
- value = inw(facp->pm1b_cnt) & ~ACPI_SLP_TYP_MASK;
- outw(value | typb | ACPI_SLP_EN, facp->pm1b_cnt);
- }
-
- // wait until S1 is entered
- while (!(acpi_read_pm1_status(facp) & ACPI_WAK)) ;
- // finished sleeping, update system time
- acpi_update_clock();
- acpi_enter_dx(ACPI_D0);
+ unsigned long slp_typ;
+ u16 typa, typb, value;
+ struct acpi_facp *facp;
+
+ slp_typ = acpi_slp_typ[(int) state];
+ if (slp_typ == ACPI_SLP_TYP_DISABLED)
+ return -EPERM;
+
+ // bits 8-15 are SLP_TYPa, bits 0-7 are SLP_TYPb
+ typa = (slp_typ >> 8) & 0xff;
+ typb = slp_typ & 0xff;
+
+ typa = ((typa << ACPI_SLP_TYP_SHIFT) & ACPI_SLP_TYP_MASK);
+ typb = ((typb << ACPI_SLP_TYP_SHIFT) & ACPI_SLP_TYP_MASK);
+
+ acpi_sleep_start = get_cmos_time();
+ acpi_enter_dx(ACPI_D3);
+ acpi_sleep_state = state;
+
+ facp = (struct acpi_facp*) acpi_facp.table;
+
+ // clear wake status
+ acpi_write_pm1_status(facp, ACPI_WAK);
+
+ // set SLP_TYPa/b and SLP_EN
+ if (facp->pm1a_cnt) {
+ value = inw(facp->pm1a_cnt) & ~ACPI_SLP_TYP_MASK;
+ outw(value | typa | ACPI_SLP_EN, facp->pm1a_cnt);
+ }
+ if (facp->pm1b_cnt) {
+ value = inw(facp->pm1b_cnt) & ~ACPI_SLP_TYP_MASK;
+ outw(value | typb | ACPI_SLP_EN, facp->pm1b_cnt);
}
+
+ // wait until S1 is entered
+ while (!(acpi_read_pm1_status(facp) & ACPI_WAK)) ;
+ // finished sleeping, update system time
+ acpi_update_clock();
+ acpi_enter_dx(ACPI_D0);
+
+ return 0;
}
/*
@@ -1113,6 +1195,42 @@
}
/*
+ * Determine if modification of value is permitted
+ */
+static int
+acpi_verify_mod(int ctl_name)
+{
+ switch (ctl_name) {
+ case ACPI_PM1_ENABLE:
+ case ACPI_GPE_ENABLE:
+ case ACPI_GPE_LEVEL:
+ if (!acpi_sci_enabled())
+ return -EPERM;
+ break;
+ case ACPI_P_LVL2_LAT:
+ case ACPI_ENTER_LVL2_LAT:
+ if (acpi_opts & ACPI_C2_DISABLED)
+ return -EPERM;
+ break;
+ case ACPI_P_LVL3_LAT:
+ case ACPI_ENTER_LVL3_LAT:
+ if (acpi_opts & ACPI_C3_DISABLED)
+ return -EPERM;
+ break;
+ case ACPI_S1_SLP_TYP:
+ case ACPI_SLEEP:
+ if (acpi_opts & ACPI_S1_DISABLED)
+ return -EPERM;
+ break;
+ case ACPI_S5_SLP_TYP:
+ if (acpi_opts & ACPI_S5_DISABLED)
+ return -EPERM;
+ break;
+ }
+ return 0;
+}
+
+/*
* Examine/modify value
*/
static int acpi_do_ulong(ctl_table *ctl,
@@ -1141,6 +1259,9 @@
*len = 0;
}
else {
+ if (acpi_verify_mod(ctl->ctl_name))
+ return -EPERM;
+
size = sizeof(str) - 1;
if (size > *len)
size = *len;
@@ -1313,6 +1434,9 @@
}
else
{
+ if (acpi_verify_mod(ctl->ctl_name))
+ return -EPERM;
+
// fetch user value
size = sizeof(str) - 1;
if (size > *len)
@@ -1443,24 +1567,71 @@
}
else
{
-#ifdef CONFIG_ACPI_S1_SLEEP
- acpi_enter_sx(ACPI_S1);
-#endif
+ if (acpi_verify_mod(ctl->ctl_name) || acpi_enter_sx(ACPI_S1))
+ return -EPERM;
}
file->f_pos += *len;
return 0;
}
+/*
+ * Parse command line options
+ */
+static int __init acpi_setup(char *str)
+{
+ while (str && *str) {
+ struct acpi_option_info *opt = acpi_options;
+ while (opt->name) {
+ if (!strncmp(str, opt->name, strlen(opt->name))) {
+ acpi_opts |= opt->value;
+ break;
+ }
+ opt++;
+ }
+ str = strpbrk(str, ",");
+ if (str)
+ str += strspn(str, ",");
+ }
+
+ if (acpi_opts)
+ printk(KERN_INFO "ACPI: options 0x%08lx\n", acpi_opts);
+
+ return 1;
+}
+
+/*
+ * kernel/module command line interfaces are both "acpi=OPTION,OPTION,..."
+ */
+__setup("acpi=", acpi_setup);
+
+static char * __initdata acpi = NULL;
+
+MODULE_DESCRIPTION("ACPI driver");
+MODULE_PARM(acpi, "s");
+MODULE_PARM_DESC(acpi, "ACPI driver command line");
/*
* Initialize and enable ACPI
*/
-static int __init acpi_init(void)
+int __init acpi_init(void)
{
struct acpi_facp *facp = NULL;
- switch (acpi_enabled) {
- case ACPI_ENABLED:
+ if (acpi)
+ acpi_setup(acpi);
+
+ if (acpi_opts & ACPI_DISABLED) {
+ return -ENODEV;
+ }
+ else if (acpi_opts & ACPI_TABLES_ONLY) {
+ if (acpi_find_tables())
+ return -ENODEV;
+ }
+ else if (acpi_opts & ACPI_CHIPSET_ONLY) {
+ if (acpi_find_chipset())
+ return -ENODEV;
+ }
+ else {
switch (acpi_find_tables()) {
case 0:
// found valid ACPI tables
@@ -1474,17 +1645,6 @@
// found broken ACPI tables
return -ENODEV;
}
- break;
- case ACPI_TABLES_ONLY:
- if (acpi_find_tables())
- return -ENODEV;
- break;
- case ACPI_CHIPSET_ONLY:
- if (acpi_find_chipset())
- return -ENODEV;
- break;
- case ACPI_DISABLED:
- return -ENODEV;
}
facp = (struct acpi_facp*) acpi_facp.table;
@@ -1502,12 +1662,14 @@
* control in the /proc interfaces.
*/
if (facp->p_lvl2_lat
- && facp->p_lvl2_lat <= ACPI_MAX_P_LVL2_LAT) {
+ && facp->p_lvl2_lat <= ACPI_MAX_P_LVL2_LAT
+ && !acpi_verify_mod(ACPI_P_LVL2_LAT)) {
acpi_p_lvl2_lat = ACPI_uS_TO_TMR_TICKS(facp->p_lvl2_lat);
acpi_enter_lvl2_lat = ACPI_uS_TO_TMR_TICKS(ACPI_TMR_HZ / 1000);
}
if (facp->p_lvl3_lat
- && facp->p_lvl3_lat <= ACPI_MAX_P_LVL3_LAT) {
+ && facp->p_lvl3_lat <= ACPI_MAX_P_LVL3_LAT
+ && !acpi_verify_mod(ACPI_P_LVL3_LAT)) {
acpi_p_lvl3_lat = ACPI_uS_TO_TMR_TICKS(facp->p_lvl3_lat);
acpi_enter_lvl3_lat
= ACPI_uS_TO_TMR_TICKS(facp->p_lvl3_lat * 5);
@@ -1519,6 +1681,7 @@
}
if (facp->sci_int
+ && acpi_sci_enabled()
&& request_irq(facp->sci_int,
acpi_irq,
SA_INTERRUPT | SA_SHIRQ,
@@ -1529,6 +1692,10 @@
goto err_out;
}
+#ifndef CONFIG_ACPI_S1_SLEEP
+ acpi_opts |= ACPI_S1_DISABLED;
+#endif
+
acpi_sysctl = register_sysctl_table(acpi_dir_table, 1);
pm_power_off = acpi_power_off;
@@ -1559,7 +1726,7 @@
/*
* Disable and deinitialize ACPI
*/
-static void __exit acpi_exit(void)
+void __exit acpi_exit(void)
{
struct acpi_facp *facp = (struct acpi_facp*) acpi_facp.table;
@@ -1570,7 +1737,7 @@
acpi_disable(facp);
acpi_release_ioports(facp);
- if (facp->sci_int)
+ if (facp->sci_int && acpi_sci_enabled())
free_irq(facp->sci_int, &acpi_facp);
acpi_destroy_tables();
@@ -1581,29 +1748,5 @@
pm_active = 0;
}
-/*
- * Parse kernel command line options
- */
-static int __init acpi_setup(char *str)
-{
- while (str && *str) {
- if (strncmp(str, "on", 2) == 0)
- acpi_enabled = ACPI_ENABLED;
- else if (strncmp(str, "tables", 6) == 0)
- acpi_enabled = ACPI_TABLES_ONLY;
- else if (strncmp(str, "chipset", 7) == 0)
- acpi_enabled = ACPI_CHIPSET_ONLY;
- else if (strncmp(str, "off", 3) == 0)
- acpi_enabled = ACPI_DISABLED;
- str = strpbrk(str, ",");
- if (str)
- str += strspn(str, ",");
- }
- return 1;
-}
-
-__setup("acpi=", acpi_setup);
-
module_init(acpi_init);
module_exit(acpi_exit);
-
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)