1313#include <linux/list_sort.h>
1414#include <linux/libnvdimm.h>
1515#include <linux/module.h>
16+ #include <linux/ndctl.h>
1617#include <linux/list.h>
1718#include <linux/acpi.h>
1819#include "nfit.h"
@@ -24,11 +25,153 @@ static const u8 *to_nfit_uuid(enum nfit_uuids id)
2425 return nfit_uuid [id ];
2526}
2627
28+ static struct acpi_nfit_desc * to_acpi_nfit_desc (
29+ struct nvdimm_bus_descriptor * nd_desc )
30+ {
31+ return container_of (nd_desc , struct acpi_nfit_desc , nd_desc );
32+ }
33+
34+ static struct acpi_device * to_acpi_dev (struct acpi_nfit_desc * acpi_desc )
35+ {
36+ struct nvdimm_bus_descriptor * nd_desc = & acpi_desc -> nd_desc ;
37+
38+ /*
39+ * If provider == 'ACPI.NFIT' we can assume 'dev' is a struct
40+ * acpi_device.
41+ */
42+ if (!nd_desc -> provider_name
43+ || strcmp (nd_desc -> provider_name , "ACPI.NFIT" ) != 0 )
44+ return NULL ;
45+
46+ return to_acpi_device (acpi_desc -> dev );
47+ }
48+
2749static int acpi_nfit_ctl (struct nvdimm_bus_descriptor * nd_desc ,
2850 struct nvdimm * nvdimm , unsigned int cmd , void * buf ,
2951 unsigned int buf_len )
3052{
31- return - ENOTTY ;
53+ struct acpi_nfit_desc * acpi_desc = to_acpi_nfit_desc (nd_desc );
54+ const struct nd_cmd_desc * desc = NULL ;
55+ union acpi_object in_obj , in_buf , * out_obj ;
56+ struct device * dev = acpi_desc -> dev ;
57+ const char * cmd_name , * dimm_name ;
58+ unsigned long dsm_mask ;
59+ acpi_handle handle ;
60+ const u8 * uuid ;
61+ u32 offset ;
62+ int rc , i ;
63+
64+ if (nvdimm ) {
65+ struct nfit_mem * nfit_mem = nvdimm_provider_data (nvdimm );
66+ struct acpi_device * adev = nfit_mem -> adev ;
67+
68+ if (!adev )
69+ return - ENOTTY ;
70+ dimm_name = dev_name (& adev -> dev );
71+ cmd_name = nvdimm_cmd_name (cmd );
72+ dsm_mask = nfit_mem -> dsm_mask ;
73+ desc = nd_cmd_dimm_desc (cmd );
74+ uuid = to_nfit_uuid (NFIT_DEV_DIMM );
75+ handle = adev -> handle ;
76+ } else {
77+ struct acpi_device * adev = to_acpi_dev (acpi_desc );
78+
79+ cmd_name = nvdimm_bus_cmd_name (cmd );
80+ dsm_mask = nd_desc -> dsm_mask ;
81+ desc = nd_cmd_bus_desc (cmd );
82+ uuid = to_nfit_uuid (NFIT_DEV_BUS );
83+ handle = adev -> handle ;
84+ dimm_name = "bus" ;
85+ }
86+
87+ if (!desc || (cmd && (desc -> out_num + desc -> in_num == 0 )))
88+ return - ENOTTY ;
89+
90+ if (!test_bit (cmd , & dsm_mask ))
91+ return - ENOTTY ;
92+
93+ in_obj .type = ACPI_TYPE_PACKAGE ;
94+ in_obj .package .count = 1 ;
95+ in_obj .package .elements = & in_buf ;
96+ in_buf .type = ACPI_TYPE_BUFFER ;
97+ in_buf .buffer .pointer = buf ;
98+ in_buf .buffer .length = 0 ;
99+
100+ /* libnvdimm has already validated the input envelope */
101+ for (i = 0 ; i < desc -> in_num ; i ++ )
102+ in_buf .buffer .length += nd_cmd_in_size (nvdimm , cmd , desc ,
103+ i , buf );
104+
105+ if (IS_ENABLED (CONFIG_ACPI_NFIT_DEBUG )) {
106+ dev_dbg (dev , "%s:%s cmd: %s input length: %d\n" , __func__ ,
107+ dimm_name , cmd_name , in_buf .buffer .length );
108+ print_hex_dump_debug (cmd_name , DUMP_PREFIX_OFFSET , 4 ,
109+ 4 , in_buf .buffer .pointer , min_t (u32 , 128 ,
110+ in_buf .buffer .length ), true);
111+ }
112+
113+ out_obj = acpi_evaluate_dsm (handle , uuid , 1 , cmd , & in_obj );
114+ if (!out_obj ) {
115+ dev_dbg (dev , "%s:%s _DSM failed cmd: %s\n" , __func__ , dimm_name ,
116+ cmd_name );
117+ return - EINVAL ;
118+ }
119+
120+ if (out_obj -> package .type != ACPI_TYPE_BUFFER ) {
121+ dev_dbg (dev , "%s:%s unexpected output object type cmd: %s type: %d\n" ,
122+ __func__ , dimm_name , cmd_name , out_obj -> type );
123+ rc = - EINVAL ;
124+ goto out ;
125+ }
126+
127+ if (IS_ENABLED (CONFIG_ACPI_NFIT_DEBUG )) {
128+ dev_dbg (dev , "%s:%s cmd: %s output length: %d\n" , __func__ ,
129+ dimm_name , cmd_name , out_obj -> buffer .length );
130+ print_hex_dump_debug (cmd_name , DUMP_PREFIX_OFFSET , 4 ,
131+ 4 , out_obj -> buffer .pointer , min_t (u32 , 128 ,
132+ out_obj -> buffer .length ), true);
133+ }
134+
135+ for (i = 0 , offset = 0 ; i < desc -> out_num ; i ++ ) {
136+ u32 out_size = nd_cmd_out_size (nvdimm , cmd , desc , i , buf ,
137+ (u32 * ) out_obj -> buffer .pointer );
138+
139+ if (offset + out_size > out_obj -> buffer .length ) {
140+ dev_dbg (dev , "%s:%s output object underflow cmd: %s field: %d\n" ,
141+ __func__ , dimm_name , cmd_name , i );
142+ break ;
143+ }
144+
145+ if (in_buf .buffer .length + offset + out_size > buf_len ) {
146+ dev_dbg (dev , "%s:%s output overrun cmd: %s field: %d\n" ,
147+ __func__ , dimm_name , cmd_name , i );
148+ rc = - ENXIO ;
149+ goto out ;
150+ }
151+ memcpy (buf + in_buf .buffer .length + offset ,
152+ out_obj -> buffer .pointer + offset , out_size );
153+ offset += out_size ;
154+ }
155+ if (offset + in_buf .buffer .length < buf_len ) {
156+ if (i >= 1 ) {
157+ /*
158+ * status valid, return the number of bytes left
159+ * unfilled in the output buffer
160+ */
161+ rc = buf_len - offset - in_buf .buffer .length ;
162+ } else {
163+ dev_err (dev , "%s:%s underrun cmd: %s buf_len: %d out_len: %d\n" ,
164+ __func__ , dimm_name , cmd_name , buf_len ,
165+ offset );
166+ rc = - ENXIO ;
167+ }
168+ } else
169+ rc = 0 ;
170+
171+ out :
172+ ACPI_FREE (out_obj );
173+
174+ return rc ;
32175}
33176
34177static const char * spa_type_name (u16 type )
@@ -489,6 +632,7 @@ static struct attribute_group acpi_nfit_dimm_attribute_group = {
489632};
490633
491634static const struct attribute_group * acpi_nfit_dimm_attribute_groups [] = {
635+ & nvdimm_attribute_group ,
492636 & acpi_nfit_dimm_attribute_group ,
493637 NULL ,
494638};
@@ -505,6 +649,50 @@ static struct nvdimm *acpi_nfit_dimm_by_handle(struct acpi_nfit_desc *acpi_desc,
505649 return NULL ;
506650}
507651
652+ static int acpi_nfit_add_dimm (struct acpi_nfit_desc * acpi_desc ,
653+ struct nfit_mem * nfit_mem , u32 device_handle )
654+ {
655+ struct acpi_device * adev , * adev_dimm ;
656+ struct device * dev = acpi_desc -> dev ;
657+ const u8 * uuid = to_nfit_uuid (NFIT_DEV_DIMM );
658+ unsigned long long sta ;
659+ int i , rc = - ENODEV ;
660+ acpi_status status ;
661+
662+ nfit_mem -> dsm_mask = acpi_desc -> dimm_dsm_force_en ;
663+ adev = to_acpi_dev (acpi_desc );
664+ if (!adev )
665+ return 0 ;
666+
667+ adev_dimm = acpi_find_child_device (adev , device_handle , false);
668+ nfit_mem -> adev = adev_dimm ;
669+ if (!adev_dimm ) {
670+ dev_err (dev , "no ACPI.NFIT device with _ADR %#x, disabling...\n" ,
671+ device_handle );
672+ return - ENODEV ;
673+ }
674+
675+ status = acpi_evaluate_integer (adev_dimm -> handle , "_STA" , NULL , & sta );
676+ if (status == AE_NOT_FOUND ) {
677+ dev_dbg (dev , "%s missing _STA, assuming enabled...\n" ,
678+ dev_name (& adev_dimm -> dev ));
679+ rc = 0 ;
680+ } else if (ACPI_FAILURE (status ))
681+ dev_err (dev , "%s failed to retrieve_STA, disabling...\n" ,
682+ dev_name (& adev_dimm -> dev ));
683+ else if ((sta & ACPI_STA_DEVICE_ENABLED ) == 0 )
684+ dev_info (dev , "%s disabled by firmware\n" ,
685+ dev_name (& adev_dimm -> dev ));
686+ else
687+ rc = 0 ;
688+
689+ for (i = ND_CMD_SMART ; i <= ND_CMD_VENDOR ; i ++ )
690+ if (acpi_check_dsm (adev_dimm -> handle , uuid , 1 , 1ULL << i ))
691+ set_bit (i , & nfit_mem -> dsm_mask );
692+
693+ return rc ;
694+ }
695+
508696static int acpi_nfit_register_dimms (struct acpi_nfit_desc * acpi_desc )
509697{
510698 struct nfit_mem * nfit_mem ;
@@ -513,6 +701,7 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc)
513701 struct nvdimm * nvdimm ;
514702 unsigned long flags = 0 ;
515703 u32 device_handle ;
704+ int rc ;
516705
517706 device_handle = __to_nfit_memdev (nfit_mem )-> device_handle ;
518707 nvdimm = acpi_nfit_dimm_by_handle (acpi_desc , device_handle );
@@ -529,8 +718,13 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc)
529718 if (nfit_mem -> bdw && nfit_mem -> memdev_pmem )
530719 flags |= NDD_ALIASING ;
531720
721+ rc = acpi_nfit_add_dimm (acpi_desc , nfit_mem , device_handle );
722+ if (rc )
723+ continue ;
724+
532725 nvdimm = nvdimm_create (acpi_desc -> nvdimm_bus , nfit_mem ,
533- acpi_nfit_dimm_attribute_groups , flags );
726+ acpi_nfit_dimm_attribute_groups ,
727+ flags , & nfit_mem -> dsm_mask );
534728 if (!nvdimm )
535729 return - ENOMEM ;
536730
@@ -540,6 +734,22 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc)
540734 return 0 ;
541735}
542736
737+ static void acpi_nfit_init_dsms (struct acpi_nfit_desc * acpi_desc )
738+ {
739+ struct nvdimm_bus_descriptor * nd_desc = & acpi_desc -> nd_desc ;
740+ const u8 * uuid = to_nfit_uuid (NFIT_DEV_BUS );
741+ struct acpi_device * adev ;
742+ int i ;
743+
744+ adev = to_acpi_dev (acpi_desc );
745+ if (!adev )
746+ return ;
747+
748+ for (i = ND_CMD_ARS_CAP ; i <= ND_CMD_ARS_STATUS ; i ++ )
749+ if (acpi_check_dsm (adev -> handle , uuid , 1 , 1ULL << i ))
750+ set_bit (i , & nd_desc -> dsm_mask );
751+ }
752+
543753static int acpi_nfit_init (struct acpi_nfit_desc * acpi_desc , acpi_size sz )
544754{
545755 struct device * dev = acpi_desc -> dev ;
@@ -567,6 +777,8 @@ static int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, acpi_size sz)
567777 if (nfit_mem_init (acpi_desc ) != 0 )
568778 return - ENOMEM ;
569779
780+ acpi_nfit_init_dsms (acpi_desc );
781+
570782 return acpi_nfit_register_dimms (acpi_desc );
571783}
572784
0 commit comments