aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/pcie/drv.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwlwifi/pcie/drv.c')
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/drv.c85
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};
396MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids); 401MODULE_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
410static 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
441static 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 */
476static 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}