Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 13b80bad authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "soc: qcom: mem-offline: BUG_ON when hw online request fails"

parents 2b85740d 98c94f32
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -24,6 +24,16 @@ config QCOM_MEM_OFFLINE
	  helps reduce power consumption during idle mode of the system.
	  If unsure, say N

config BUG_ON_HW_MEM_ONLINE_FAIL
	bool "Trigger a BUG when HW memory online fails"
	depends on QCOM_MEM_OFFLINE
	help
	  Select this option if kernel should BUG when the hardware
	  onlining of memory hotplug blocks fails. This helps to catch
	  online failures much quicker and avoids the later side effects
	  of such memory online failures.
	  If unsure, say N

config QCOM_GENI_SE
	tristate "QCOM GENI Serial Engine Driver"
	depends on ARCH_QCOM || COMPILE_TEST
+74 −16
Original line number Diff line number Diff line
@@ -45,6 +45,8 @@ enum memory_states {
	MAX_STATE,
};

static enum memory_states *mem_hw_state;

static struct mem_offline_mailbox {
	struct mbox_client cl;
	struct mbox_chan *mbox;
@@ -134,6 +136,32 @@ static int aop_send_msg(unsigned long addr, bool online)
	return (mbox_send_message(mailbox.mbox, &pkt) < 0);
}

static int mem_change_refresh_state(struct memory_notify *mn,
				    enum memory_states state)
{
	int start = SECTION_ALIGN_DOWN(mn->start_pfn);
	unsigned long sec_nr = pfn_to_section_nr(start);
	bool online = (state == MEMORY_ONLINE) ? true : false;
	unsigned long idx = (sec_nr - start_section_nr) / sections_per_block;
	int ret;

	if (mem_hw_state[idx] == state) {
		/* we shouldn't be getting this request */
		pr_warn("mem-offline: hardware state of mem%d block already in %s state. Ignoring refresh state change request\n",
				sec_nr, online ? "online" : "offline");
		return 0;
	}
	ret = aop_send_msg(__pfn_to_phys(start), online);
	if (ret) {
		if (state == MEMORY_ONLINE)
			BUG_ON(IS_ENABLED(CONFIG_BUG_ON_HW_MEM_ONLINE_FAIL));
		return -EINVAL;
	}
	mem_hw_state[idx] = state;

	return 0;
}

static int mem_event_callback(struct notifier_block *self,
				unsigned long action, void *arg)
{
@@ -173,9 +201,11 @@ static int mem_event_callback(struct notifier_block *self,
			   idx) / sections_per_block].fail_count;
		cur = ktime_get();

		if (aop_send_msg(__pfn_to_phys(start), true))
		if (mem_change_refresh_state(mn, MEMORY_ONLINE)) {
			pr_err("PASR: AOP online request addr:0x%llx failed\n",
			       __pfn_to_phys(start));
			return NOTIFY_BAD;
		}
		if (!debug_pagealloc_enabled()) {
			/* Create kernel page-tables */
			create_pgtable_mapping(start_addr, end_addr);
@@ -201,9 +231,14 @@ static int mem_event_callback(struct notifier_block *self,
			/* Clear kernel page-tables */
			clear_pgtable_mapping(start_addr, end_addr);
		}
		if (aop_send_msg(__pfn_to_phys(start), false))
		if (mem_change_refresh_state(mn, MEMORY_OFFLINE)) {
			pr_err("PASR: AOP offline request addr:0x%llx failed\n",
			       __pfn_to_phys(start));
			/*
			 * Notifying that something went bad at this stage won't
			 * help since this is the last stage of memory hotplug.
			 */
		}

		delay = ktime_ms_delta(ktime_get(), cur);
		record_stat(sec_nr, delay, MEMORY_OFFLINE);
@@ -214,8 +249,8 @@ static int mem_event_callback(struct notifier_block *self,
	case MEM_CANCEL_ONLINE:
		pr_info("mem-offline: MEM_CANCEL_ONLINE: start = 0x%llx end = 0x%llx\n",
				start_addr, end_addr);
		if (aop_send_msg(__pfn_to_phys(start), false))
			pr_err("PASR: AOP online request addr:0x%llx failed\n",
		if (mem_change_refresh_state(mn, MEMORY_OFFLINE))
			pr_err("PASR: AOP offline request addr:0x%llx failed\n",
			       __pfn_to_phys(start));
		break;
	default:
@@ -348,9 +383,6 @@ static struct attribute_group mem_attr_group = {

static int mem_sysfs_init(void)
{
	unsigned int total_blks = (end_section_nr - start_section_nr + 1) /
							sections_per_block;

	if (start_section_nr == end_section_nr)
		return -EINVAL;

@@ -361,11 +393,6 @@ static int mem_sysfs_init(void)
	if (sysfs_create_group(kobj, &mem_attr_group))
		kobject_put(kobj);

	mem_info = kzalloc(sizeof(*mem_info) * total_blks * MAX_STATE,
								GFP_KERNEL);
	if (!mem_info)
		return -ENOMEM;

	return 0;
}

@@ -413,7 +440,8 @@ static struct notifier_block hotplug_memory_callback_nb = {

static int mem_offline_driver_probe(struct platform_device *pdev)
{
	int ret;
	unsigned int total_blks;
	int ret, i;

	ret = mem_parse_dt(pdev);
	if (ret)
@@ -426,16 +454,46 @@ static int mem_offline_driver_probe(struct platform_device *pdev)
	if (ret > 0)
		pr_err("mem-offline: !!ERROR!! Auto onlining some memory blocks failed. System could run with less RAM\n");

	if (mem_sysfs_init())
		return -ENODEV;
	total_blks = (end_section_nr - start_section_nr + 1) /
			sections_per_block;
	mem_info = kcalloc(total_blks * MAX_STATE, sizeof(*mem_info),
			   GFP_KERNEL);
	if (!mem_info)
		return -ENOMEM;

	mem_hw_state = kcalloc(total_blks, sizeof(*mem_hw_state), GFP_KERNEL);
	if (!mem_hw_state) {
		ret = -ENOMEM;
		goto err_free_mem_info;
	}

	/* we assume that hardware state of mem blocks are online after boot */
	for (i = 0; i < total_blks; i++)
		mem_hw_state[i] = MEMORY_ONLINE;

	if (mem_sysfs_init()) {
		ret = -ENODEV;
		goto err_free_mem_hw_state;
	}

	if (register_hotmemory_notifier(&hotplug_memory_callback_nb)) {
		pr_err("mem-offline: Registering memory hotplug notifier failed\n");
		return -ENODEV;
		ret = -ENODEV;
		goto err_sysfs_remove_group;
	}
	pr_info("mem-offline: Added memory blocks ranging from mem%lu - mem%lu\n",
			start_section_nr, end_section_nr);

	return 0;

err_sysfs_remove_group:
	sysfs_remove_group(kobj, &mem_attr_group);
	kobject_put(kobj);
err_free_mem_hw_state:
	kfree(mem_hw_state);
err_free_mem_info:
	kfree(mem_info);
	return ret;
}

static const struct of_device_id mem_offline_match_table[] = {