Commit cbadb98b authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull s390 fixes from Alexander Gordeev:

 - Fix PAI NNPA mismatch between counting and recording, where sampling
   reports twice the value

 - Fix loss of PAI counter increments during recording on systems with
   many CPUs under heavy load, while counting is not affected

 - On some supported machines, CHSC cannot access memory outside the DMA
   zone, causing CHSC command failures. Restore GFP_DMA flag when
   allocating memory for CHSC control blocks

 - Align the numbering scheme for higher-level topology structures like
   socket, book, drawer with other hardware identifiers e.g. in sysfs,
   procfs and tools like lscpu

* tag 's390-7.1-3' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux:
  s390/topology: Use zero-based numbering for containing entities
  s390/cio: Restore GFP_DMA for CHSC allocation
  s390/pai: Fix missing PAI counter increments under heavy load
  s390/pai: Disable duplicate read of kernel PAI counter value
parents 46de4087 540f4a4f
Loading
Loading
Loading
Loading
+21 −10
Original line number Diff line number Diff line
@@ -186,6 +186,13 @@ static u64 pai_getctr(unsigned long *page, int nr, unsigned long offset)
	return page[nr];
}

static void pai_setctr(unsigned long *page, int nr, unsigned long offset, u64 v)
{
	if (offset)
		nr += offset / sizeof(*page);
	page[nr] = v;
}

/* Read the counter values. Return value from location in CMP. For base
 * event xxx_ALL sum up all events. Returns counter value.
 */
@@ -551,6 +558,8 @@ static void paicrypt_del(struct perf_event *event, int flags)
/* Create raw data and save it in buffer. Calculate the delta for each
 * counter between this invocation and the last invocation.
 * Returns number of bytes copied.
 * After reading from PAI counter page, save the read value to the old
 * page to calculate PAI counter deltas.
 * Saves only entries with positive counter difference of the form
 * 2 bytes: Number of counter
 * 8 bytes: Value of counter
@@ -562,16 +571,22 @@ static size_t pai_copy(struct pai_userdata *userdata, unsigned long *page,
	int i, outidx = 0;

	for (i = 1; i <= pp->num_avail; i++) {
		u64 val = 0, val_old = 0;
		u64 val = 0, val_old = 0, val_k = 0, val_old_k = 0;

		if (!exclude_kernel) {
			val += pai_getctr(page, i, pp->kernel_offset);
			val_old += pai_getctr(page_old, i, pp->kernel_offset);
			val_k = pai_getctr(page, i, pp->kernel_offset);
			val_old_k = pai_getctr(page_old, i, pp->kernel_offset);
			if (val_k != val_old_k)
				pai_setctr(page_old, i, pp->kernel_offset, val_k);
		}
		if (!exclude_user) {
			val += pai_getctr(page, i, 0);
			val_old += pai_getctr(page_old, i, 0);
			val = pai_getctr(page, i, 0);
			val_old = pai_getctr(page_old, i, 0);
			if (val != val_old)
				pai_setctr(page_old, i, 0, val);
		}
		val += val_k;
		val_old += val_old_k;
		if (val >= val_old)
			val -= val_old;
		else
@@ -602,8 +617,6 @@ static size_t pai_copy(struct pai_userdata *userdata, unsigned long *page,
static int pai_push_sample(size_t rawsize, struct pai_map *cpump,
			   struct perf_event *event)
{
	int idx = PAI_PMU_IDX(event);
	struct pai_pmu *pp = &pai_pmu[idx];
	struct perf_sample_data data;
	struct perf_raw_record raw;
	struct pt_regs regs;
@@ -634,8 +647,6 @@ static int pai_push_sample(size_t rawsize, struct pai_map *cpump,

	overflow = perf_event_overflow(event, &data, &regs);
	perf_event_update_userpage(event);
	/* Save crypto counter lowcore page after reading event data. */
	memcpy((void *)PAI_SAVE_AREA(event), cpump->area, pp->area_size);
	return overflow;
}

@@ -651,7 +662,7 @@ static void pai_have_sample(struct perf_event *event, struct pai_map *cpump)
	rawsize = pai_copy(cpump->save, cpump->area, pp,
			   (unsigned long *)PAI_SAVE_AREA(event),
			   event->attr.exclude_user,
			   event->attr.exclude_kernel);
			   !pp->kernel_offset ? true : event->attr.exclude_kernel);
	if (rawsize)			/* No incremented counters */
		pai_push_sample(rawsize, cpump, event);
}
+7 −3
Original line number Diff line number Diff line
@@ -192,17 +192,21 @@ static void tl_to_masks(struct sysinfo_15_1_x *info)
	end = (union topology_entry *)((unsigned long)info + info->length);
	while (tle < end) {
		switch (tle->nl) {
		/*
		 * Adjust drawer_id, book_id, and socked_id so they match the
		 * numbering scheme of e.g. the hardware management console.
		 */
		case 3:
			drawer = drawer->next;
			drawer->id = tle->container.id;
			drawer->id = tle->container.id - 1;
			break;
		case 2:
			book = book->next;
			book->id = tle->container.id;
			book->id = tle->container.id - 1;
			break;
		case 1:
			socket = socket->next;
			socket->id = tle->container.id;
			socket->id = tle->container.id - 1;
			break;
		case 0:
			add_cpus_to_mask(&tle->cpu, drawer, book, socket);
+2 −2
Original line number Diff line number Diff line
@@ -1142,8 +1142,8 @@ int __init chsc_init(void)
{
	int ret;

	sei_page = (void *)get_zeroed_page(GFP_KERNEL);
	chsc_page = (void *)get_zeroed_page(GFP_KERNEL);
	sei_page = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
	chsc_page = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
	if (!sei_page || !chsc_page) {
		ret = -ENOMEM;
		goto out_err;
+10 −10
Original line number Diff line number Diff line
@@ -292,7 +292,7 @@ static int chsc_ioctl_start(void __user *user_area)
	if (!css_general_characteristics.dynio)
		/* It makes no sense to try. */
		return -EOPNOTSUPP;
	chsc_area = (void *)get_zeroed_page(GFP_KERNEL);
	chsc_area = (void *)get_zeroed_page(GFP_DMA | GFP_KERNEL);
	if (!chsc_area)
		return -ENOMEM;
	request = kzalloc_obj(*request);
@@ -340,7 +340,7 @@ static int chsc_ioctl_on_close_set(void __user *user_area)
		ret = -ENOMEM;
		goto out_unlock;
	}
	on_close_chsc_area = (void *)get_zeroed_page(GFP_KERNEL);
	on_close_chsc_area = (void *)get_zeroed_page(GFP_DMA | GFP_KERNEL);
	if (!on_close_chsc_area) {
		ret = -ENOMEM;
		goto out_free_request;
@@ -392,7 +392,7 @@ static int chsc_ioctl_start_sync(void __user *user_area)
	struct chsc_sync_area *chsc_area;
	int ret, ccode;

	chsc_area = (void *)get_zeroed_page(GFP_KERNEL);
	chsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
	if (!chsc_area)
		return -ENOMEM;
	if (copy_from_user(chsc_area, user_area, PAGE_SIZE)) {
@@ -438,7 +438,7 @@ static int chsc_ioctl_info_channel_path(void __user *user_cd)
		u8 data[PAGE_SIZE - 20];
	} __attribute__ ((packed)) *scpcd_area;

	scpcd_area = (void *)get_zeroed_page(GFP_KERNEL);
	scpcd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
	if (!scpcd_area)
		return -ENOMEM;
	cd = kzalloc_obj(*cd);
@@ -500,7 +500,7 @@ static int chsc_ioctl_info_cu(void __user *user_cd)
		u8 data[PAGE_SIZE - 20];
	} __attribute__ ((packed)) *scucd_area;

	scucd_area = (void *)get_zeroed_page(GFP_KERNEL);
	scucd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
	if (!scucd_area)
		return -ENOMEM;
	cd = kzalloc_obj(*cd);
@@ -563,7 +563,7 @@ static int chsc_ioctl_info_sch_cu(void __user *user_cud)
		u8 data[PAGE_SIZE - 20];
	} __attribute__ ((packed)) *sscud_area;

	sscud_area = (void *)get_zeroed_page(GFP_KERNEL);
	sscud_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
	if (!sscud_area)
		return -ENOMEM;
	cud = kzalloc_obj(*cud);
@@ -625,7 +625,7 @@ static int chsc_ioctl_conf_info(void __user *user_ci)
		u8 data[PAGE_SIZE - 20];
	} __attribute__ ((packed)) *sci_area;

	sci_area = (void *)get_zeroed_page(GFP_KERNEL);
	sci_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
	if (!sci_area)
		return -ENOMEM;
	ci = kzalloc_obj(*ci);
@@ -696,7 +696,7 @@ static int chsc_ioctl_conf_comp_list(void __user *user_ccl)
		u32 res;
	} __attribute__ ((packed)) *cssids_parm;

	sccl_area = (void *)get_zeroed_page(GFP_KERNEL);
	sccl_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
	if (!sccl_area)
		return -ENOMEM;
	ccl = kzalloc_obj(*ccl);
@@ -756,7 +756,7 @@ static int chsc_ioctl_chpd(void __user *user_chpd)
	int ret;

	chpd = kzalloc_obj(*chpd);
	scpd_area = (void *)get_zeroed_page(GFP_KERNEL);
	scpd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
	if (!scpd_area || !chpd) {
		ret = -ENOMEM;
		goto out_free;
@@ -796,7 +796,7 @@ static int chsc_ioctl_dcal(void __user *user_dcal)
		u8 data[PAGE_SIZE - 36];
	} __attribute__ ((packed)) *sdcal_area;

	sdcal_area = (void *)get_zeroed_page(GFP_KERNEL);
	sdcal_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
	if (!sdcal_area)
		return -ENOMEM;
	dcal = kzalloc_obj(*dcal);
+1 −1
Original line number Diff line number Diff line
@@ -229,7 +229,7 @@ int scm_update_information(void)
	size_t num;
	int ret;

	scm_info = (void *)__get_free_page(GFP_KERNEL);
	scm_info = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
	if (!scm_info)
		return -ENOMEM;