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

Commit c8107ed9 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull s390 fixes from Martin Schwidefsky:

 - A couple of bug fixes: memory management, perf, cio, dasd and
   scm_blk.

 - A larger change in regard to the CPU topology to improve performance
   for systems running under z/VM or KVM.

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux:
  s390/topology: enable / disable topology dynamically
  s390/topology: alternative topology for topology-less machines
  s390/mm: fix write access check in gup_huge_pmd()
  s390/mm: make pmdp_invalidate() do invalidation only
  s390/cio: recover from bad paths
  s390/scm_blk: consistently use blk_status_t as error type
  s390/dasd: fix race during dasd initialization
  s390/perf: fix bug when creating per-thread event
parents 7a6d0071 51dce386
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -1507,7 +1507,9 @@ static inline pmd_t pmdp_huge_clear_flush(struct vm_area_struct *vma,
static inline void pmdp_invalidate(struct vm_area_struct *vma,
				   unsigned long addr, pmd_t *pmdp)
{
	pmdp_xchg_direct(vma->vm_mm, addr, pmdp, __pmd(_SEGMENT_ENTRY_EMPTY));
	pmd_t pmd = __pmd(pmd_val(*pmdp) | _SEGMENT_ENTRY_INVALID);

	pmdp_xchg_direct(vma->vm_mm, addr, pmdp, pmd);
}

#define __HAVE_ARCH_PMDP_SET_WRPROTECT
+0 −12
Original line number Diff line number Diff line
@@ -404,18 +404,6 @@ static inline void save_vector_registers(void)
#endif
}

static int __init topology_setup(char *str)
{
	bool enabled;
	int rc;

	rc = kstrtobool(str, &enabled);
	if (!rc && !enabled)
		S390_lowcore.machine_flags &= ~MACHINE_FLAG_TOPOLOGY;
	return rc;
}
early_param("topology", topology_setup);

static int __init disable_vector_extension(char *str)
{
	S390_lowcore.machine_flags &= ~MACHINE_FLAG_VX;
+6 −3
Original line number Diff line number Diff line
@@ -823,9 +823,12 @@ static int cpumsf_pmu_event_init(struct perf_event *event)
	}

	/* Check online status of the CPU to which the event is pinned */
	if ((unsigned int)event->cpu >= nr_cpumask_bits ||
	    (event->cpu >= 0 && !cpu_online(event->cpu)))
	if (event->cpu >= 0) {
		if ((unsigned int)event->cpu >= nr_cpumask_bits)
			return -ENODEV;
		if (!cpu_online(event->cpu))
			return -ENODEV;
	}

	/* Force reset of idle/hv excludes regardless of what the
	 * user requested.
+135 −13
Original line number Diff line number Diff line
@@ -8,6 +8,8 @@

#include <linux/workqueue.h>
#include <linux/bootmem.h>
#include <linux/uaccess.h>
#include <linux/sysctl.h>
#include <linux/cpuset.h>
#include <linux/device.h>
#include <linux/export.h>
@@ -29,12 +31,20 @@
#define PTF_VERTICAL	(1UL)
#define PTF_CHECK	(2UL)

enum {
	TOPOLOGY_MODE_HW,
	TOPOLOGY_MODE_SINGLE,
	TOPOLOGY_MODE_PACKAGE,
	TOPOLOGY_MODE_UNINITIALIZED
};

struct mask_info {
	struct mask_info *next;
	unsigned char id;
	cpumask_t mask;
};

static int topology_mode = TOPOLOGY_MODE_UNINITIALIZED;
static void set_topology_timer(void);
static void topology_work_fn(struct work_struct *work);
static struct sysinfo_15_1_x *tl_info;
@@ -59,11 +69,26 @@ static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu)
	cpumask_t mask;

	cpumask_copy(&mask, cpumask_of(cpu));
	if (!MACHINE_HAS_TOPOLOGY)
		return mask;
	for (; info; info = info->next) {
		if (cpumask_test_cpu(cpu, &info->mask))
			return info->mask;
	switch (topology_mode) {
	case TOPOLOGY_MODE_HW:
		while (info) {
			if (cpumask_test_cpu(cpu, &info->mask)) {
				mask = info->mask;
				break;
			}
			info = info->next;
		}
		if (cpumask_empty(&mask))
			cpumask_copy(&mask, cpumask_of(cpu));
		break;
	case TOPOLOGY_MODE_PACKAGE:
		cpumask_copy(&mask, cpu_present_mask);
		break;
	default:
		/* fallthrough */
	case TOPOLOGY_MODE_SINGLE:
		cpumask_copy(&mask, cpumask_of(cpu));
		break;
	}
	return mask;
}
@@ -74,7 +99,7 @@ static cpumask_t cpu_thread_map(unsigned int cpu)
	int i;

	cpumask_copy(&mask, cpumask_of(cpu));
	if (!MACHINE_HAS_TOPOLOGY)
	if (topology_mode != TOPOLOGY_MODE_HW)
		return mask;
	cpu -= cpu % (smp_cpu_mtid + 1);
	for (i = 0; i <= smp_cpu_mtid; i++)
@@ -184,10 +209,8 @@ static void topology_update_polarization_simple(void)
{
	int cpu;

	mutex_lock(&smp_cpu_state_mutex);
	for_each_possible_cpu(cpu)
		smp_cpu_set_polarization(cpu, POLARIZATION_HRZ);
	mutex_unlock(&smp_cpu_state_mutex);
}

static int ptf(unsigned long fc)
@@ -223,7 +246,7 @@ int topology_set_cpu_management(int fc)
static void update_cpu_masks(void)
{
	struct cpu_topology_s390 *topo;
	int cpu;
	int cpu, id;

	for_each_possible_cpu(cpu) {
		topo = &cpu_topology[cpu];
@@ -231,12 +254,13 @@ static void update_cpu_masks(void)
		topo->core_mask = cpu_group_map(&socket_info, cpu);
		topo->book_mask = cpu_group_map(&book_info, cpu);
		topo->drawer_mask = cpu_group_map(&drawer_info, cpu);
		if (!MACHINE_HAS_TOPOLOGY) {
		if (topology_mode != TOPOLOGY_MODE_HW) {
			id = topology_mode == TOPOLOGY_MODE_PACKAGE ? 0 : cpu;
			topo->thread_id = cpu;
			topo->core_id = cpu;
			topo->socket_id = cpu;
			topo->book_id = cpu;
			topo->drawer_id = cpu;
			topo->socket_id = id;
			topo->book_id = id;
			topo->drawer_id = id;
			if (cpu_present(cpu))
				cpumask_set_cpu(cpu, &cpus_with_topology);
		}
@@ -254,6 +278,7 @@ static int __arch_update_cpu_topology(void)
	struct sysinfo_15_1_x *info = tl_info;
	int rc = 0;

	mutex_lock(&smp_cpu_state_mutex);
	cpumask_clear(&cpus_with_topology);
	if (MACHINE_HAS_TOPOLOGY) {
		rc = 1;
@@ -263,6 +288,7 @@ static int __arch_update_cpu_topology(void)
	update_cpu_masks();
	if (!MACHINE_HAS_TOPOLOGY)
		topology_update_polarization_simple();
	mutex_unlock(&smp_cpu_state_mutex);
	return rc;
}

@@ -289,6 +315,11 @@ void topology_schedule_update(void)
	schedule_work(&topology_work);
}

static void topology_flush_work(void)
{
	flush_work(&topology_work);
}

static void topology_timer_fn(unsigned long ignored)
{
	if (ptf(PTF_CHECK))
@@ -459,6 +490,12 @@ void __init topology_init_early(void)
	struct sysinfo_15_1_x *info;

	set_sched_topology(s390_topology);
	if (topology_mode == TOPOLOGY_MODE_UNINITIALIZED) {
		if (MACHINE_HAS_TOPOLOGY)
			topology_mode = TOPOLOGY_MODE_HW;
		else
			topology_mode = TOPOLOGY_MODE_SINGLE;
	}
	if (!MACHINE_HAS_TOPOLOGY)
		goto out;
	tl_info = memblock_virt_alloc(PAGE_SIZE, PAGE_SIZE);
@@ -474,12 +511,97 @@ void __init topology_init_early(void)
	__arch_update_cpu_topology();
}

static inline int topology_get_mode(int enabled)
{
	if (!enabled)
		return TOPOLOGY_MODE_SINGLE;
	return MACHINE_HAS_TOPOLOGY ? TOPOLOGY_MODE_HW : TOPOLOGY_MODE_PACKAGE;
}

static inline int topology_is_enabled(void)
{
	return topology_mode != TOPOLOGY_MODE_SINGLE;
}

static int __init topology_setup(char *str)
{
	bool enabled;
	int rc;

	rc = kstrtobool(str, &enabled);
	if (rc)
		return rc;
	topology_mode = topology_get_mode(enabled);
	return 0;
}
early_param("topology", topology_setup);

static int topology_ctl_handler(struct ctl_table *ctl, int write,
				void __user *buffer, size_t *lenp, loff_t *ppos)
{
	unsigned int len;
	int new_mode;
	char buf[2];

	if (!*lenp || *ppos) {
		*lenp = 0;
		return 0;
	}
	if (!write) {
		strncpy(buf, topology_is_enabled() ? "1\n" : "0\n",
			ARRAY_SIZE(buf));
		len = strnlen(buf, ARRAY_SIZE(buf));
		if (len > *lenp)
			len = *lenp;
		if (copy_to_user(buffer, buf, len))
			return -EFAULT;
		goto out;
	}
	len = *lenp;
	if (copy_from_user(buf, buffer, len > sizeof(buf) ? sizeof(buf) : len))
		return -EFAULT;
	if (buf[0] != '0' && buf[0] != '1')
		return -EINVAL;
	mutex_lock(&smp_cpu_state_mutex);
	new_mode = topology_get_mode(buf[0] == '1');
	if (topology_mode != new_mode) {
		topology_mode = new_mode;
		topology_schedule_update();
	}
	mutex_unlock(&smp_cpu_state_mutex);
	topology_flush_work();
out:
	*lenp = len;
	*ppos += len;
	return 0;
}

static struct ctl_table topology_ctl_table[] = {
	{
		.procname	= "topology",
		.mode		= 0644,
		.proc_handler	= topology_ctl_handler,
	},
	{ },
};

static struct ctl_table topology_dir_table[] = {
	{
		.procname	= "s390",
		.maxlen		= 0,
		.mode		= 0555,
		.child		= topology_ctl_table,
	},
	{ },
};

static int __init topology_init(void)
{
	if (MACHINE_HAS_TOPOLOGY)
		set_topology_timer();
	else
		topology_update_polarization_simple();
	register_sysctl_table(topology_dir_table);
	return device_create_file(cpu_subsys.dev_root, &dev_attr_dispatching);
}
device_initcall(topology_init);
+3 −4
Original line number Diff line number Diff line
@@ -56,13 +56,12 @@ static inline int gup_pte_range(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
static inline int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
		unsigned long end, int write, struct page **pages, int *nr)
{
	unsigned long mask, result;
	struct page *head, *page;
	unsigned long mask;
	int refs;

	result = write ? 0 : _SEGMENT_ENTRY_PROTECT;
	mask = result | _SEGMENT_ENTRY_INVALID;
	if ((pmd_val(pmd) & mask) != result)
	mask = (write ? _SEGMENT_ENTRY_PROTECT : 0) | _SEGMENT_ENTRY_INVALID;
	if ((pmd_val(pmd) & mask) != 0)
		return 0;
	VM_BUG_ON(!pfn_valid(pmd_val(pmd) >> PAGE_SHIFT));

Loading