13
13
#include <linux/list_sort.h>
14
14
#include <linux/libnvdimm.h>
15
15
#include <linux/module.h>
16
+ #include <linux/ndctl.h>
16
17
#include <linux/list.h>
17
18
#include <linux/acpi.h>
18
19
#include "nfit.h"
@@ -24,11 +25,153 @@ static const u8 *to_nfit_uuid(enum nfit_uuids id)
24
25
return nfit_uuid [id ];
25
26
}
26
27
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
+
27
49
static int acpi_nfit_ctl (struct nvdimm_bus_descriptor * nd_desc ,
28
50
struct nvdimm * nvdimm , unsigned int cmd , void * buf ,
29
51
unsigned int buf_len )
30
52
{
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 ;
32
175
}
33
176
34
177
static const char * spa_type_name (u16 type )
@@ -489,6 +632,7 @@ static struct attribute_group acpi_nfit_dimm_attribute_group = {
489
632
};
490
633
491
634
static const struct attribute_group * acpi_nfit_dimm_attribute_groups [] = {
635
+ & nvdimm_attribute_group ,
492
636
& acpi_nfit_dimm_attribute_group ,
493
637
NULL ,
494
638
};
@@ -505,6 +649,50 @@ static struct nvdimm *acpi_nfit_dimm_by_handle(struct acpi_nfit_desc *acpi_desc,
505
649
return NULL ;
506
650
}
507
651
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
+
508
696
static int acpi_nfit_register_dimms (struct acpi_nfit_desc * acpi_desc )
509
697
{
510
698
struct nfit_mem * nfit_mem ;
@@ -513,6 +701,7 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc)
513
701
struct nvdimm * nvdimm ;
514
702
unsigned long flags = 0 ;
515
703
u32 device_handle ;
704
+ int rc ;
516
705
517
706
device_handle = __to_nfit_memdev (nfit_mem )-> device_handle ;
518
707
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)
529
718
if (nfit_mem -> bdw && nfit_mem -> memdev_pmem )
530
719
flags |= NDD_ALIASING ;
531
720
721
+ rc = acpi_nfit_add_dimm (acpi_desc , nfit_mem , device_handle );
722
+ if (rc )
723
+ continue ;
724
+
532
725
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 );
534
728
if (!nvdimm )
535
729
return - ENOMEM ;
536
730
@@ -540,6 +734,22 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc)
540
734
return 0 ;
541
735
}
542
736
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
+
543
753
static int acpi_nfit_init (struct acpi_nfit_desc * acpi_desc , acpi_size sz )
544
754
{
545
755
struct device * dev = acpi_desc -> dev ;
@@ -567,6 +777,8 @@ static int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, acpi_size sz)
567
777
if (nfit_mem_init (acpi_desc ) != 0 )
568
778
return - ENOMEM ;
569
779
780
+ acpi_nfit_init_dsms (acpi_desc );
781
+
570
782
return acpi_nfit_register_dimms (acpi_desc );
571
783
}
572
784
0 commit comments