diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2014-01-12 17:45:52 -0500 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2014-01-12 17:45:52 -0500 |
commit | fbb9c10d40f88011ac72f855c97e3bdd981026a9 (patch) | |
tree | 255b3c21fd859004310bfad0a829ea4392d4851b /drivers/gpu/drm/nouveau | |
parent | 3e7cc142c1e040fd4629ad34a54b1c5b46dc3dd3 (diff) | |
parent | 7ede9f8a1805b26b3141730c9deaea8bc95a64bc (diff) |
Merge branch 'acpi-dsm'
* acpi-dsm:
ACPI / extlog: replace open-coded _DSM code with helper functions
ACPI / nouveau: replace open-coded _DSM code with helper functions
nouveau / ACPI: fix memory leak in ACPI _DSM related code
ACPI / i915: replace open-coded _DSM code with helper functions
ACPI / i2c-hid: replace open-coded _DSM code with helper functions
ACPI / TPM: detect PPI features by checking availability of _DSM functions
ACPI / TPM: replace open-coded _DSM code with helper functions
ACPI / TPM: match node name instead of full path when searching for TPM device
PCI / pci-label: treat PCI label with index 0 as valid label
ACPI / PCI: replace open-coded _DSM code with helper functions
PCI / pci-label: release allocated ACPI object on error recovery path
ACPI: introduce helper interfaces for _DSM method
Diffstat (limited to 'drivers/gpu/drm/nouveau')
-rw-r--r-- | drivers/gpu/drm/nouveau/core/subdev/mxm/base.c | 48 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_acpi.c | 131 |
2 files changed, 53 insertions, 126 deletions
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mxm/base.c b/drivers/gpu/drm/nouveau/core/subdev/mxm/base.c index 129120473f6c..13c5af88a601 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/mxm/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/mxm/base.c | |||
@@ -87,55 +87,39 @@ mxm_shadow_dsm(struct nouveau_mxm *mxm, u8 version) | |||
87 | 0xB8, 0x9C, 0x79, 0xB6, 0x2F, 0xD5, 0x56, 0x65 | 87 | 0xB8, 0x9C, 0x79, 0xB6, 0x2F, 0xD5, 0x56, 0x65 |
88 | }; | 88 | }; |
89 | u32 mxms_args[] = { 0x00000000 }; | 89 | u32 mxms_args[] = { 0x00000000 }; |
90 | union acpi_object args[4] = { | 90 | union acpi_object argv4 = { |
91 | /* _DSM MUID */ | 91 | .buffer.type = ACPI_TYPE_BUFFER, |
92 | { .buffer.type = 3, | 92 | .buffer.length = sizeof(mxms_args), |
93 | .buffer.length = sizeof(muid), | 93 | .buffer.pointer = (char *)mxms_args, |
94 | .buffer.pointer = muid, | ||
95 | }, | ||
96 | /* spec says this can be zero to mean "highest revision", but | ||
97 | * of course there's at least one bios out there which fails | ||
98 | * unless you pass in exactly the version it supports.. | ||
99 | */ | ||
100 | { .integer.type = ACPI_TYPE_INTEGER, | ||
101 | .integer.value = (version & 0xf0) << 4 | (version & 0x0f), | ||
102 | }, | ||
103 | /* MXMS function */ | ||
104 | { .integer.type = ACPI_TYPE_INTEGER, | ||
105 | .integer.value = 0x00000010, | ||
106 | }, | ||
107 | /* Pointer to MXMS arguments */ | ||
108 | { .buffer.type = ACPI_TYPE_BUFFER, | ||
109 | .buffer.length = sizeof(mxms_args), | ||
110 | .buffer.pointer = (char *)mxms_args, | ||
111 | }, | ||
112 | }; | 94 | }; |
113 | struct acpi_object_list list = { ARRAY_SIZE(args), args }; | ||
114 | struct acpi_buffer retn = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
115 | union acpi_object *obj; | 95 | union acpi_object *obj; |
116 | acpi_handle handle; | 96 | acpi_handle handle; |
117 | int ret; | 97 | int rev; |
118 | 98 | ||
119 | handle = ACPI_HANDLE(&device->pdev->dev); | 99 | handle = ACPI_HANDLE(&device->pdev->dev); |
120 | if (!handle) | 100 | if (!handle) |
121 | return false; | 101 | return false; |
122 | 102 | ||
123 | ret = acpi_evaluate_object(handle, "_DSM", &list, &retn); | 103 | /* |
124 | if (ret) { | 104 | * spec says this can be zero to mean "highest revision", but |
125 | nv_debug(mxm, "DSM MXMS failed: %d\n", ret); | 105 | * of course there's at least one bios out there which fails |
106 | * unless you pass in exactly the version it supports.. | ||
107 | */ | ||
108 | rev = (version & 0xf0) << 4 | (version & 0x0f); | ||
109 | obj = acpi_evaluate_dsm(handle, muid, rev, 0x00000010, &argv4); | ||
110 | if (!obj) { | ||
111 | nv_debug(mxm, "DSM MXMS failed\n"); | ||
126 | return false; | 112 | return false; |
127 | } | 113 | } |
128 | 114 | ||
129 | obj = retn.pointer; | ||
130 | if (obj->type == ACPI_TYPE_BUFFER) { | 115 | if (obj->type == ACPI_TYPE_BUFFER) { |
131 | mxm->mxms = kmemdup(obj->buffer.pointer, | 116 | mxm->mxms = kmemdup(obj->buffer.pointer, |
132 | obj->buffer.length, GFP_KERNEL); | 117 | obj->buffer.length, GFP_KERNEL); |
133 | } else | 118 | } else if (obj->type == ACPI_TYPE_INTEGER) { |
134 | if (obj->type == ACPI_TYPE_INTEGER) { | ||
135 | nv_debug(mxm, "DSM MXMS returned 0x%llx\n", obj->integer.value); | 119 | nv_debug(mxm, "DSM MXMS returned 0x%llx\n", obj->integer.value); |
136 | } | 120 | } |
137 | 121 | ||
138 | kfree(obj); | 122 | ACPI_FREE(obj); |
139 | return mxm->mxms != NULL; | 123 | return mxm->mxms != NULL; |
140 | } | 124 | } |
141 | #endif | 125 | #endif |
diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c index 1bc996c4f121..3c149617cfcb 100644 --- a/drivers/gpu/drm/nouveau/nouveau_acpi.c +++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c | |||
@@ -73,124 +73,66 @@ static const char nouveau_op_dsm_muid[] = { | |||
73 | 73 | ||
74 | static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t *result) | 74 | static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t *result) |
75 | { | 75 | { |
76 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | 76 | int i; |
77 | struct acpi_object_list input; | ||
78 | union acpi_object params[4]; | ||
79 | union acpi_object *obj; | 77 | union acpi_object *obj; |
80 | int i, err; | ||
81 | char args_buff[4]; | 78 | char args_buff[4]; |
79 | union acpi_object argv4 = { | ||
80 | .buffer.type = ACPI_TYPE_BUFFER, | ||
81 | .buffer.length = 4, | ||
82 | .buffer.pointer = args_buff | ||
83 | }; | ||
82 | 84 | ||
83 | input.count = 4; | ||
84 | input.pointer = params; | ||
85 | params[0].type = ACPI_TYPE_BUFFER; | ||
86 | params[0].buffer.length = sizeof(nouveau_op_dsm_muid); | ||
87 | params[0].buffer.pointer = (char *)nouveau_op_dsm_muid; | ||
88 | params[1].type = ACPI_TYPE_INTEGER; | ||
89 | params[1].integer.value = 0x00000100; | ||
90 | params[2].type = ACPI_TYPE_INTEGER; | ||
91 | params[2].integer.value = func; | ||
92 | params[3].type = ACPI_TYPE_BUFFER; | ||
93 | params[3].buffer.length = 4; | ||
94 | /* ACPI is little endian, AABBCCDD becomes {DD,CC,BB,AA} */ | 85 | /* ACPI is little endian, AABBCCDD becomes {DD,CC,BB,AA} */ |
95 | for (i = 0; i < 4; i++) | 86 | for (i = 0; i < 4; i++) |
96 | args_buff[i] = (arg >> i * 8) & 0xFF; | 87 | args_buff[i] = (arg >> i * 8) & 0xFF; |
97 | params[3].buffer.pointer = args_buff; | ||
98 | 88 | ||
99 | err = acpi_evaluate_object(handle, "_DSM", &input, &output); | 89 | *result = 0; |
100 | if (err) { | 90 | obj = acpi_evaluate_dsm_typed(handle, nouveau_op_dsm_muid, 0x00000100, |
101 | printk(KERN_INFO "failed to evaluate _DSM: %d\n", err); | 91 | func, &argv4, ACPI_TYPE_BUFFER); |
102 | return err; | 92 | if (!obj) { |
103 | } | 93 | acpi_handle_info(handle, "failed to evaluate _DSM\n"); |
104 | 94 | return AE_ERROR; | |
105 | obj = (union acpi_object *)output.pointer; | 95 | } else { |
106 | 96 | if (obj->buffer.length == 4) { | |
107 | if (obj->type == ACPI_TYPE_INTEGER) | ||
108 | if (obj->integer.value == 0x80000002) { | ||
109 | return -ENODEV; | ||
110 | } | ||
111 | |||
112 | if (obj->type == ACPI_TYPE_BUFFER) { | ||
113 | if (obj->buffer.length == 4 && result) { | ||
114 | *result = 0; | ||
115 | *result |= obj->buffer.pointer[0]; | 97 | *result |= obj->buffer.pointer[0]; |
116 | *result |= (obj->buffer.pointer[1] << 8); | 98 | *result |= (obj->buffer.pointer[1] << 8); |
117 | *result |= (obj->buffer.pointer[2] << 16); | 99 | *result |= (obj->buffer.pointer[2] << 16); |
118 | *result |= (obj->buffer.pointer[3] << 24); | 100 | *result |= (obj->buffer.pointer[3] << 24); |
119 | } | 101 | } |
102 | ACPI_FREE(obj); | ||
120 | } | 103 | } |
121 | 104 | ||
122 | kfree(output.pointer); | ||
123 | return 0; | 105 | return 0; |
124 | } | 106 | } |
125 | 107 | ||
126 | static int nouveau_dsm(acpi_handle handle, int func, int arg, uint32_t *result) | 108 | static int nouveau_dsm(acpi_handle handle, int func, int arg) |
127 | { | 109 | { |
128 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | 110 | int ret = 0; |
129 | struct acpi_object_list input; | ||
130 | union acpi_object params[4]; | ||
131 | union acpi_object *obj; | 111 | union acpi_object *obj; |
132 | int err; | 112 | union acpi_object argv4 = { |
133 | 113 | .integer.type = ACPI_TYPE_INTEGER, | |
134 | input.count = 4; | 114 | .integer.value = arg, |
135 | input.pointer = params; | 115 | }; |
136 | params[0].type = ACPI_TYPE_BUFFER; | 116 | |
137 | params[0].buffer.length = sizeof(nouveau_dsm_muid); | 117 | obj = acpi_evaluate_dsm_typed(handle, nouveau_dsm_muid, 0x00000102, |
138 | params[0].buffer.pointer = (char *)nouveau_dsm_muid; | 118 | func, &argv4, ACPI_TYPE_INTEGER); |
139 | params[1].type = ACPI_TYPE_INTEGER; | 119 | if (!obj) { |
140 | params[1].integer.value = 0x00000102; | 120 | acpi_handle_info(handle, "failed to evaluate _DSM\n"); |
141 | params[2].type = ACPI_TYPE_INTEGER; | 121 | return AE_ERROR; |
142 | params[2].integer.value = func; | 122 | } else { |
143 | params[3].type = ACPI_TYPE_INTEGER; | ||
144 | params[3].integer.value = arg; | ||
145 | |||
146 | err = acpi_evaluate_object(handle, "_DSM", &input, &output); | ||
147 | if (err) { | ||
148 | printk(KERN_INFO "failed to evaluate _DSM: %d\n", err); | ||
149 | return err; | ||
150 | } | ||
151 | |||
152 | obj = (union acpi_object *)output.pointer; | ||
153 | |||
154 | if (obj->type == ACPI_TYPE_INTEGER) | ||
155 | if (obj->integer.value == 0x80000002) | 123 | if (obj->integer.value == 0x80000002) |
156 | return -ENODEV; | 124 | ret = -ENODEV; |
157 | 125 | ACPI_FREE(obj); | |
158 | if (obj->type == ACPI_TYPE_BUFFER) { | ||
159 | if (obj->buffer.length == 4 && result) { | ||
160 | *result = 0; | ||
161 | *result |= obj->buffer.pointer[0]; | ||
162 | *result |= (obj->buffer.pointer[1] << 8); | ||
163 | *result |= (obj->buffer.pointer[2] << 16); | ||
164 | *result |= (obj->buffer.pointer[3] << 24); | ||
165 | } | ||
166 | } | 126 | } |
167 | 127 | ||
168 | kfree(output.pointer); | 128 | return ret; |
169 | return 0; | ||
170 | } | ||
171 | |||
172 | /* Returns 1 if a DSM function is usable and 0 otherwise */ | ||
173 | static int nouveau_test_dsm(acpi_handle test_handle, | ||
174 | int (*dsm_func)(acpi_handle, int, int, uint32_t *), | ||
175 | int sfnc) | ||
176 | { | ||
177 | u32 result = 0; | ||
178 | |||
179 | /* Function 0 returns a Buffer containing available functions. The args | ||
180 | * parameter is ignored for function 0, so just put 0 in it */ | ||
181 | if (dsm_func(test_handle, 0, 0, &result)) | ||
182 | return 0; | ||
183 | |||
184 | /* ACPI Spec v4 9.14.1: if bit 0 is zero, no function is supported. If | ||
185 | * the n-th bit is enabled, function n is supported */ | ||
186 | return result & 1 && result & (1 << sfnc); | ||
187 | } | 129 | } |
188 | 130 | ||
189 | static int nouveau_dsm_switch_mux(acpi_handle handle, int mux_id) | 131 | static int nouveau_dsm_switch_mux(acpi_handle handle, int mux_id) |
190 | { | 132 | { |
191 | mxm_wmi_call_mxmx(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0); | 133 | mxm_wmi_call_mxmx(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0); |
192 | mxm_wmi_call_mxds(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0); | 134 | mxm_wmi_call_mxds(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0); |
193 | return nouveau_dsm(handle, NOUVEAU_DSM_LED, mux_id, NULL); | 135 | return nouveau_dsm(handle, NOUVEAU_DSM_LED, mux_id); |
194 | } | 136 | } |
195 | 137 | ||
196 | static int nouveau_dsm_set_discrete_state(acpi_handle handle, enum vga_switcheroo_state state) | 138 | static int nouveau_dsm_set_discrete_state(acpi_handle handle, enum vga_switcheroo_state state) |
@@ -200,7 +142,7 @@ static int nouveau_dsm_set_discrete_state(acpi_handle handle, enum vga_switchero | |||
200 | arg = NOUVEAU_DSM_POWER_SPEED; | 142 | arg = NOUVEAU_DSM_POWER_SPEED; |
201 | else | 143 | else |
202 | arg = NOUVEAU_DSM_POWER_STAMINA; | 144 | arg = NOUVEAU_DSM_POWER_STAMINA; |
203 | nouveau_dsm(handle, NOUVEAU_DSM_POWER, arg, NULL); | 145 | nouveau_dsm(handle, NOUVEAU_DSM_POWER, arg); |
204 | return 0; | 146 | return 0; |
205 | } | 147 | } |
206 | 148 | ||
@@ -260,11 +202,12 @@ static int nouveau_dsm_pci_probe(struct pci_dev *pdev) | |||
260 | nouveau_dsm_priv.other_handle = dhandle; | 202 | nouveau_dsm_priv.other_handle = dhandle; |
261 | return false; | 203 | return false; |
262 | } | 204 | } |
263 | if (nouveau_test_dsm(dhandle, nouveau_dsm, NOUVEAU_DSM_POWER)) | 205 | if (acpi_check_dsm(dhandle, nouveau_dsm_muid, 0x00000102, |
206 | 1 << NOUVEAU_DSM_POWER)) | ||
264 | retval |= NOUVEAU_DSM_HAS_MUX; | 207 | retval |= NOUVEAU_DSM_HAS_MUX; |
265 | 208 | ||
266 | if (nouveau_test_dsm(dhandle, nouveau_optimus_dsm, | 209 | if (acpi_check_dsm(dhandle, nouveau_op_dsm_muid, 0x00000100, |
267 | NOUVEAU_DSM_OPTIMUS_CAPS)) | 210 | 1 << NOUVEAU_DSM_OPTIMUS_CAPS)) |
268 | retval |= NOUVEAU_DSM_HAS_OPT; | 211 | retval |= NOUVEAU_DSM_HAS_OPT; |
269 | 212 | ||
270 | if (retval & NOUVEAU_DSM_HAS_OPT) { | 213 | if (retval & NOUVEAU_DSM_HAS_OPT) { |