2015-05-20 05:54:31 +03:00
/*
* Copyright ( c ) 2013 - 2015 Intel Corporation . All rights reserved .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*/
# include <linux/list_sort.h>
# include <linux/libnvdimm.h>
# include <linux/module.h>
# include <linux/list.h>
# include <linux/acpi.h>
# include "nfit.h"
static u8 nfit_uuid [ NFIT_UUID_MAX ] [ 16 ] ;
static const u8 * to_nfit_uuid ( enum nfit_uuids id )
{
return nfit_uuid [ id ] ;
}
static int acpi_nfit_ctl ( struct nvdimm_bus_descriptor * nd_desc ,
struct nvdimm * nvdimm , unsigned int cmd , void * buf ,
unsigned int buf_len )
{
return - ENOTTY ;
}
static const char * spa_type_name ( u16 type )
{
static const char * to_name [ ] = {
[ NFIT_SPA_VOLATILE ] = " volatile " ,
[ NFIT_SPA_PM ] = " pmem " ,
[ NFIT_SPA_DCR ] = " dimm-control-region " ,
[ NFIT_SPA_BDW ] = " block-data-window " ,
[ NFIT_SPA_VDISK ] = " volatile-disk " ,
[ NFIT_SPA_VCD ] = " volatile-cd " ,
[ NFIT_SPA_PDISK ] = " persistent-disk " ,
[ NFIT_SPA_PCD ] = " persistent-cd " ,
} ;
if ( type > NFIT_SPA_PCD )
return " unknown " ;
return to_name [ type ] ;
}
static int nfit_spa_type ( struct acpi_nfit_system_address * spa )
{
int i ;
for ( i = 0 ; i < NFIT_UUID_MAX ; i + + )
if ( memcmp ( to_nfit_uuid ( i ) , spa - > range_guid , 16 ) = = 0 )
return i ;
return - 1 ;
}
static bool add_spa ( struct acpi_nfit_desc * acpi_desc ,
struct acpi_nfit_system_address * spa )
{
struct device * dev = acpi_desc - > dev ;
struct nfit_spa * nfit_spa = devm_kzalloc ( dev , sizeof ( * nfit_spa ) ,
GFP_KERNEL ) ;
if ( ! nfit_spa )
return false ;
INIT_LIST_HEAD ( & nfit_spa - > list ) ;
nfit_spa - > spa = spa ;
list_add_tail ( & nfit_spa - > list , & acpi_desc - > spas ) ;
dev_dbg ( dev , " %s: spa index: %d type: %s \n " , __func__ ,
spa - > range_index ,
spa_type_name ( nfit_spa_type ( spa ) ) ) ;
return true ;
}
static bool add_memdev ( struct acpi_nfit_desc * acpi_desc ,
struct acpi_nfit_memory_map * memdev )
{
struct device * dev = acpi_desc - > dev ;
struct nfit_memdev * nfit_memdev = devm_kzalloc ( dev ,
sizeof ( * nfit_memdev ) , GFP_KERNEL ) ;
if ( ! nfit_memdev )
return false ;
INIT_LIST_HEAD ( & nfit_memdev - > list ) ;
nfit_memdev - > memdev = memdev ;
list_add_tail ( & nfit_memdev - > list , & acpi_desc - > memdevs ) ;
dev_dbg ( dev , " %s: memdev handle: %#x spa: %d dcr: %d \n " ,
__func__ , memdev - > device_handle , memdev - > range_index ,
memdev - > region_index ) ;
return true ;
}
static bool add_dcr ( struct acpi_nfit_desc * acpi_desc ,
struct acpi_nfit_control_region * dcr )
{
struct device * dev = acpi_desc - > dev ;
struct nfit_dcr * nfit_dcr = devm_kzalloc ( dev , sizeof ( * nfit_dcr ) ,
GFP_KERNEL ) ;
if ( ! nfit_dcr )
return false ;
INIT_LIST_HEAD ( & nfit_dcr - > list ) ;
nfit_dcr - > dcr = dcr ;
list_add_tail ( & nfit_dcr - > list , & acpi_desc - > dcrs ) ;
dev_dbg ( dev , " %s: dcr index: %d windows: %d \n " , __func__ ,
dcr - > region_index , dcr - > windows ) ;
return true ;
}
static bool add_bdw ( struct acpi_nfit_desc * acpi_desc ,
struct acpi_nfit_data_region * bdw )
{
struct device * dev = acpi_desc - > dev ;
struct nfit_bdw * nfit_bdw = devm_kzalloc ( dev , sizeof ( * nfit_bdw ) ,
GFP_KERNEL ) ;
if ( ! nfit_bdw )
return false ;
INIT_LIST_HEAD ( & nfit_bdw - > list ) ;
nfit_bdw - > bdw = bdw ;
list_add_tail ( & nfit_bdw - > list , & acpi_desc - > bdws ) ;
dev_dbg ( dev , " %s: bdw dcr: %d windows: %d \n " , __func__ ,
bdw - > region_index , bdw - > windows ) ;
return true ;
}
static void * add_table ( struct acpi_nfit_desc * acpi_desc , void * table ,
const void * end )
{
struct device * dev = acpi_desc - > dev ;
struct acpi_nfit_header * hdr ;
void * err = ERR_PTR ( - ENOMEM ) ;
if ( table > = end )
return NULL ;
hdr = table ;
switch ( hdr - > type ) {
case ACPI_NFIT_TYPE_SYSTEM_ADDRESS :
if ( ! add_spa ( acpi_desc , table ) )
return err ;
break ;
case ACPI_NFIT_TYPE_MEMORY_MAP :
if ( ! add_memdev ( acpi_desc , table ) )
return err ;
break ;
case ACPI_NFIT_TYPE_CONTROL_REGION :
if ( ! add_dcr ( acpi_desc , table ) )
return err ;
break ;
case ACPI_NFIT_TYPE_DATA_REGION :
if ( ! add_bdw ( acpi_desc , table ) )
return err ;
break ;
/* TODO */
case ACPI_NFIT_TYPE_INTERLEAVE :
dev_dbg ( dev , " %s: idt \n " , __func__ ) ;
break ;
case ACPI_NFIT_TYPE_FLUSH_ADDRESS :
dev_dbg ( dev , " %s: flush \n " , __func__ ) ;
break ;
case ACPI_NFIT_TYPE_SMBIOS :
dev_dbg ( dev , " %s: smbios \n " , __func__ ) ;
break ;
default :
dev_err ( dev , " unknown table '%d' parsing nfit \n " , hdr - > type ) ;
break ;
}
return table + hdr - > length ;
}
static void nfit_mem_find_spa_bdw ( struct acpi_nfit_desc * acpi_desc ,
struct nfit_mem * nfit_mem )
{
u32 device_handle = __to_nfit_memdev ( nfit_mem ) - > device_handle ;
u16 dcr = nfit_mem - > dcr - > region_index ;
struct nfit_spa * nfit_spa ;
list_for_each_entry ( nfit_spa , & acpi_desc - > spas , list ) {
u16 range_index = nfit_spa - > spa - > range_index ;
int type = nfit_spa_type ( nfit_spa - > spa ) ;
struct nfit_memdev * nfit_memdev ;
if ( type ! = NFIT_SPA_BDW )
continue ;
list_for_each_entry ( nfit_memdev , & acpi_desc - > memdevs , list ) {
if ( nfit_memdev - > memdev - > range_index ! = range_index )
continue ;
if ( nfit_memdev - > memdev - > device_handle ! = device_handle )
continue ;
if ( nfit_memdev - > memdev - > region_index ! = dcr )
continue ;
nfit_mem - > spa_bdw = nfit_spa - > spa ;
return ;
}
}
dev_dbg ( acpi_desc - > dev , " SPA-BDW not found for SPA-DCR %d \n " ,
nfit_mem - > spa_dcr - > range_index ) ;
nfit_mem - > bdw = NULL ;
}
static int nfit_mem_add ( struct acpi_nfit_desc * acpi_desc ,
struct nfit_mem * nfit_mem , struct acpi_nfit_system_address * spa )
{
u16 dcr = __to_nfit_memdev ( nfit_mem ) - > region_index ;
struct nfit_dcr * nfit_dcr ;
struct nfit_bdw * nfit_bdw ;
list_for_each_entry ( nfit_dcr , & acpi_desc - > dcrs , list ) {
if ( nfit_dcr - > dcr - > region_index ! = dcr )
continue ;
nfit_mem - > dcr = nfit_dcr - > dcr ;
break ;
}
if ( ! nfit_mem - > dcr ) {
dev_dbg ( acpi_desc - > dev , " SPA %d missing:%s%s \n " ,
spa - > range_index , __to_nfit_memdev ( nfit_mem )
? " " : " MEMDEV " , nfit_mem - > dcr ? " " : " DCR " ) ;
return - ENODEV ;
}
/*
* We ' ve found enough to create an nvdimm , optionally
* find an associated BDW
*/
list_add ( & nfit_mem - > list , & acpi_desc - > dimms ) ;
list_for_each_entry ( nfit_bdw , & acpi_desc - > bdws , list ) {
if ( nfit_bdw - > bdw - > region_index ! = dcr )
continue ;
nfit_mem - > bdw = nfit_bdw - > bdw ;
break ;
}
if ( ! nfit_mem - > bdw )
return 0 ;
nfit_mem_find_spa_bdw ( acpi_desc , nfit_mem ) ;
return 0 ;
}
static int nfit_mem_dcr_init ( struct acpi_nfit_desc * acpi_desc ,
struct acpi_nfit_system_address * spa )
{
struct nfit_mem * nfit_mem , * found ;
struct nfit_memdev * nfit_memdev ;
int type = nfit_spa_type ( spa ) ;
u16 dcr ;
switch ( type ) {
case NFIT_SPA_DCR :
case NFIT_SPA_PM :
break ;
default :
return 0 ;
}
list_for_each_entry ( nfit_memdev , & acpi_desc - > memdevs , list ) {
int rc ;
if ( nfit_memdev - > memdev - > range_index ! = spa - > range_index )
continue ;
found = NULL ;
dcr = nfit_memdev - > memdev - > region_index ;
list_for_each_entry ( nfit_mem , & acpi_desc - > dimms , list )
if ( __to_nfit_memdev ( nfit_mem ) - > region_index = = dcr ) {
found = nfit_mem ;
break ;
}
if ( found )
nfit_mem = found ;
else {
nfit_mem = devm_kzalloc ( acpi_desc - > dev ,
sizeof ( * nfit_mem ) , GFP_KERNEL ) ;
if ( ! nfit_mem )
return - ENOMEM ;
INIT_LIST_HEAD ( & nfit_mem - > list ) ;
}
if ( type = = NFIT_SPA_DCR ) {
/* multiple dimms may share a SPA when interleaved */
nfit_mem - > spa_dcr = spa ;
nfit_mem - > memdev_dcr = nfit_memdev - > memdev ;
} else {
/*
* A single dimm may belong to multiple SPA - PM
* ranges , record at least one in addition to
* any SPA - DCR range .
*/
nfit_mem - > memdev_pmem = nfit_memdev - > memdev ;
}
if ( found )
continue ;
rc = nfit_mem_add ( acpi_desc , nfit_mem , spa ) ;
if ( rc )
return rc ;
}
return 0 ;
}
static int nfit_mem_cmp ( void * priv , struct list_head * _a , struct list_head * _b )
{
struct nfit_mem * a = container_of ( _a , typeof ( * a ) , list ) ;
struct nfit_mem * b = container_of ( _b , typeof ( * b ) , list ) ;
u32 handleA , handleB ;
handleA = __to_nfit_memdev ( a ) - > device_handle ;
handleB = __to_nfit_memdev ( b ) - > device_handle ;
if ( handleA < handleB )
return - 1 ;
else if ( handleA > handleB )
return 1 ;
return 0 ;
}
static int nfit_mem_init ( struct acpi_nfit_desc * acpi_desc )
{
struct nfit_spa * nfit_spa ;
/*
* For each SPA - DCR or SPA - PMEM address range find its
* corresponding MEMDEV ( s ) . From each MEMDEV find the
* corresponding DCR . Then , if we ' re operating on a SPA - DCR ,
* try to find a SPA - BDW and a corresponding BDW that references
* the DCR . Throw it all into an nfit_mem object . Note , that
* BDWs are optional .
*/
list_for_each_entry ( nfit_spa , & acpi_desc - > spas , list ) {
int rc ;
rc = nfit_mem_dcr_init ( acpi_desc , nfit_spa - > spa ) ;
if ( rc )
return rc ;
}
list_sort ( NULL , & acpi_desc - > dimms , nfit_mem_cmp ) ;
return 0 ;
}
2015-04-27 02:26:48 +03:00
static ssize_t revision_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct nvdimm_bus * nvdimm_bus = to_nvdimm_bus ( dev ) ;
struct nvdimm_bus_descriptor * nd_desc = to_nd_desc ( nvdimm_bus ) ;
struct acpi_nfit_desc * acpi_desc = to_acpi_desc ( nd_desc ) ;
return sprintf ( buf , " %d \n " , acpi_desc - > nfit - > header . revision ) ;
}
static DEVICE_ATTR_RO ( revision ) ;
static struct attribute * acpi_nfit_attributes [ ] = {
& dev_attr_revision . attr ,
NULL ,
} ;
static struct attribute_group acpi_nfit_attribute_group = {
. name = " nfit " ,
. attrs = acpi_nfit_attributes ,
} ;
static const struct attribute_group * acpi_nfit_attribute_groups [ ] = {
& nvdimm_bus_attribute_group ,
& acpi_nfit_attribute_group ,
NULL ,
} ;
2015-04-25 10:56:17 +03:00
static struct acpi_nfit_memory_map * to_nfit_memdev ( struct device * dev )
{
struct nvdimm * nvdimm = to_nvdimm ( dev ) ;
struct nfit_mem * nfit_mem = nvdimm_provider_data ( nvdimm ) ;
return __to_nfit_memdev ( nfit_mem ) ;
}
static struct acpi_nfit_control_region * to_nfit_dcr ( struct device * dev )
{
struct nvdimm * nvdimm = to_nvdimm ( dev ) ;
struct nfit_mem * nfit_mem = nvdimm_provider_data ( nvdimm ) ;
return nfit_mem - > dcr ;
}
static ssize_t handle_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct acpi_nfit_memory_map * memdev = to_nfit_memdev ( dev ) ;
return sprintf ( buf , " %#x \n " , memdev - > device_handle ) ;
}
static DEVICE_ATTR_RO ( handle ) ;
static ssize_t phys_id_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct acpi_nfit_memory_map * memdev = to_nfit_memdev ( dev ) ;
return sprintf ( buf , " %#x \n " , memdev - > physical_id ) ;
}
static DEVICE_ATTR_RO ( phys_id ) ;
static ssize_t vendor_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct acpi_nfit_control_region * dcr = to_nfit_dcr ( dev ) ;
return sprintf ( buf , " %#x \n " , dcr - > vendor_id ) ;
}
static DEVICE_ATTR_RO ( vendor ) ;
static ssize_t rev_id_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct acpi_nfit_control_region * dcr = to_nfit_dcr ( dev ) ;
return sprintf ( buf , " %#x \n " , dcr - > revision_id ) ;
}
static DEVICE_ATTR_RO ( rev_id ) ;
static ssize_t device_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct acpi_nfit_control_region * dcr = to_nfit_dcr ( dev ) ;
return sprintf ( buf , " %#x \n " , dcr - > device_id ) ;
}
static DEVICE_ATTR_RO ( device ) ;
static ssize_t format_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct acpi_nfit_control_region * dcr = to_nfit_dcr ( dev ) ;
return sprintf ( buf , " %#x \n " , dcr - > code ) ;
}
static DEVICE_ATTR_RO ( format ) ;
static ssize_t serial_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct acpi_nfit_control_region * dcr = to_nfit_dcr ( dev ) ;
return sprintf ( buf , " %#x \n " , dcr - > serial_number ) ;
}
static DEVICE_ATTR_RO ( serial ) ;
static struct attribute * acpi_nfit_dimm_attributes [ ] = {
& dev_attr_handle . attr ,
& dev_attr_phys_id . attr ,
& dev_attr_vendor . attr ,
& dev_attr_device . attr ,
& dev_attr_format . attr ,
& dev_attr_serial . attr ,
& dev_attr_rev_id . attr ,
NULL ,
} ;
static umode_t acpi_nfit_dimm_attr_visible ( struct kobject * kobj ,
struct attribute * a , int n )
{
struct device * dev = container_of ( kobj , struct device , kobj ) ;
if ( to_nfit_dcr ( dev ) )
return a - > mode ;
else
return 0 ;
}
static struct attribute_group acpi_nfit_dimm_attribute_group = {
. name = " nfit " ,
. attrs = acpi_nfit_dimm_attributes ,
. is_visible = acpi_nfit_dimm_attr_visible ,
} ;
static const struct attribute_group * acpi_nfit_dimm_attribute_groups [ ] = {
& acpi_nfit_dimm_attribute_group ,
NULL ,
} ;
static struct nvdimm * acpi_nfit_dimm_by_handle ( struct acpi_nfit_desc * acpi_desc ,
u32 device_handle )
{
struct nfit_mem * nfit_mem ;
list_for_each_entry ( nfit_mem , & acpi_desc - > dimms , list )
if ( __to_nfit_memdev ( nfit_mem ) - > device_handle = = device_handle )
return nfit_mem - > nvdimm ;
return NULL ;
}
static int acpi_nfit_register_dimms ( struct acpi_nfit_desc * acpi_desc )
{
struct nfit_mem * nfit_mem ;
list_for_each_entry ( nfit_mem , & acpi_desc - > dimms , list ) {
struct nvdimm * nvdimm ;
unsigned long flags = 0 ;
u32 device_handle ;
device_handle = __to_nfit_memdev ( nfit_mem ) - > device_handle ;
nvdimm = acpi_nfit_dimm_by_handle ( acpi_desc , device_handle ) ;
if ( nvdimm ) {
/*
* If for some reason we find multiple DCRs the
* first one wins
*/
dev_err ( acpi_desc - > dev , " duplicate DCR detected: %s \n " ,
nvdimm_name ( nvdimm ) ) ;
continue ;
}
if ( nfit_mem - > bdw & & nfit_mem - > memdev_pmem )
flags | = NDD_ALIASING ;
nvdimm = nvdimm_create ( acpi_desc - > nvdimm_bus , nfit_mem ,
acpi_nfit_dimm_attribute_groups , flags ) ;
if ( ! nvdimm )
return - ENOMEM ;
nfit_mem - > nvdimm = nvdimm ;
}
return 0 ;
}
2015-05-20 05:54:31 +03:00
static int acpi_nfit_init ( struct acpi_nfit_desc * acpi_desc , acpi_size sz )
{
struct device * dev = acpi_desc - > dev ;
const void * end ;
u8 * data ;
INIT_LIST_HEAD ( & acpi_desc - > spas ) ;
INIT_LIST_HEAD ( & acpi_desc - > dcrs ) ;
INIT_LIST_HEAD ( & acpi_desc - > bdws ) ;
INIT_LIST_HEAD ( & acpi_desc - > memdevs ) ;
INIT_LIST_HEAD ( & acpi_desc - > dimms ) ;
data = ( u8 * ) acpi_desc - > nfit ;
end = data + sz ;
data + = sizeof ( struct acpi_table_nfit ) ;
while ( ! IS_ERR_OR_NULL ( data ) )
data = add_table ( acpi_desc , data , end ) ;
if ( IS_ERR ( data ) ) {
dev_dbg ( dev , " %s: nfit table parsing error: %ld \n " , __func__ ,
PTR_ERR ( data ) ) ;
return PTR_ERR ( data ) ;
}
if ( nfit_mem_init ( acpi_desc ) ! = 0 )
return - ENOMEM ;
2015-04-25 10:56:17 +03:00
return acpi_nfit_register_dimms ( acpi_desc ) ;
2015-05-20 05:54:31 +03:00
}
static int acpi_nfit_add ( struct acpi_device * adev )
{
struct nvdimm_bus_descriptor * nd_desc ;
struct acpi_nfit_desc * acpi_desc ;
struct device * dev = & adev - > dev ;
struct acpi_table_header * tbl ;
acpi_status status = AE_OK ;
acpi_size sz ;
int rc ;
status = acpi_get_table_with_size ( " NFIT " , 0 , & tbl , & sz ) ;
if ( ACPI_FAILURE ( status ) ) {
dev_err ( dev , " failed to find NFIT \n " ) ;
return - ENXIO ;
}
acpi_desc = devm_kzalloc ( dev , sizeof ( * acpi_desc ) , GFP_KERNEL ) ;
if ( ! acpi_desc )
return - ENOMEM ;
dev_set_drvdata ( dev , acpi_desc ) ;
acpi_desc - > dev = dev ;
acpi_desc - > nfit = ( struct acpi_table_nfit * ) tbl ;
nd_desc = & acpi_desc - > nd_desc ;
nd_desc - > provider_name = " ACPI.NFIT " ;
nd_desc - > ndctl = acpi_nfit_ctl ;
2015-04-27 02:26:48 +03:00
nd_desc - > attr_groups = acpi_nfit_attribute_groups ;
2015-05-20 05:54:31 +03:00
acpi_desc - > nvdimm_bus = nvdimm_bus_register ( dev , nd_desc ) ;
if ( ! acpi_desc - > nvdimm_bus )
return - ENXIO ;
rc = acpi_nfit_init ( acpi_desc , sz ) ;
if ( rc ) {
nvdimm_bus_unregister ( acpi_desc - > nvdimm_bus ) ;
return rc ;
}
return 0 ;
}
static int acpi_nfit_remove ( struct acpi_device * adev )
{
struct acpi_nfit_desc * acpi_desc = dev_get_drvdata ( & adev - > dev ) ;
nvdimm_bus_unregister ( acpi_desc - > nvdimm_bus ) ;
return 0 ;
}
static const struct acpi_device_id acpi_nfit_ids [ ] = {
{ " ACPI0012 " , 0 } ,
{ " " , 0 } ,
} ;
MODULE_DEVICE_TABLE ( acpi , acpi_nfit_ids ) ;
static struct acpi_driver acpi_nfit_driver = {
. name = KBUILD_MODNAME ,
. ids = acpi_nfit_ids ,
. ops = {
. add = acpi_nfit_add ,
. remove = acpi_nfit_remove ,
} ,
} ;
static __init int nfit_init ( void )
{
BUILD_BUG_ON ( sizeof ( struct acpi_table_nfit ) ! = 40 ) ;
BUILD_BUG_ON ( sizeof ( struct acpi_nfit_system_address ) ! = 56 ) ;
BUILD_BUG_ON ( sizeof ( struct acpi_nfit_memory_map ) ! = 48 ) ;
BUILD_BUG_ON ( sizeof ( struct acpi_nfit_interleave ) ! = 20 ) ;
BUILD_BUG_ON ( sizeof ( struct acpi_nfit_smbios ) ! = 9 ) ;
BUILD_BUG_ON ( sizeof ( struct acpi_nfit_control_region ) ! = 80 ) ;
BUILD_BUG_ON ( sizeof ( struct acpi_nfit_data_region ) ! = 40 ) ;
acpi_str_to_uuid ( UUID_VOLATILE_MEMORY , nfit_uuid [ NFIT_SPA_VOLATILE ] ) ;
acpi_str_to_uuid ( UUID_PERSISTENT_MEMORY , nfit_uuid [ NFIT_SPA_PM ] ) ;
acpi_str_to_uuid ( UUID_CONTROL_REGION , nfit_uuid [ NFIT_SPA_DCR ] ) ;
acpi_str_to_uuid ( UUID_DATA_REGION , nfit_uuid [ NFIT_SPA_BDW ] ) ;
acpi_str_to_uuid ( UUID_VOLATILE_VIRTUAL_DISK , nfit_uuid [ NFIT_SPA_VDISK ] ) ;
acpi_str_to_uuid ( UUID_VOLATILE_VIRTUAL_CD , nfit_uuid [ NFIT_SPA_VCD ] ) ;
acpi_str_to_uuid ( UUID_PERSISTENT_VIRTUAL_DISK , nfit_uuid [ NFIT_SPA_PDISK ] ) ;
acpi_str_to_uuid ( UUID_PERSISTENT_VIRTUAL_CD , nfit_uuid [ NFIT_SPA_PCD ] ) ;
acpi_str_to_uuid ( UUID_NFIT_BUS , nfit_uuid [ NFIT_DEV_BUS ] ) ;
acpi_str_to_uuid ( UUID_NFIT_DIMM , nfit_uuid [ NFIT_DEV_DIMM ] ) ;
return acpi_bus_register_driver ( & acpi_nfit_driver ) ;
}
static __exit void nfit_exit ( void )
{
acpi_bus_unregister_driver ( & acpi_nfit_driver ) ;
}
module_init ( nfit_init ) ;
module_exit ( nfit_exit ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_AUTHOR ( " Intel Corporation " ) ;