.. | .. |
---|
1 | | -// SPDX-License-Identifier: GPL-2.0 |
---|
| 1 | +// SPDX-License-Identifier: MIT |
---|
2 | 2 | #include <linux/pci.h> |
---|
3 | 3 | #include <linux/acpi.h> |
---|
4 | 4 | #include <linux/slab.h> |
---|
.. | .. |
---|
49 | 49 | bool optimus_flags_detected; |
---|
50 | 50 | bool optimus_skip_dsm; |
---|
51 | 51 | acpi_handle dhandle; |
---|
52 | | - acpi_handle rom_handle; |
---|
53 | 52 | } nouveau_dsm_priv; |
---|
54 | 53 | |
---|
55 | 54 | bool nouveau_is_optimus(void) { |
---|
.. | .. |
---|
212 | 211 | .get_client_id = nouveau_dsm_get_client_id, |
---|
213 | 212 | }; |
---|
214 | 213 | |
---|
215 | | -/* |
---|
216 | | - * Firmware supporting Windows 8 or later do not use _DSM to put the device into |
---|
217 | | - * D3cold, they instead rely on disabling power resources on the parent. |
---|
218 | | - */ |
---|
219 | | -static bool nouveau_pr3_present(struct pci_dev *pdev) |
---|
220 | | -{ |
---|
221 | | - struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); |
---|
222 | | - struct acpi_device *parent_adev; |
---|
223 | | - |
---|
224 | | - if (!parent_pdev) |
---|
225 | | - return false; |
---|
226 | | - |
---|
227 | | - if (!parent_pdev->bridge_d3) { |
---|
228 | | - /* |
---|
229 | | - * Parent PCI bridge is currently not power managed. |
---|
230 | | - * Since userspace can change these afterwards to be on |
---|
231 | | - * the safe side we stick with _DSM and prevent usage of |
---|
232 | | - * _PR3 from the bridge. |
---|
233 | | - */ |
---|
234 | | - pci_d3cold_disable(pdev); |
---|
235 | | - return false; |
---|
236 | | - } |
---|
237 | | - |
---|
238 | | - parent_adev = ACPI_COMPANION(&parent_pdev->dev); |
---|
239 | | - if (!parent_adev) |
---|
240 | | - return false; |
---|
241 | | - |
---|
242 | | - return parent_adev->power.flags.power_resources && |
---|
243 | | - acpi_has_method(parent_adev->handle, "_PR3"); |
---|
244 | | -} |
---|
245 | | - |
---|
246 | 214 | static void nouveau_dsm_pci_probe(struct pci_dev *pdev, acpi_handle *dhandle_out, |
---|
247 | 215 | bool *has_mux, bool *has_opt, |
---|
248 | 216 | bool *has_opt_flags, bool *has_pr3) |
---|
.. | .. |
---|
250 | 218 | acpi_handle dhandle; |
---|
251 | 219 | bool supports_mux; |
---|
252 | 220 | int optimus_funcs; |
---|
| 221 | + struct pci_dev *parent_pdev; |
---|
| 222 | + |
---|
| 223 | + if (pdev->vendor != PCI_VENDOR_ID_NVIDIA) |
---|
| 224 | + return; |
---|
| 225 | + |
---|
| 226 | + *has_pr3 = false; |
---|
| 227 | + parent_pdev = pci_upstream_bridge(pdev); |
---|
| 228 | + if (parent_pdev) { |
---|
| 229 | + if (parent_pdev->bridge_d3) |
---|
| 230 | + *has_pr3 = pci_pr3_present(parent_pdev); |
---|
| 231 | + else |
---|
| 232 | + pci_d3cold_disable(pdev); |
---|
| 233 | + } |
---|
253 | 234 | |
---|
254 | 235 | dhandle = ACPI_HANDLE(&pdev->dev); |
---|
255 | 236 | if (!dhandle) |
---|
.. | .. |
---|
270 | 251 | *has_mux = supports_mux; |
---|
271 | 252 | *has_opt = !!optimus_funcs; |
---|
272 | 253 | *has_opt_flags = optimus_funcs & (1 << NOUVEAU_DSM_OPTIMUS_FLAGS); |
---|
273 | | - *has_pr3 = false; |
---|
274 | 254 | |
---|
275 | 255 | if (optimus_funcs) { |
---|
276 | 256 | uint32_t result; |
---|
.. | .. |
---|
280 | 260 | (result & OPTIMUS_ENABLED) ? "enabled" : "disabled", |
---|
281 | 261 | (result & OPTIMUS_DYNAMIC_PWR_CAP) ? "dynamic power, " : "", |
---|
282 | 262 | (result & OPTIMUS_HDA_CODEC_MASK) ? "hda bios codec supported" : ""); |
---|
283 | | - |
---|
284 | | - *has_pr3 = nouveau_pr3_present(pdev); |
---|
285 | 263 | } |
---|
286 | 264 | } |
---|
287 | 265 | |
---|
.. | .. |
---|
384 | 362 | void nouveau_unregister_dsm_handler(void) {} |
---|
385 | 363 | void nouveau_switcheroo_optimus_dsm(void) {} |
---|
386 | 364 | #endif |
---|
387 | | - |
---|
388 | | -/* retrieve the ROM in 4k blocks */ |
---|
389 | | -static int nouveau_rom_call(acpi_handle rom_handle, uint8_t *bios, |
---|
390 | | - int offset, int len) |
---|
391 | | -{ |
---|
392 | | - acpi_status status; |
---|
393 | | - union acpi_object rom_arg_elements[2], *obj; |
---|
394 | | - struct acpi_object_list rom_arg; |
---|
395 | | - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL}; |
---|
396 | | - |
---|
397 | | - rom_arg.count = 2; |
---|
398 | | - rom_arg.pointer = &rom_arg_elements[0]; |
---|
399 | | - |
---|
400 | | - rom_arg_elements[0].type = ACPI_TYPE_INTEGER; |
---|
401 | | - rom_arg_elements[0].integer.value = offset; |
---|
402 | | - |
---|
403 | | - rom_arg_elements[1].type = ACPI_TYPE_INTEGER; |
---|
404 | | - rom_arg_elements[1].integer.value = len; |
---|
405 | | - |
---|
406 | | - status = acpi_evaluate_object(rom_handle, NULL, &rom_arg, &buffer); |
---|
407 | | - if (ACPI_FAILURE(status)) { |
---|
408 | | - pr_info("failed to evaluate ROM got %s\n", |
---|
409 | | - acpi_format_exception(status)); |
---|
410 | | - return -ENODEV; |
---|
411 | | - } |
---|
412 | | - obj = (union acpi_object *)buffer.pointer; |
---|
413 | | - len = min(len, (int)obj->buffer.length); |
---|
414 | | - memcpy(bios+offset, obj->buffer.pointer, len); |
---|
415 | | - kfree(buffer.pointer); |
---|
416 | | - return len; |
---|
417 | | -} |
---|
418 | | - |
---|
419 | | -bool nouveau_acpi_rom_supported(struct device *dev) |
---|
420 | | -{ |
---|
421 | | - acpi_status status; |
---|
422 | | - acpi_handle dhandle, rom_handle; |
---|
423 | | - |
---|
424 | | - dhandle = ACPI_HANDLE(dev); |
---|
425 | | - if (!dhandle) |
---|
426 | | - return false; |
---|
427 | | - |
---|
428 | | - status = acpi_get_handle(dhandle, "_ROM", &rom_handle); |
---|
429 | | - if (ACPI_FAILURE(status)) |
---|
430 | | - return false; |
---|
431 | | - |
---|
432 | | - nouveau_dsm_priv.rom_handle = rom_handle; |
---|
433 | | - return true; |
---|
434 | | -} |
---|
435 | | - |
---|
436 | | -int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len) |
---|
437 | | -{ |
---|
438 | | - return nouveau_rom_call(nouveau_dsm_priv.rom_handle, bios, offset, len); |
---|
439 | | -} |
---|
440 | 365 | |
---|
441 | 366 | void * |
---|
442 | 367 | nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector) |
---|