kolibrios/drivers/acpi/acpi.c

632 lines
15 KiB
C
Raw Normal View History

#include <syscall.h>
#include <linux/delay.h>
#include <linux/ktime.h>
#include <linux/acpi.h>
#include <linux/dmi.h>
#define PREFIX "ACPI: "
int sbf_port __initdata = -1;
static bool acpi_os_initialized;
u32 __attribute__((externally_visible)) drvEntry(int action, char *cmdline)
{
int result;
if(action != 1)
return 0;
if( !dbg_open("/tmp0/1/acpi.log") )
{
printk("Can't open /tmp0/1/acpi.log\nExit\n");
return 0;
}
dmi_scan_machine();
acpi_boot_table_init();
early_acpi_boot_init();
acpi_noirq_set();
acpi_early_init();
// if (acpi_disabled) {
// printk(KERN_INFO PREFIX "Interpreter disabled.\n");
// return -ENODEV;
// }
// init_acpi_device_notify();
// result = acpi_bus_init();
// if (result) {
// disable_acpi();
// return result;
// }
// pci_mmcfg_late_init();
// acpi_scan_init();
// acpi_ec_init();
// acpi_debugfs_init();
// acpi_sleep_proc_init();
// acpi_wakeup_device_init();
dbgprintf("module loaded\n");
return 0;
};
#define PREFIX "ACPI: "
u32 IMPORT AcpiGetRootPtr(void)__asm__("AcpiGetRootPtr");
acpi_physical_address __init acpi_os_get_root_pointer(void)
{
return AcpiGetRootPtr();
}
void* acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
{
return (void *)MapIoMem((addr_t)phys, size, PG_SW);
}
void acpi_os_unmap_memory(void *virt, acpi_size size)
{
u32 ptr = (u32)virt;
ptr &= 0xFFFFF000;
return FreeKernelSpace((void*)ptr);
}
void __init early_acpi_os_unmap_memory(void __iomem *virt, acpi_size size)
{
acpi_os_unmap_memory(virt, size);
}
int acpi_os_map_generic_address(struct acpi_generic_address *gas)
{
addr_t addr;
void *virt;
if (gas->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY)
return 0;
addr = (addr_t)gas->address;
if (!addr || !gas->bit_width)
return -EINVAL;
virt = (void *)MapIoMem(addr, gas->bit_width / 8, PG_SW);
if (!virt)
return -EIO;
return 0;
}
void acpi_os_printf(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
acpi_os_vprintf(fmt, args);
va_end(args);
}
void acpi_os_vprintf(const char *fmt, va_list args)
{
static char buffer[512];
vsprintf(buffer, fmt, args);
#ifdef ENABLE_DEBUGGER
if (acpi_in_debugger) {
kdb_printf("%s", buffer);
} else {
printk("%s", buffer);
}
#else
printk("%s", buffer);
#endif
}
static void acpi_table_taint(struct acpi_table_header *table)
{
pr_warn(PREFIX
"Override [%4.4s-%8.8s], this is unsafe: tainting kernel\n",
table->signature, table->oem_table_id);
add_taint(TAINT_OVERRIDDEN_ACPI_TABLE, LOCKDEP_NOW_UNRELIABLE);
}
acpi_status
acpi_os_table_override(struct acpi_table_header * existing_table,
struct acpi_table_header ** new_table)
{
if (!existing_table || !new_table)
return AE_BAD_PARAMETER;
*new_table = NULL;
#ifdef CONFIG_ACPI_CUSTOM_DSDT
if (strncmp(existing_table->signature, "DSDT", 4) == 0)
*new_table = (struct acpi_table_header *)AmlCode;
#endif
if (*new_table != NULL)
acpi_table_taint(existing_table);
return AE_OK;
}
acpi_status
acpi_os_physical_table_override(struct acpi_table_header *existing_table,
acpi_physical_address *address,
u32 *table_length)
{
#ifndef CONFIG_ACPI_INITRD_TABLE_OVERRIDE
*table_length = 0;
*address = 0;
return AE_OK;
#else
int table_offset = 0;
struct acpi_table_header *table;
*table_length = 0;
*address = 0;
if (!acpi_tables_addr)
return AE_OK;
do {
if (table_offset + ACPI_HEADER_SIZE > all_tables_size) {
WARN_ON(1);
return AE_OK;
}
table = acpi_os_map_memory(acpi_tables_addr + table_offset,
ACPI_HEADER_SIZE);
if (table_offset + table->length > all_tables_size) {
acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
WARN_ON(1);
return AE_OK;
}
table_offset += table->length;
if (memcmp(existing_table->signature, table->signature, 4)) {
acpi_os_unmap_memory(table,
ACPI_HEADER_SIZE);
continue;
}
/* Only override tables with matching oem id */
if (memcmp(table->oem_table_id, existing_table->oem_table_id,
ACPI_OEM_TABLE_ID_SIZE)) {
acpi_os_unmap_memory(table,
ACPI_HEADER_SIZE);
continue;
}
table_offset -= table->length;
*table_length = table->length;
acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
*address = acpi_tables_addr + table_offset;
break;
} while (table_offset + ACPI_HEADER_SIZE < all_tables_size);
if (*address != 0)
acpi_table_taint(existing_table);
return AE_OK;
#endif
}
static struct osi_linux {
unsigned int enable:1;
unsigned int dmi:1;
unsigned int cmdline:1;
unsigned int default_disabling:1;
} osi_linux = {0, 0, 0, 0};
#define OSI_STRING_LENGTH_MAX 64 /* arbitrary */
#define OSI_STRING_ENTRIES_MAX 16 /* arbitrary */
struct osi_setup_entry {
char string[OSI_STRING_LENGTH_MAX];
bool enable;
};
static struct osi_setup_entry
osi_setup_entries[OSI_STRING_ENTRIES_MAX] __initdata = {
{"Module Device", true},
{"Processor Device", true},
{"3.0 _SCP Extensions", true},
{"Processor Aggregator Device", true},
};
void __init acpi_osi_setup(char *str)
{
struct osi_setup_entry *osi;
bool enable = true;
int i;
if (!acpi_gbl_create_osi_method)
return;
if (str == NULL || *str == '\0') {
printk(KERN_INFO PREFIX "_OSI method disabled\n");
acpi_gbl_create_osi_method = FALSE;
return;
}
if (*str == '!') {
str++;
if (*str == '\0') {
osi_linux.default_disabling = 1;
return;
} else if (*str == '*') {
acpi_update_interfaces(ACPI_DISABLE_ALL_STRINGS);
for (i = 0; i < OSI_STRING_ENTRIES_MAX; i++) {
osi = &osi_setup_entries[i];
osi->enable = false;
}
return;
}
enable = false;
}
for (i = 0; i < OSI_STRING_ENTRIES_MAX; i++) {
osi = &osi_setup_entries[i];
if (!strcmp(osi->string, str)) {
osi->enable = enable;
break;
} else if (osi->string[0] == '\0') {
osi->enable = enable;
strncpy(osi->string, str, OSI_STRING_LENGTH_MAX);
break;
}
}
}
static void __init set_osi_linux(unsigned int enable)
{
if (osi_linux.enable != enable)
osi_linux.enable = enable;
if (osi_linux.enable)
acpi_osi_setup("Linux");
else
acpi_osi_setup("!Linux");
return;
}
void __init acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d)
{
printk(KERN_NOTICE PREFIX "DMI detected: %s\n", d->ident);
if (enable == -1)
return;
osi_linux.dmi = 1; /* DMI knows that this box asks OSI(Linux) */
set_osi_linux(enable);
return;
}
acpi_status acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 timeout)
{
void *sem = (void*)handle;
if (!acpi_os_initialized)
return AE_OK;
if (!sem || (units < 1))
return AE_BAD_PARAMETER;
if (units > 1)
return AE_SUPPORT;
ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Waiting for semaphore[%p|%d|%d]\n",
handle, units, timeout));
return AE_OK;
}
acpi_status acpi_os_signal_semaphore(acpi_handle handle, u32 units)
{
void *sem = (void*)handle;
if (!acpi_os_initialized)
return AE_OK;
if (!sem || (units < 1))
return AE_BAD_PARAMETER;
if (units > 1)
return AE_SUPPORT;
ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Signaling semaphore[%p|%d]\n", handle,
units));
// up(sem);
return AE_OK;
}
acpi_status __init acpi_os_initialize(void)
{
// acpi_os_map_generic_address(&acpi_gbl_FADT.xpm1a_event_block);
// acpi_os_map_generic_address(&acpi_gbl_FADT.xpm1b_event_block);
// acpi_os_map_generic_address(&acpi_gbl_FADT.xgpe0_block);
// acpi_os_map_generic_address(&acpi_gbl_FADT.xgpe1_block);
if (acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER) {
/*
* Use acpi_os_map_generic_address to pre-map the reset
* register if it's in system memory.
*/
int rv;
rv = acpi_os_map_generic_address(&acpi_gbl_FADT.reset_register);
pr_debug(PREFIX "%s: map reset_reg status %d\n", __func__, rv);
}
acpi_os_initialized = true;
return AE_OK;
}
acpi_status __init acpi_os_initialize1(void)
{
// kacpid_wq = alloc_workqueue("kacpid", 0, 1);
// kacpi_notify_wq = alloc_workqueue("kacpi_notify", 0, 1);
// kacpi_hotplug_wq = alloc_ordered_workqueue("kacpi_hotplug", 0);
// BUG_ON(!kacpid_wq);
// BUG_ON(!kacpi_notify_wq);
// BUG_ON(!kacpi_hotplug_wq);
// acpi_install_interface_handler(acpi_osi_handler);
// acpi_osi_setup_late();
return AE_OK;
}
acpi_status acpi_os_delete_semaphore(acpi_handle handle)
{
// void *sem = (void*)handle;
// if (!sem)
// return AE_BAD_PARAMETER;
// kfree(sem);
// sem = NULL;
return AE_OK;
}
acpi_status acpi_os_create_semaphore(u32 max_units,
u32 initial_units, acpi_handle * out_handle)
{
*out_handle = (acpi_handle) 1;
return (AE_OK);
}
acpi_status
acpi_os_create_mutex(acpi_handle * handle)
{
struct mutex *mtx = NULL;
mtx = kzalloc(sizeof(struct mutex),0);
if (!mtx)
return AE_NO_MEMORY;
mutex_init(mtx);
*handle = (acpi_handle *) mtx;
return AE_OK;
}
void acpi_os_release_mutex(acpi_mutex handle)
{
struct mutex *mtx = (struct mutex*)handle;
if (!acpi_os_initialized)
return;
mutex_unlock(mtx);
}
acpi_status acpi_os_acquire_mutex(acpi_mutex handle, u16 timeout)
{
struct mutex *mtx = (struct mutex*)handle;
if (!acpi_os_initialized)
return AE_OK;
mutex_lock(mtx);
return AE_OK;
}
void acpi_os_delete_mutex(acpi_mutex handle)
{
struct mutex *mtx = (struct mutex*)handle;
kfree(mtx);
};
acpi_cpu_flags acpi_os_acquire_lock(acpi_spinlock lockp)
{
acpi_cpu_flags flags;
spin_lock_irqsave(lockp, flags);
return flags;
}
void acpi_os_release_lock(acpi_spinlock lockp, acpi_cpu_flags flags)
{
spin_unlock_irqrestore(lockp, flags);
}
acpi_status acpi_os_signal(u32 function, void *info)
{
switch (function) {
case ACPI_SIGNAL_FATAL:
printk(KERN_ERR PREFIX "Fatal opcode executed\n");
break;
case ACPI_SIGNAL_BREAKPOINT:
/*
* AML Breakpoint
* ACPI spec. says to treat it as a NOP unless
* you are debugging. So if/when we integrate
* AML debugger into the kernel debugger its
* hook will go here. But until then it is
* not useful to print anything on breakpoints.
*/
break;
default:
break;
}
return AE_OK;
}
void acpi_os_sleep(u64 ms)
{
msleep(ms);
}
void acpi_os_stall(u32 us)
{
while (us) {
u32 delay = 1000;
if (delay > us)
delay = us;
udelay(delay);
// touch_nmi_watchdog();
us -= delay;
}
}
void msleep(unsigned int msecs)
{
msecs /= 10;
if(!msecs) msecs = 1;
__asm__ __volatile__ (
"call *__imp__Delay"
::"b" (msecs));
__asm__ __volatile__ (
"":::"ebx");
};
acpi_status acpi_os_execute(acpi_execute_type type,
acpi_osd_exec_callback function, void *context)
{
return AE_OK;
}
u64 acpi_os_get_timer(void)
{
u64 time_ns = ktime_to_ns(ktime_get());
do_div(time_ns, 100);
return time_ns;
}
ktime_t ktime_get(void)
{
ktime_t t;
t.tv64 = GetClockNs();
return t;
}
void __delay(unsigned long loops)
{
asm volatile(
"test %0,%0\n"
"jz 3f\n"
"jmp 1f\n"
".align 16\n"
"1: jmp 2f\n"
".align 16\n"
"2: dec %0\n"
" jnz 2b\n"
"3: dec %0\n"
: /* we don't need output */
: "a" (loops)
);
}
inline void __const_udelay(unsigned long xloops)
{
int d0;
xloops *= 4;
asm("mull %%edx"
: "=d" (xloops), "=&a" (d0)
: "1" (xloops), ""
(loops_per_jiffy * (HZ/4)));
__delay(++xloops);
}
void __udelay(unsigned long usecs)
{
__const_udelay(usecs * 0x000010c7); /* 2**32 / 1000000 (rounded up) */
}
#define acpi_rev_override false
#define ACPI_MAX_OVERRIDE_LEN 100
static char acpi_os_name[ACPI_MAX_OVERRIDE_LEN];
acpi_status
acpi_os_predefined_override(const struct acpi_predefined_names *init_val,
char **new_val)
{
if (!init_val || !new_val)
return AE_BAD_PARAMETER;
*new_val = NULL;
if (!memcmp(init_val->name, "_OS_", 4) && strlen(acpi_os_name)) {
printk(KERN_INFO PREFIX "Overriding _OS definition to '%s'\n",
acpi_os_name);
*new_val = acpi_os_name;
}
if (!memcmp(init_val->name, "_REV", 4) && acpi_rev_override) {
printk(KERN_INFO PREFIX "Overriding _REV return value to 5\n");
*new_val = (char *)5;
}
return AE_OK;
}