diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/pcie/drv.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/pcie/drv.c | 85 |
1 files changed, 84 insertions, 1 deletions
diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index 3872ead75488..edb015c99049 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c | |||
@@ -66,6 +66,7 @@ | |||
66 | #include <linux/module.h> | 66 | #include <linux/module.h> |
67 | #include <linux/pci.h> | 67 | #include <linux/pci.h> |
68 | #include <linux/pci-aspm.h> | 68 | #include <linux/pci-aspm.h> |
69 | #include <linux/acpi.h> | ||
69 | 70 | ||
70 | #include "iwl-trans.h" | 71 | #include "iwl-trans.h" |
71 | #include "iwl-drv.h" | 72 | #include "iwl-drv.h" |
@@ -389,12 +390,92 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { | |||
389 | {IWL_PCI_DEVICE(0x095A, 0x5590, iwl7265_2ac_cfg)}, | 390 | {IWL_PCI_DEVICE(0x095A, 0x5590, iwl7265_2ac_cfg)}, |
390 | {IWL_PCI_DEVICE(0x095B, 0x5290, iwl7265_2ac_cfg)}, | 391 | {IWL_PCI_DEVICE(0x095B, 0x5290, iwl7265_2ac_cfg)}, |
391 | {IWL_PCI_DEVICE(0x095A, 0x5490, iwl7265_2ac_cfg)}, | 392 | {IWL_PCI_DEVICE(0x095A, 0x5490, iwl7265_2ac_cfg)}, |
393 | |||
394 | /* 8000 Series */ | ||
395 | {IWL_PCI_DEVICE(0x24F3, 0x0010, iwl8260_2ac_cfg)}, | ||
396 | {IWL_PCI_DEVICE(0x24F4, 0x0030, iwl8260_2ac_cfg)}, | ||
392 | #endif /* CONFIG_IWLMVM */ | 397 | #endif /* CONFIG_IWLMVM */ |
393 | 398 | ||
394 | {0} | 399 | {0} |
395 | }; | 400 | }; |
396 | MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids); | 401 | MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids); |
397 | 402 | ||
403 | #ifdef CONFIG_ACPI | ||
404 | #define SPL_METHOD "SPLC" | ||
405 | #define SPL_DOMAINTYPE_MODULE BIT(0) | ||
406 | #define SPL_DOMAINTYPE_WIFI BIT(1) | ||
407 | #define SPL_DOMAINTYPE_WIGIG BIT(2) | ||
408 | #define SPL_DOMAINTYPE_RFEM BIT(3) | ||
409 | |||
410 | static u64 splx_get_pwr_limit(struct iwl_trans *trans, union acpi_object *splx) | ||
411 | { | ||
412 | union acpi_object *limits, *domain_type, *power_limit; | ||
413 | |||
414 | if (splx->type != ACPI_TYPE_PACKAGE || | ||
415 | splx->package.count != 2 || | ||
416 | splx->package.elements[0].type != ACPI_TYPE_INTEGER || | ||
417 | splx->package.elements[0].integer.value != 0) { | ||
418 | IWL_ERR(trans, "Unsupported splx structure"); | ||
419 | return 0; | ||
420 | } | ||
421 | |||
422 | limits = &splx->package.elements[1]; | ||
423 | if (limits->type != ACPI_TYPE_PACKAGE || | ||
424 | limits->package.count < 2 || | ||
425 | limits->package.elements[0].type != ACPI_TYPE_INTEGER || | ||
426 | limits->package.elements[1].type != ACPI_TYPE_INTEGER) { | ||
427 | IWL_ERR(trans, "Invalid limits element"); | ||
428 | return 0; | ||
429 | } | ||
430 | |||
431 | domain_type = &limits->package.elements[0]; | ||
432 | power_limit = &limits->package.elements[1]; | ||
433 | if (!(domain_type->integer.value & SPL_DOMAINTYPE_WIFI)) { | ||
434 | IWL_DEBUG_INFO(trans, "WiFi power is not limited"); | ||
435 | return 0; | ||
436 | } | ||
437 | |||
438 | return power_limit->integer.value; | ||
439 | } | ||
440 | |||
441 | static void set_dflt_pwr_limit(struct iwl_trans *trans, struct pci_dev *pdev) | ||
442 | { | ||
443 | acpi_handle pxsx_handle; | ||
444 | acpi_handle handle; | ||
445 | struct acpi_buffer splx = {ACPI_ALLOCATE_BUFFER, NULL}; | ||
446 | acpi_status status; | ||
447 | |||
448 | pxsx_handle = ACPI_HANDLE(&pdev->dev); | ||
449 | if (!pxsx_handle) { | ||
450 | IWL_DEBUG_INFO(trans, | ||
451 | "Could not retrieve root port ACPI handle"); | ||
452 | return; | ||
453 | } | ||
454 | |||
455 | /* Get the method's handle */ | ||
456 | status = acpi_get_handle(pxsx_handle, (acpi_string)SPL_METHOD, &handle); | ||
457 | if (ACPI_FAILURE(status)) { | ||
458 | IWL_DEBUG_INFO(trans, "SPL method not found"); | ||
459 | return; | ||
460 | } | ||
461 | |||
462 | /* Call SPLC with no arguments */ | ||
463 | status = acpi_evaluate_object(handle, NULL, NULL, &splx); | ||
464 | if (ACPI_FAILURE(status)) { | ||
465 | IWL_ERR(trans, "SPLC invocation failed (0x%x)", status); | ||
466 | return; | ||
467 | } | ||
468 | |||
469 | trans->dflt_pwr_limit = splx_get_pwr_limit(trans, splx.pointer); | ||
470 | IWL_DEBUG_INFO(trans, "Default power limit set to %lld", | ||
471 | trans->dflt_pwr_limit); | ||
472 | kfree(splx.pointer); | ||
473 | } | ||
474 | |||
475 | #else /* CONFIG_ACPI */ | ||
476 | static void set_dflt_pwr_limit(struct iwl_trans *trans, struct pci_dev *pdev) {} | ||
477 | #endif | ||
478 | |||
398 | /* PCI registers */ | 479 | /* PCI registers */ |
399 | #define PCI_CFG_RETRY_TIMEOUT 0x041 | 480 | #define PCI_CFG_RETRY_TIMEOUT 0x041 |
400 | 481 | ||
@@ -419,6 +500,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
419 | goto out_free_trans; | 500 | goto out_free_trans; |
420 | } | 501 | } |
421 | 502 | ||
503 | set_dflt_pwr_limit(iwl_trans, pdev); | ||
504 | |||
422 | /* register transport layer debugfs here */ | 505 | /* register transport layer debugfs here */ |
423 | ret = iwl_trans_dbgfs_register(iwl_trans, iwl_trans->dbgfs_dir); | 506 | ret = iwl_trans_dbgfs_register(iwl_trans, iwl_trans->dbgfs_dir); |
424 | if (ret) | 507 | if (ret) |
@@ -477,7 +560,7 @@ static int iwl_pci_resume(struct device *device) | |||
477 | iwl_enable_rfkill_int(trans); | 560 | iwl_enable_rfkill_int(trans); |
478 | 561 | ||
479 | hw_rfkill = iwl_is_rfkill_set(trans); | 562 | hw_rfkill = iwl_is_rfkill_set(trans); |
480 | iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill); | 563 | iwl_trans_pcie_rf_kill(trans, hw_rfkill); |
481 | 564 | ||
482 | return 0; | 565 | return 0; |
483 | } | 566 | } |