Commit 2b0181a5 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki
Browse files

Merge branch 'acpi-processor'

Merge ACPI processor driver changes for 6.20-rc1/7.0-rc1:

 - Rework the ACPI idle driver initialization to register it directly
   from the common initialization code instead of doing that from a
   CPU hotplug "online" callback and clean it up (Huisong Li, Rafael
   Wysocki)

 - Fix a possible NULL pointer dereference in
   acpi_processor_errata_piix4() (Tuo Li)

* acpi-processor:
  ACPI: processor: idle: Rework the handling of acpi_processor_ffh_lpi_probe()
  ACPI: processor: idle: Convert acpi_processor_setup_cpuidle_dev() to void
  ACPI: processor: idle: Convert acpi_processor_setup_cpuidle_states() to void
  ACPI: processor: idle: Add debug log for states with invalid entry methods
  ACPI: processor: Fix NULL-pointer dereference in acpi_processor_errata_piix4()
  ACPI: processor: Do not expose global variable acpi_idle_driver
  ACPI: processor: idle: Rearrange declarations in header file
  ACPI: processor: idle: Redefine two functions as void
  ACPI: processor: Update cpuidle driver check in __acpi_processor_start()
  ACPI: processor: Remove unused empty stubs of some functions
  ACPI: processor: idle: Optimize ACPI idle driver registration
parents 1a91d4e2 cac173be
Loading
Loading
Loading
Loading
+15 −13
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@ static int acpi_processor_errata_piix4(struct pci_dev *dev)
{
	u8 value1 = 0;
	u8 value2 = 0;
	struct pci_dev *ide_dev = NULL, *isa_dev = NULL;


	if (!dev)
@@ -107,12 +108,12 @@ static int acpi_processor_errata_piix4(struct pci_dev *dev)
		 * each IDE controller's DMA status to make sure we catch all
		 * DMA activity.
		 */
		dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
		ide_dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
				     PCI_DEVICE_ID_INTEL_82371AB,
				     PCI_ANY_ID, PCI_ANY_ID, NULL);
		if (dev) {
			errata.piix4.bmisx = pci_resource_start(dev, 4);
			pci_dev_put(dev);
		if (ide_dev) {
			errata.piix4.bmisx = pci_resource_start(ide_dev, 4);
			pci_dev_put(ide_dev);
		}

		/*
@@ -124,24 +125,25 @@ static int acpi_processor_errata_piix4(struct pci_dev *dev)
		 * disable C3 support if this is enabled, as some legacy
		 * devices won't operate well if fast DMA is disabled.
		 */
		dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
		isa_dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
				     PCI_DEVICE_ID_INTEL_82371AB_0,
				     PCI_ANY_ID, PCI_ANY_ID, NULL);
		if (dev) {
			pci_read_config_byte(dev, 0x76, &value1);
			pci_read_config_byte(dev, 0x77, &value2);
		if (isa_dev) {
			pci_read_config_byte(isa_dev, 0x76, &value1);
			pci_read_config_byte(isa_dev, 0x77, &value2);
			if ((value1 & 0x80) || (value2 & 0x80))
				errata.piix4.fdma = 1;
			pci_dev_put(dev);
			pci_dev_put(isa_dev);
		}

		break;
	}

	if (errata.piix4.bmisx)
		dev_dbg(&dev->dev, "Bus master activity detection (BM-IDE) erratum enabled\n");
	if (errata.piix4.fdma)
		dev_dbg(&dev->dev, "Type-F DMA livelock erratum (C3 disabled)\n");
	if (ide_dev)
		dev_dbg(&ide_dev->dev, "Bus master activity detection (BM-IDE) erratum enabled\n");

	if (isa_dev)
		dev_dbg(&isa_dev->dev, "Type-F DMA livelock erratum (C3 disabled)\n");

	return 0;
}
+10 −3
Original line number Diff line number Diff line
@@ -166,7 +166,6 @@ static int __acpi_processor_start(struct acpi_device *device)
	if (result && !IS_ENABLED(CONFIG_ACPI_CPU_FREQ_PSS))
		dev_dbg(&device->dev, "CPPC data invalid or not present\n");

	if (!cpuidle_get_driver() || cpuidle_get_driver() == &acpi_idle_driver)
	acpi_processor_power_init(pr);

	acpi_pss_perf_init(pr);
@@ -259,9 +258,11 @@ static int __init acpi_processor_driver_init(void)
		acpi_processor_ignore_ppc_init();
	}

	acpi_processor_register_idle_driver();

	result = driver_register(&acpi_processor_driver);
	if (result < 0)
		return result;
		goto unregister_idle_drv;

	result = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
				   "acpi/cpu-drv:online",
@@ -283,8 +284,13 @@ static int __init acpi_processor_driver_init(void)
	acpi_idle_rescan_dead_smt_siblings();

	return 0;

err:
	driver_unregister(&acpi_processor_driver);

unregister_idle_drv:
	acpi_processor_unregister_idle_driver();

	return result;
}

@@ -302,6 +308,7 @@ static void __exit acpi_processor_driver_exit(void)
	cpuhp_remove_state_nocalls(hp_online);
	cpuhp_remove_state_nocalls(CPUHP_ACPI_CPUDRV_DEAD);
	driver_unregister(&acpi_processor_driver);
	acpi_processor_unregister_idle_driver();
}

module_init(acpi_processor_driver_init);
+93 −65
Original line number Diff line number Diff line
@@ -51,7 +51,7 @@ module_param(latency_factor, uint, 0644);

static DEFINE_PER_CPU(struct cpuidle_device *, acpi_cpuidle_device);

struct cpuidle_driver acpi_idle_driver = {
static struct cpuidle_driver acpi_idle_driver = {
	.name =		"acpi_idle",
	.owner =	THIS_MODULE,
};
@@ -946,6 +946,8 @@ static int acpi_processor_evaluate_lpi(acpi_handle handle,
			lpi_state->entry_method = ACPI_CSTATE_INTEGER;
			lpi_state->address = obj->integer.value;
		} else {
			pr_debug("Entry method of state-%d is invalid, disable it.\n",
				 state_idx);
			continue;
		}

@@ -1178,7 +1180,7 @@ static int acpi_idle_lpi_enter(struct cpuidle_device *dev,
	return -EINVAL;
}

static int acpi_processor_setup_lpi_states(struct acpi_processor *pr)
static void acpi_processor_setup_lpi_states(struct acpi_processor *pr)
{
	int i;
	struct acpi_lpi_state *lpi;
@@ -1186,7 +1188,7 @@ static int acpi_processor_setup_lpi_states(struct acpi_processor *pr)
	struct cpuidle_driver *drv = &acpi_idle_driver;

	if (!pr->flags.has_lpi)
		return -EOPNOTSUPP;
		return;

	for (i = 0; i < pr->power.count && i < CPUIDLE_STATE_MAX; i++) {
		lpi = &pr->power.lpi_states[i];
@@ -1204,8 +1206,6 @@ static int acpi_processor_setup_lpi_states(struct acpi_processor *pr)
	}

	drv->state_count = i;

	return 0;
}

/**
@@ -1214,13 +1214,13 @@ static int acpi_processor_setup_lpi_states(struct acpi_processor *pr)
 *
 * @pr: the ACPI processor
 */
static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr)
static void acpi_processor_setup_cpuidle_states(struct acpi_processor *pr)
{
	int i;
	struct cpuidle_driver *drv = &acpi_idle_driver;

	if (!pr->flags.power_setup_done || !pr->flags.power)
		return -EINVAL;
		return;

	drv->safe_state_index = -1;
	for (i = ACPI_IDLE_STATE_START; i < CPUIDLE_STATE_MAX; i++) {
@@ -1228,32 +1228,30 @@ static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr)
		drv->states[i].desc[0] = '\0';
	}

	if (pr->flags.has_lpi)
		return acpi_processor_setup_lpi_states(pr);
	if (pr->flags.has_lpi) {
		acpi_processor_setup_lpi_states(pr);
		return;
	}

	acpi_processor_setup_cstates(pr);
	return 0;
}

/**
 * acpi_processor_setup_cpuidle_dev - prepares and configures CPUIDLE
 * acpi_processor_setup_cpuidle_dev - configures CPUIDLE
 * device i.e. per-cpu data
 *
 * @pr: the ACPI processor
 * @dev : the cpuidle device
 */
static int acpi_processor_setup_cpuidle_dev(struct acpi_processor *pr,
static void acpi_processor_setup_cpuidle_dev(struct acpi_processor *pr,
					     struct cpuidle_device *dev)
{
	if (!pr->flags.power_setup_done || !pr->flags.power || !dev)
		return -EINVAL;
		return;

	dev->cpu = pr->id;
	if (pr->flags.has_lpi)
		return acpi_processor_ffh_lpi_probe(pr->id);

	if (!pr->flags.has_lpi)
		acpi_processor_setup_cpuidle_cx(pr, dev);
	return 0;
}

static int acpi_processor_get_power_info(struct acpi_processor *pr)
@@ -1262,7 +1260,13 @@ static int acpi_processor_get_power_info(struct acpi_processor *pr)

	ret = acpi_processor_get_lpi_info(pr);
	if (ret)
		ret = acpi_processor_get_cstate_info(pr);
		return acpi_processor_get_cstate_info(pr);

	if (pr->flags.has_lpi) {
		ret = acpi_processor_ffh_lpi_probe(pr->id);
		if (ret)
			pr_err("CPU%u: Invalid FFH LPI data\n", pr->id);
	}

	return ret;
}
@@ -1347,79 +1351,103 @@ int acpi_processor_power_state_has_changed(struct acpi_processor *pr)
	return 0;
}

static int acpi_processor_registered;
void acpi_processor_register_idle_driver(void)
{
	struct acpi_processor *pr;
	int ret = -ENODEV;
	int cpu;

	/*
	 * ACPI idle driver is used by all possible CPUs.
	 * Use the processor power info of one in them to set up idle states.
	 * Note that the existing idle handler will be used on platforms that
	 * only support C1.
	 */
	for_each_possible_cpu(cpu) {
		pr = per_cpu(processors, cpu);
		if (!pr)
			continue;

		acpi_processor_cstate_first_run_checks();
		ret = acpi_processor_get_power_info(pr);
		if (!ret) {
			pr->flags.power_setup_done = 1;
			acpi_processor_setup_cpuidle_states(pr);
			break;
		}
	}

	if (ret) {
		pr_debug("No ACPI power information from any CPUs.\n");
		return;
	}

int acpi_processor_power_init(struct acpi_processor *pr)
	ret = cpuidle_register_driver(&acpi_idle_driver);
	if (ret) {
		pr_debug("register %s failed.\n", acpi_idle_driver.name);
		return;
	}
	pr_debug("%s registered with cpuidle.\n", acpi_idle_driver.name);
}

void acpi_processor_unregister_idle_driver(void)
{
	cpuidle_unregister_driver(&acpi_idle_driver);
}

void acpi_processor_power_init(struct acpi_processor *pr)
{
	int retval;
	struct cpuidle_device *dev;

	/*
	 * The code below only works if the current cpuidle driver is the ACPI
	 * idle driver.
	 */
	if (cpuidle_get_driver() != &acpi_idle_driver)
		return;

	if (disabled_by_idle_boot_param())
		return 0;
		return;

	acpi_processor_cstate_first_run_checks();

	if (!acpi_processor_get_power_info(pr))
		pr->flags.power_setup_done = 1;

	/*
	 * Install the idle handler if processor power management is supported.
	 * Note that we use previously set idle handler will be used on
	 * platforms that only support C1.
	 */
	if (pr->flags.power) {
		/* Register acpi_idle_driver if not already registered */
		if (!acpi_processor_registered) {
			acpi_processor_setup_cpuidle_states(pr);
			retval = cpuidle_register_driver(&acpi_idle_driver);
			if (retval)
				return retval;
			pr_debug("%s registered with cpuidle\n",
				 acpi_idle_driver.name);
		}
	if (!pr->flags.power)
		return;

	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
	if (!dev)
			return -ENOMEM;
		return;

	per_cpu(acpi_cpuidle_device, pr->id) = dev;

	acpi_processor_setup_cpuidle_dev(pr, dev);

		/* Register per-cpu cpuidle_device. Cpuidle driver
		 * must already be registered before registering device
	/*
	 * Register a cpuidle device for this CPU.  The cpuidle driver using
	 * this device is expected to be registered.
	 */
		retval = cpuidle_register_device(dev);
		if (retval) {
			if (acpi_processor_registered == 0)
				cpuidle_unregister_driver(&acpi_idle_driver);

	if (cpuidle_register_device(dev)) {
		per_cpu(acpi_cpuidle_device, pr->id) = NULL;
		kfree(dev);
			return retval;
		}
		acpi_processor_registered++;
	}
	return 0;
}

int acpi_processor_power_exit(struct acpi_processor *pr)
void acpi_processor_power_exit(struct acpi_processor *pr)
{
	struct cpuidle_device *dev = per_cpu(acpi_cpuidle_device, pr->id);

	if (disabled_by_idle_boot_param())
		return 0;
		return;

	if (pr->flags.power) {
		cpuidle_unregister_device(dev);
		acpi_processor_registered--;
		if (acpi_processor_registered == 0)
			cpuidle_unregister_driver(&acpi_idle_driver);

		kfree(dev);
	}

	pr->flags.power_setup_done = 0;
	return 0;
}

MODULE_IMPORT_NS("ACPI_PROCESSOR_IDLE");
+6 −28
Original line number Diff line number Diff line
@@ -417,32 +417,15 @@ static inline void acpi_processor_throttling_init(void) {}
#endif	/* CONFIG_ACPI_CPU_FREQ_PSS */

/* in processor_idle.c */
extern struct cpuidle_driver acpi_idle_driver;
#ifdef CONFIG_ACPI_PROCESSOR_IDLE
int acpi_processor_power_init(struct acpi_processor *pr);
int acpi_processor_power_exit(struct acpi_processor *pr);
void acpi_processor_power_init(struct acpi_processor *pr);
void acpi_processor_power_exit(struct acpi_processor *pr);
int acpi_processor_power_state_has_changed(struct acpi_processor *pr);
int acpi_processor_hotplug(struct acpi_processor *pr);
#else
static inline int acpi_processor_power_init(struct acpi_processor *pr)
{
	return -ENODEV;
}

static inline int acpi_processor_power_exit(struct acpi_processor *pr)
{
	return -ENODEV;
}

static inline int acpi_processor_power_state_has_changed(struct acpi_processor *pr)
{
	return -ENODEV;
}

static inline int acpi_processor_hotplug(struct acpi_processor *pr)
{
	return -ENODEV;
}
void acpi_processor_register_idle_driver(void);
void acpi_processor_unregister_idle_driver(void);
int acpi_processor_ffh_lpi_probe(unsigned int cpu);
int acpi_processor_ffh_lpi_enter(struct acpi_lpi_state *lpi);
#endif /* CONFIG_ACPI_PROCESSOR_IDLE */

/* in processor_thermal.c */
@@ -465,11 +448,6 @@ static inline void acpi_thermal_cpufreq_exit(struct cpufreq_policy *policy)
}
#endif	/* CONFIG_CPU_FREQ */

#ifdef CONFIG_ACPI_PROCESSOR_IDLE
extern int acpi_processor_ffh_lpi_probe(unsigned int cpu);
extern int acpi_processor_ffh_lpi_enter(struct acpi_lpi_state *lpi);
#endif

void acpi_processor_init_invariance_cppc(void);

#endif