Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH RESEND] irqchip: gicv3-its: Don't assume GICv3 hardware supports 16bit INTID
From: Shanker Donthineni @ 2017-04-30 14:54 UTC (permalink / raw)
  To: linux-arm-kernel

The current ITS driver is assuming every ITS hardware implementation
supports minimum of 16bit INTID. But this is not true, as per GICv3
specification, INTID field is IMPLEMENTATION DEFINED in the range of
14-24 bits. We might see an unpredictable system behavior on systems
where hardware support less than 16bits and software tries to use
64K LPI interrupts.

On Qualcomm Datacenter Technologies QDF2400 platform, boot log shows
confusing information about number of LPI chunks as shown below. The
QDF2400 ITS hardware supports 24bit INTID.

This patch allocates the memory resources for PEND/PROP tables based
on discoverable value which is specified in GITS_TYPER.IDbits. Also
taking this opportunity to increase number of LPI/MSI(x) to 128K if
the hardware is capable, and show log message that reflects the
correct number of LPI chunks.

ITS at 0xff7efe0000: allocated 524288 Devices @3c0400000 (indirect, esz 8, psz 64K, shr 1)
ITS at 0xff7efe0000: allocated 8192 Interrupt Collections @3c0130000 (flat, esz 8, psz 64K, shr 1)
ITS at 0xff7efe0000: allocated 8192 Virtual CPUs @3c0140000 (flat, esz 8, psz 64K, shr 1)
ITS: Allocated 524032 chunks for LPIs
PCI/MSI: ITS at 0xff7efe0000 domain created
Platform MSI: ITS at 0xff7efe0000 domain created

Signed-off-by: Shanker Donthineni <shankerd@codeaurora.org>
---
 drivers/irqchip/irq-gic-v3-its.c | 34 ++++++++++++++++------------------
 1 file changed, 16 insertions(+), 18 deletions(-)

diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 72e56f03..6c24e3c 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -687,9 +687,11 @@ static void its_irq_compose_msi_msg(struct irq_data *d, struct msi_msg *msg)
  */
 #define IRQS_PER_CHUNK_SHIFT	5
 #define IRQS_PER_CHUNK		(1 << IRQS_PER_CHUNK_SHIFT)
+#define ITS_MAX_LPI_NRBITS	(17) /* 128K LPIs */
 
 static unsigned long *lpi_bitmap;
 static u32 lpi_chunks;
+static u32 lpi_nrbits;
 static DEFINE_SPINLOCK(lpi_lock);
 
 static int its_lpi_to_chunk(int lpi)
@@ -785,26 +787,19 @@ static void its_lpi_free(struct event_lpi_map *map)
 }
 
 /*
- * We allocate 64kB for PROPBASE. That gives us@most 64K LPIs to
+ * We allocate memory for PROPBASE to cover 2 ^ lpi_nrbits LPIs to
  * deal with (one configuration byte per interrupt). PENDBASE has to
  * be 64kB aligned (one bit per LPI, plus 8192 bits for SPI/PPI/SGI).
  */
-#define LPI_PROPBASE_SZ		SZ_64K
-#define LPI_PENDBASE_SZ		(LPI_PROPBASE_SZ / 8 + SZ_1K)
-
-/*
- * This is how many bits of ID we need, including the useless ones.
- */
-#define LPI_NRBITS		ilog2(LPI_PROPBASE_SZ + SZ_8K)
 
 #define LPI_PROP_DEFAULT_PRIO	0xa0
 
 static int __init its_alloc_lpi_tables(void)
 {
+	u32 size = ALIGN(BIT(lpi_nrbits), SZ_64K);
 	phys_addr_t paddr;
 
-	gic_rdists->prop_page = alloc_pages(GFP_NOWAIT,
-					   get_order(LPI_PROPBASE_SZ));
+	gic_rdists->prop_page = alloc_pages(GFP_NOWAIT, get_order(size));
 	if (!gic_rdists->prop_page) {
 		pr_err("Failed to allocate PROPBASE\n");
 		return -ENOMEM;
@@ -816,10 +811,10 @@ static int __init its_alloc_lpi_tables(void)
 	/* Priority 0xa0, Group-1, disabled */
 	memset(page_address(gic_rdists->prop_page),
 	       LPI_PROP_DEFAULT_PRIO | LPI_PROP_GROUP1,
-	       LPI_PROPBASE_SZ);
+	       size);
 
 	/* Make sure the GIC will observe the written configuration */
-	gic_flush_dcache_to_poc(page_address(gic_rdists->prop_page), LPI_PROPBASE_SZ);
+	gic_flush_dcache_to_poc(page_address(gic_rdists->prop_page), size);
 
 	return 0;
 }
@@ -1091,12 +1086,14 @@ static void its_cpu_init_lpis(void)
 	pend_page = gic_data_rdist()->pend_page;
 	if (!pend_page) {
 		phys_addr_t paddr;
+		u32 size;
 		/*
-		 * The pending pages have to be at least 64kB aligned,
-		 * hence the 'max(LPI_PENDBASE_SZ, SZ_64K)' below.
+		 * The pending pages have to be at least 64kB aligned
+		 * hence the 'ALIGN(BIT(lpi_nrbits)/8, SZ_64K)' below.
 		 */
+		size = ALIGN(BIT(lpi_nrbits)/8, SZ_64K);
 		pend_page = alloc_pages(GFP_NOWAIT | __GFP_ZERO,
-					get_order(max(LPI_PENDBASE_SZ, SZ_64K)));
+					get_order(size));
 		if (!pend_page) {
 			pr_err("Failed to allocate PENDBASE for CPU%d\n",
 			       smp_processor_id());
@@ -1104,7 +1101,7 @@ static void its_cpu_init_lpis(void)
 		}
 
 		/* Make sure the GIC will observe the zero-ed page */
-		gic_flush_dcache_to_poc(page_address(pend_page), LPI_PENDBASE_SZ);
+		gic_flush_dcache_to_poc(page_address(pend_page), size);
 
 		paddr = page_to_phys(pend_page);
 		pr_info("CPU%d: using LPI pending table @%pa\n",
@@ -1126,7 +1123,7 @@ static void its_cpu_init_lpis(void)
 	val = (page_to_phys(gic_rdists->prop_page) |
 	       GICR_PROPBASER_InnerShareable |
 	       GICR_PROPBASER_RaWaWb |
-	       ((LPI_NRBITS - 1) & GICR_PROPBASER_IDBITS_MASK));
+	       ((lpi_nrbits - 1) & GICR_PROPBASER_IDBITS_MASK));
 
 	gicr_write_propbaser(val, rbase + GICR_PROPBASER);
 	tmp = gicr_read_propbaser(rbase + GICR_PROPBASER);
@@ -1897,9 +1894,10 @@ int __init its_init(struct fwnode_handle *handle, struct rdists *rdists,
 		return -ENXIO;
 	}
 
+	lpi_nrbits = min_t(u32, rdists->id_bits, ITS_MAX_LPI_NRBITS);
 	gic_rdists = rdists;
 	its_alloc_lpi_tables();
-	its_lpi_init(rdists->id_bits);
+	its_lpi_init(lpi_nrbits);
 
 	return 0;
 }
-- 
Qualcomm Datacenter Technologies, Inc. on behalf of the Qualcomm Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.

^ permalink raw reply related

* [PATCH v4] irqchip/gicv3-its: Avoid memory over allocation for ITEs
From: Shanker Donthineni @ 2017-04-30 14:36 UTC (permalink / raw)
  To: linux-arm-kernel

We are always allocating extra 255Bytes of memory to handle ITE
physical address alignment requirement. The kmalloc() satisfies
the ITE alignment since the ITS driver is requesting a minimum
size of ITS_ITT_ALIGN bytes.

Let's try to allocate the exact amount of memory that is required
for ITEs to avoid wastage.

Signed-off-by: Shanker Donthineni <shankerd@codeaurora.org>
---
Changes:
v2: removed 'Change-Id: Ia8084189833f2081ff13c392deb5070c46a64038' from commit.
v3: changed from IITE to ITE.
v3: removed fallback since kmalloc() guarantees the right alignment.

 drivers/irqchip/irq-gic-v3-its.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 45ea1933..72e56f03 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -261,7 +261,6 @@ static struct its_collection *its_build_mapd_cmd(struct its_cmd_block *cmd,
 	u8 size = ilog2(desc->its_mapd_cmd.dev->nr_ites);
 
 	itt_addr = virt_to_phys(desc->its_mapd_cmd.dev->itt);
-	itt_addr = ALIGN(itt_addr, ITS_ITT_ALIGN);
 
 	its_encode_cmd(cmd, GITS_CMD_MAPD);
 	its_encode_devid(cmd, desc->its_mapd_cmd.dev->device_id);
@@ -1329,13 +1328,14 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
 	 */
 	nr_ites = max(2UL, roundup_pow_of_two(nvecs));
 	sz = nr_ites * its->ite_size;
-	sz = max(sz, ITS_ITT_ALIGN) + ITS_ITT_ALIGN - 1;
+	sz = max(sz, ITS_ITT_ALIGN);
 	itt = kzalloc(sz, GFP_KERNEL);
 	lpi_map = its_lpi_alloc_chunks(nvecs, &lpi_base, &nr_lpis);
 	if (lpi_map)
 		col_map = kzalloc(sizeof(*col_map) * nr_lpis, GFP_KERNEL);
 
-	if (!dev || !itt || !lpi_map || !col_map) {
+	if (!dev || !itt || !lpi_map || !col_map ||
+	    !IS_ALIGNED(virt_to_phys(itt), ITS_ITT_ALIGN)) {
 		kfree(dev);
 		kfree(itt);
 		kfree(lpi_map);
-- 
Qualcomm Datacenter Technologies, Inc. on behalf of the Qualcomm Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.

^ permalink raw reply related

* [PATCH v3 3/3] arm/arm64: signal SIBGUS and inject SEA Error
From: Dongjiu Geng @ 2017-04-30  5:37 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1493530677-4919-1-git-send-email-gengdongjiu@huawei.com>

when happen SEA, deliver signal bus and handle the ioctl that
inject SEA abort to guest, so that guest can handle the SEA error.

Signed-off-by: Dongjiu Geng <gengdongjiu@huawei.com>
---
 arch/arm/include/asm/kvm_host.h   |  1 +
 arch/arm/kvm/arm.c                |  3 +++
 arch/arm/kvm/guest.c              |  5 +++++
 arch/arm/kvm/mmu.c                | 37 +++++++++++++++++++++++++++++++++++++
 arch/arm64/include/asm/kvm_host.h |  1 +
 arch/arm64/kvm/guest.c            |  7 +++++++
 include/uapi/linux/kvm.h          |  1 +
 7 files changed, 55 insertions(+)

diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index 31ee468..ad19f80 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -244,6 +244,7 @@ int kvm_arm_coproc_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *);
 
 int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
 		int exception_index);
+int kvm_vcpu_ioctl_sea(struct kvm_vcpu *vcpu);
 
 static inline void __cpu_init_hyp_mode(phys_addr_t pgd_ptr,
 				       unsigned long hyp_stack_ptr,
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index 96dba7c..907ba4a 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -972,6 +972,9 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
 			return -E2BIG;
 		return kvm_arm_copy_reg_indices(vcpu, user_list->reg);
 	}
+	case KVM_ARM_SEA: {
+		return kvm_vcpu_ioctl_sea(vcpu);
+	}
 	case KVM_SET_DEVICE_ATTR: {
 		if (copy_from_user(&attr, argp, sizeof(attr)))
 			return -EFAULT;
diff --git a/arch/arm/kvm/guest.c b/arch/arm/kvm/guest.c
index fa6182a..48e5b53 100644
--- a/arch/arm/kvm/guest.c
+++ b/arch/arm/kvm/guest.c
@@ -247,6 +247,11 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
 {
 	return -EINVAL;
 }
+int kvm_vcpu_ioctl_sea(struct kvm_vcpu *vcpu)
+{
+	return 0;
+
+}
 
 int __attribute_const__ kvm_target_cpu(void)
 {
diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
index 105b6ab..a96594f 100644
--- a/arch/arm/kvm/mmu.c
+++ b/arch/arm/kvm/mmu.c
@@ -20,8 +20,10 @@
 #include <linux/kvm_host.h>
 #include <linux/io.h>
 #include <linux/hugetlb.h>
+#include <linux/sched/signal.h>
 #include <trace/events/kvm.h>
 #include <asm/pgalloc.h>
+#include <asm/siginfo.h>
 #include <asm/cacheflush.h>
 #include <asm/kvm_arm.h>
 #include <asm/kvm_mmu.h>
@@ -1238,6 +1240,36 @@ static void coherent_cache_guest_page(struct kvm_vcpu *vcpu, kvm_pfn_t pfn,
 	__coherent_cache_guest_page(vcpu, pfn, size);
 }
 
+static void kvm_send_signal(unsigned long address, bool hugetlb, bool hwpoison)
+{
+	siginfo_t info;
+
+	info.si_signo   = SIGBUS;
+	info.si_errno   = 0;
+	if (hwpoison)
+		info.si_code    = BUS_MCEERR_AR;
+	else
+		info.si_code    = 0;
+
+	info.si_addr    = (void __user *)address;
+	if (hugetlb)
+		info.si_addr_lsb = PMD_SHIFT;
+	else
+		info.si_addr_lsb = PAGE_SHIFT;
+
+	send_sig_info(SIGBUS, &info, current);
+}
+
+static void kvm_handle_bad_page(unsigned long address,
+					bool hugetlb, bool hwpoison)
+{
+	/* handle both hwpoison and other synchronous external Abort */
+	if (hwpoison)
+		kvm_send_signal(address, hugetlb, true);
+	else
+		kvm_send_signal(address, hugetlb, false);
+}
+
 static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
 			  struct kvm_memory_slot *memslot, unsigned long hva,
 			  unsigned long fault_status)
@@ -1307,6 +1339,11 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
 	smp_rmb();
 
 	pfn = gfn_to_pfn_prot(kvm, gfn, write_fault, &writable);
+	if (pfn == KVM_PFN_ERR_HWPOISON) {
+		kvm_handle_bad_page(hva, hugetlb, true);
+		return 0;
+	}
+
 	if (is_error_noslot_pfn(pfn))
 		return -EFAULT;
 
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 84ed239..4a80c3b 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -386,6 +386,7 @@ int kvm_arm_vcpu_arch_get_attr(struct kvm_vcpu *vcpu,
 			       struct kvm_device_attr *attr);
 int kvm_arm_vcpu_arch_has_attr(struct kvm_vcpu *vcpu,
 			       struct kvm_device_attr *attr);
+int kvm_vcpu_ioctl_sea(struct kvm_vcpu *vcpu);
 
 static inline void __cpu_init_stage2(void)
 {
diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index b37446a..780e3c4 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -277,6 +277,13 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
 	return -EINVAL;
 }
 
+int kvm_vcpu_ioctl_sea(struct kvm_vcpu *vcpu)
+{
+	kvm_inject_dabt(vcpu, kvm_vcpu_get_hfar(vcpu));
+
+	return 0;
+}
+
 int __attribute_const__ kvm_target_cpu(void)
 {
 	unsigned long implementor = read_cpuid_implementor();
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index bb02909..1d2e2e7 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -1306,6 +1306,7 @@ struct kvm_s390_ucas_mapping {
 #define KVM_S390_GET_IRQ_STATE	  _IOW(KVMIO, 0xb6, struct kvm_s390_irq_state)
 /* Available with KVM_CAP_X86_SMM */
 #define KVM_SMI                   _IO(KVMIO,   0xb7)
+#define KVM_ARM_SEA               _IO(KVMIO,   0xb8)
 
 #define KVM_DEV_ASSIGN_ENABLE_IOMMU	(1 << 0)
 #define KVM_DEV_ASSIGN_PCI_2_3		(1 << 1)
-- 
2.10.1

^ permalink raw reply related

* [PATCH v3 2/3] arm64: kvm: inject SError with virtual syndrome
From: Dongjiu Geng @ 2017-04-30  5:37 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1493530677-4919-1-git-send-email-gengdongjiu@huawei.com>

when SError happen, kvm notifies kvmtool to generate GHES table
to record the error, then kvmtools inject the SError with specified
virtual syndrome. when switch to guest, a virtual SError will happen with
this specified syndrome.

Signed-off-by: Dongjiu Geng <gengdongjiu@huawei.com>
---
 arch/arm64/include/asm/esr.h         |  2 ++
 arch/arm64/include/asm/kvm_emulate.h | 10 ++++++++++
 arch/arm64/include/asm/kvm_host.h    |  1 +
 arch/arm64/include/asm/sysreg.h      |  3 +++
 arch/arm64/kvm/handle_exit.c         | 25 +++++++++++++++++++------
 arch/arm64/kvm/hyp/switch.c          | 15 ++++++++++++++-
 include/uapi/linux/kvm.h             |  5 +++++
 7 files changed, 54 insertions(+), 7 deletions(-)

diff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h
index 22f9c90..d009c99 100644
--- a/arch/arm64/include/asm/esr.h
+++ b/arch/arm64/include/asm/esr.h
@@ -127,6 +127,8 @@
 #define ESR_ELx_WFx_ISS_WFE	(UL(1) << 0)
 #define ESR_ELx_xVC_IMM_MASK	((1UL << 16) - 1)
 
+#define VSESR_ELx_IDS_ISS_MASK    ((1UL << 25) - 1)
+
 /* ESR value templates for specific events */
 
 /* BRK instruction trap from AArch64 state */
diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index f5ea0ba..a3259a9 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -148,6 +148,16 @@ static inline u32 kvm_vcpu_get_hsr(const struct kvm_vcpu *vcpu)
 	return vcpu->arch.fault.esr_el2;
 }
 
+static inline u32 kvm_vcpu_get_vsesr(const struct kvm_vcpu *vcpu)
+{
+		return vcpu->arch.fault.vsesr_el2;
+}
+
+static inline void kvm_vcpu_set_vsesr(struct kvm_vcpu *vcpu, unsigned long val)
+{
+		vcpu->arch.fault.vsesr_el2 = val;
+}
+
 static inline int kvm_vcpu_get_condition(const struct kvm_vcpu *vcpu)
 {
 	u32 esr = kvm_vcpu_get_hsr(vcpu);
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index e7705e7..84ed239 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -86,6 +86,7 @@ struct kvm_vcpu_fault_info {
 	u32 esr_el2;		/* Hyp Syndrom Register */
 	u64 far_el2;		/* Hyp Fault Address Register */
 	u64 hpfar_el2;		/* Hyp IPA Fault Address Register */
+	u32 vsesr_el2;		/* Virtual SError Exception Syndrome Register */
 };
 
 /*
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index 32964c7..b6afb7a 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -125,6 +125,9 @@
 #define REG_PSTATE_PAN_IMM		sys_reg(0, 0, 4, 0, 4)
 #define REG_PSTATE_UAO_IMM		sys_reg(0, 0, 4, 0, 3)
 
+#define VSESR_EL2			sys_reg(3, 4, 5, 2, 3)
+
+
 #define SET_PSTATE_PAN(x) __emit_inst(0xd5000000 | REG_PSTATE_PAN_IMM |	\
 				      (!!x)<<8 | 0x1f)
 #define SET_PSTATE_UAO(x) __emit_inst(0xd5000000 | REG_PSTATE_UAO_IMM |	\
diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
index c89d83a..3d024a9 100644
--- a/arch/arm64/kvm/handle_exit.c
+++ b/arch/arm64/kvm/handle_exit.c
@@ -180,7 +180,11 @@ static exit_handle_fn kvm_get_exit_handler(struct kvm_vcpu *vcpu)
 
 static int kvm_handle_guest_sei(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
-	unsigned long fault_ipa = kvm_vcpu_get_fault_ipa(vcpu);
+	unsigned long hva, fault_ipa = kvm_vcpu_get_fault_ipa(vcpu);
+	struct kvm_memory_slot *memslot;
+	int hsr, ret = 1;
+	bool writable;
+	gfn_t gfn;
 
 	if (handle_guest_sei((unsigned long)fault_ipa,
 				kvm_vcpu_get_hsr(vcpu))) {
@@ -190,9 +194,20 @@ static int kvm_handle_guest_sei(struct kvm_vcpu *vcpu, struct kvm_run *run)
 				(unsigned long)kvm_vcpu_get_hsr(vcpu));
 
 		kvm_inject_vabt(vcpu);
+	} else {
+		hsr = kvm_vcpu_get_hsr(vcpu);
+
+		gfn = fault_ipa >> PAGE_SHIFT;
+		memslot = gfn_to_memslot(vcpu->kvm, gfn);
+		hva = gfn_to_hva_memslot_prot(memslot, gfn, &writable);
+
+		run->exit_reason = KVM_EXIT_INTR;
+		run->intr.syndrome_info = hsr;
+		run->intr.address = hva;
+		ret = 0;
 	}
 
-	return 0;
+	return ret;
 }
 
 /*
@@ -218,8 +233,7 @@ int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
 			*vcpu_pc(vcpu) -= adj;
 		}
 
-		kvm_handle_guest_sei(vcpu, run);
-		return 1;
+		return kvm_handle_guest_sei(vcpu, run);
 	}
 
 	exception_index = ARM_EXCEPTION_CODE(exception_index);
@@ -228,8 +242,7 @@ int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
 	case ARM_EXCEPTION_IRQ:
 		return 1;
 	case ARM_EXCEPTION_EL1_SERROR:
-		kvm_handle_guest_sei(vcpu, run);
-		return 1;
+		return kvm_handle_guest_sei(vcpu, run);
 	case ARM_EXCEPTION_TRAP:
 		/*
 		 * See ARM ARM B1.14.1: "Hyp traps on instructions
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index aede165..ded6211 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -86,6 +86,13 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
 		isb();
 	}
 	write_sysreg(val, hcr_el2);
+    /* If virtual System Error or Asynchronous Abort is pending. set
+     * the virtual exception syndrome information
+     */
+	if (cpus_have_cap(ARM64_HAS_RAS_EXTN) &&
+			(vcpu->arch.hcr_el2 & HCR_VSE))
+		write_sysreg_s(vcpu->arch.fault.vsesr_el2, VSESR_EL2);
+
 	/* Trap on AArch32 cp15 c15 accesses (EL1 or EL0) */
 	write_sysreg(1 << 15, hstr_el2);
 	/*
@@ -139,9 +146,15 @@ static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
 	 * the crucial bit is "On taking a vSError interrupt,
 	 * HCR_EL2.VSE is cleared to 0."
 	 */
-	if (vcpu->arch.hcr_el2 & HCR_VSE)
+	if (vcpu->arch.hcr_el2 & HCR_VSE) {
 		vcpu->arch.hcr_el2 = read_sysreg(hcr_el2);
 
+		if (cpus_have_cap(ARM64_HAS_RAS_EXTN)) {
+			/* set vsesr_el2[24:0] with esr_el2[24:0] */
+			kvm_vcpu_set_vsesr(vcpu, read_sysreg_el2(esr)
+					& VSESR_ELx_IDS_ISS_MASK);
+		}
+	}
 	__deactivate_traps_arch()();
 	write_sysreg(0, hstr_el2);
 	write_sysreg(0, pmuserenr_el0);
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 27fe556..bb02909 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -360,6 +360,11 @@ struct kvm_run {
 		struct {
 			__u8 vector;
 		} eoi;
+		/* KVM_EXIT_INTR */
+		struct {
+			__u32 syndrome_info;
+			__u64 address;
+		} intr;
 		/* KVM_EXIT_HYPERV */
 		struct kvm_hyperv_exit hyperv;
 		/* Fix the size of the union. */
-- 
2.10.1

^ permalink raw reply related

* [PATCH v3 1/3] arm64: kvm: support kvmtool to detect RAS extension feature
From: Dongjiu Geng @ 2017-04-30  5:37 UTC (permalink / raw)
  To: linux-arm-kernel

Handle kvmtool's detection for RAS extension, because sometimes
the APP needs to know the CPU's capacity

Signed-off-by: Dongjiu Geng <gengdongjiu@huawei.com>
---
 arch/arm64/kvm/reset.c   | 11 +++++++++++
 include/uapi/linux/kvm.h |  1 +
 2 files changed, 12 insertions(+)

diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
index d9e9697..1004039 100644
--- a/arch/arm64/kvm/reset.c
+++ b/arch/arm64/kvm/reset.c
@@ -64,6 +64,14 @@ static bool cpu_has_32bit_el1(void)
 	return !!(pfr0 & 0x20);
 }
 
+static bool kvm_arm_support_ras_extension(void)
+{
+	u64 pfr0;
+
+	pfr0 = read_system_reg(SYS_ID_AA64PFR0_EL1);
+	return !!(pfr0 & 0x10000000);
+}
+
 /**
  * kvm_arch_dev_ioctl_check_extension
  *
@@ -87,6 +95,9 @@ int kvm_arch_dev_ioctl_check_extension(struct kvm *kvm, long ext)
 	case KVM_CAP_ARM_PMU_V3:
 		r = kvm_arm_support_pmu_v3();
 		break;
+	case KVM_CAP_ARM_RAS_EXTENSION:
+		r = kvm_arm_support_ras_extension();
+		break;
 	case KVM_CAP_SET_GUEST_DEBUG:
 	case KVM_CAP_VCPU_ATTRIBUTES:
 		r = 1;
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index f51d508..27fe556 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -883,6 +883,7 @@ struct kvm_ppc_resize_hpt {
 #define KVM_CAP_PPC_MMU_RADIX 134
 #define KVM_CAP_PPC_MMU_HASH_V3 135
 #define KVM_CAP_IMMEDIATE_EXIT 136
+#define KVM_CAP_ARM_RAS_EXTENSION 137
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
-- 
2.10.1

^ permalink raw reply related

* [PATCH v3 4/4] target-arm: kvm64: handle SError interrupt for RAS extension
From: Dongjiu Geng @ 2017-04-30  5:35 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1493530506-26833-1-git-send-email-gengdongjiu@huawei.com>

Record this CPER to GHES, and raise a virtual SError interrupt
with specified syndrome information, the virtual syndrome
is delivered by vsesr_el2. the reason that record the error to HEST
table and inject the SError to guest is due to guest can
handle some errores to avoid directly panic, such as the
application error defered by ESB.

The steps are shown below:
1. syndrome_info and host error VA is delivered by KVM, qemu parse it.
2. translate the host VA to PA and record this error to HEST table.
3. Raise a virtual SError interrupt by set the hcr_el2.vse and pass
   the virtual syndrome

Signed-off-by: Dongjiu Geng <gengdongjiu@huawei.com>
---
 linux-headers/linux/kvm.h |  5 +++++
 target/arm/cpu.h          |  5 +++++
 target/arm/helper.c       | 20 ++++++++++++++++++++
 target/arm/internals.h    |  1 +
 target/arm/kvm.c          |  3 +++
 target/arm/kvm64.c        | 31 +++++++++++++++++++++++++++++++
 target/arm/kvm_arm.h      | 14 ++++++++++++++
 7 files changed, 79 insertions(+)

diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index c985e10..7951b91 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -360,6 +360,11 @@ struct kvm_run {
 		struct {
 			__u8 vector;
 		} eoi;
+		/* KVM_EXIT_INTR */
+		struct {
+			__u32 syndrome_info;
+			__u64 address;
+		} intr;
 		/* KVM_EXIT_HYPERV */
 		struct kvm_hyperv_exit hyperv;
 		/* Fix the size of the union. */
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 1cf4a5b..a2e6348 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -58,6 +58,8 @@
 #define EXCP_SEMIHOST       16   /* semihosting call */
 #define EXCP_NOCP           17   /* v7M NOCP UsageFault */
 #define EXCP_INVSTATE       18   /* v7M INVSTATE UsageFault */
+#define EXCP_SERROR         19   /* v8 System Error or Asynchronous Abort */
+
 
 #define ARMV7M_EXCP_RESET   1
 #define ARMV7M_EXCP_NMI     2
@@ -273,6 +275,7 @@ typedef struct CPUARMState {
             };
             uint64_t esr_el[4];
         };
+        uint64_t vsesr_el2;
         uint32_t c6_region[8]; /* MPU base/size registers.  */
         union { /* Fault address registers. */
             struct {
@@ -922,6 +925,8 @@ void pmccntr_sync(CPUARMState *env);
 #define PSTATE_MODE_EL1t 4
 #define PSTATE_MODE_EL0t 0
 
+#define VSESR_ELx_IDS_ISS_MASK    ((1UL << 25) - 1)
+
 /* Map EL and handler into a PSTATE_MODE.  */
 static inline unsigned int aarch64_pstate_mode(unsigned int el, bool handler)
 {
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 8cb7a94..bdfaba2 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -4852,6 +4852,15 @@ void register_cp_regs_for_features(ARMCPU *cpu)
         }
         define_arm_cp_regs(cpu, v8_idregs);
         define_arm_cp_regs(cpu, v8_cp_reginfo);
+        if (arm_feature(env, ARM_FEATURE_RAS_EXTENSION)) {
+            ARMCPRegInfo ras_cp_reginfo = {
+                .name = "VSESR_EL2", .state = ARM_CP_STATE_AA64,
+                .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 2, .opc2 = 3,
+                .access = PL2_RW,
+                .fieldoffset = offsetof(CPUARMState, cp15.vsesr_el2)
+            };
+            define_one_arm_cp_reg(cpu, &ras_cp_reginfo);
+        }
     }
     if (arm_feature(env, ARM_FEATURE_EL2)) {
         uint64_t vmpidr_def = mpidr_read_val(env);
@@ -6930,6 +6939,17 @@ void arm_cpu_do_interrupt(CPUState *cs)
         qemu_log_mask(CPU_LOG_INT, "...handled as PSCI call\n");
         return;
     }
+    if (cs->exception_index == EXCP_SERROR
+        && arm_feature(env, ARM_FEATURE_RAS_EXTENSION)) {
+        /* Raise virtual System Error or Asynchronous Abort and
+         * set virtual syndrome information
+         */
+        env->cp15.esr_el[2] = env->exception.syndrome;
+        env->cp15.vsesr_el2 = env->exception.syndrome & VSESR_ELx_IDS_ISS_MASK;
+        env->cp15.hcr_el2 = env->cp15.hcr_el2 | HCR_VSE;
+        qemu_log_mask(CPU_LOG_INT, "...handled as async SError\n");
+        return;
+    }
 
     /* Semihosting semantics depend on the register width of the
      * code that caused the exception, not the target exception level,
diff --git a/target/arm/internals.h b/target/arm/internals.h
index f742a41..29aabad 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -70,6 +70,7 @@ static const char * const excnames[] = {
     [EXCP_VIRQ] = "Virtual IRQ",
     [EXCP_VFIQ] = "Virtual FIQ",
     [EXCP_SEMIHOST] = "Semihosting call",
+    [EXCP_SERROR] = "async SError"
 };
 
 /* Scale factor for generic timers, ie number of ns per tick.
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index bf6ee4c..000e7c3 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -570,12 +570,15 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
 {
     int ret = 0;
 
+    struct kvm_async_abort *async_abort = (struct kvm_async_abort *)&run->intr;
     switch (run->exit_reason) {
     case KVM_EXIT_DEBUG:
         if (kvm_arm_handle_debug(cs, &run->debug.arch)) {
             ret = EXCP_DEBUG;
         } /* otherwise return to guest */
         break;
+    case KVM_EXIT_INTR:
+        kvm_arm_inject_serror(cs, async_abort);
     default:
         qemu_log_mask(LOG_UNIMP, "%s: un-handled exit reason %d\n",
                       __func__, run->exit_reason);
diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
index 5eee6f4..7d4c32f 100644
--- a/target/arm/kvm64.c
+++ b/target/arm/kvm64.c
@@ -1048,3 +1048,34 @@ bool kvm_arm_handle_debug(CPUState *cs, struct kvm_debug_exit_arch *debug_exit)
 
     return false;
 }
+
+bool kvm_arm_inject_serror(CPUState *cs,
+                struct kvm_async_abort *async_abort_exit)
+{
+    ARMCPU *cpu = ARM_CPU(cs);
+    CPUClass *cc = CPU_GET_CLASS(cs);
+    CPUARMState *env = &cpu->env;
+    hwaddr paddr;
+    ram_addr_t ram_addr;
+
+    /* Ensure PC is synchronised */
+    kvm_cpu_synchronize_state(cs);
+
+    /* record the CPER to GHES */
+    if (arm_feature(env, ARM_FEATURE_RAS_EXTENSION)
+                && async_abort_exit->address) {
+        ram_addr = qemu_ram_addr_from_host((void *)async_abort_exit->address);
+        if (ram_addr != RAM_ADDR_INVALID &&
+            kvm_physical_memory_addr_from_host(cs->kvm_state,
+                        (void *)async_abort_exit->address, &paddr)) {
+            ghes_update_guest(ACPI_HEST_NOTIFY_SEI, paddr);
+        }
+    }
+    cs->exception_index = EXCP_SERROR;
+    env->exception.syndrome = async_abort_exit->hsr;
+
+    /* inject SError to guest */
+    cc->do_interrupt(cs);
+
+    return true;
+}
diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
index 7cdde97..ed73e2b 100644
--- a/target/arm/kvm_arm.h
+++ b/target/arm/kvm_arm.h
@@ -120,6 +120,11 @@ bool write_kvmstate_to_list(ARMCPU *cpu);
  */
 void kvm_arm_reset_vcpu(ARMCPU *cpu);
 
+struct kvm_async_abort {
+    unsigned int hsr;
+    unsigned long address;  /* used for async SError */
+};
+
 #ifdef CONFIG_KVM
 /**
  * kvm_arm_create_scratch_host_vcpu:
@@ -249,6 +254,15 @@ static inline const char *gicv3_class_name(void)
 bool kvm_arm_handle_debug(CPUState *cs, struct kvm_debug_exit_arch *debug_exit);
 
 /**
+ * kvm_arm_inject_serror:
+ * @cs: CPUState
+ * @async_abort_exit: the async abort exception infomation
+ *
+ * Returns: TRUE if the async SError was injected.
+ */
+bool kvm_arm_inject_serror(CPUState *cs,
+        struct kvm_async_abort *async_abort_exit);
+/**
  * kvm_arm_hw_debug_active:
  * @cs: CPU State
  *
-- 
1.8.3.1

^ permalink raw reply related

* [PATCH v3 3/4] target-arm: kvm64: handle SIGBUS signal for synchronous External Abort
From: Dongjiu Geng @ 2017-04-30  5:35 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1493530506-26833-1-git-send-email-gengdongjiu@huawei.com>

If RAS extension feature exists, when guest OS happen synchronous
External Abort, a SIGBUS signal will be delivered from the kvm.
so handle this signal, generate GHES record and inject this
abort to notify guest. then guest can handle this abort

The Synchronous External Abort mainly includes below two types:
1. Error on memory access, such as hwpoison. the SIGBUS si_code is
   BUS_MCEERR_AR or BUS_MCEERR_OR
2. Error on translation table walk or hardware update of translation table.
   The SIGBUS si_code is 0

Signed-off-by: Dongjiu Geng <gengdongjiu@huawei.com>
---
 include/sysemu/kvm.h      |  2 +-
 linux-headers/linux/kvm.h |  3 +++
 target/arm/kvm.c          | 34 +++++++++++++++++++++++++++
 target/arm/kvm64.c        | 60 +++++++++++++++++++++++++++++++++++++++++++++++
 target/arm/kvm_arm.h      |  1 +
 5 files changed, 99 insertions(+), 1 deletion(-)

diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index 24281fc..feef990 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -354,7 +354,7 @@ bool kvm_vcpu_id_is_valid(int vcpu_id);
 /* Returns VCPU ID to be used on KVM_CREATE_VCPU ioctl() */
 unsigned long kvm_arch_vcpu_id(CPUState *cpu);
 
-#ifdef TARGET_I386
+#if defined(TARGET_I386) || defined(TARGET_AARCH64)
 #define KVM_HAVE_MCE_INJECTION 1
 void kvm_arch_on_sigbus_vcpu(CPUState *cpu, int code, void *addr);
 #endif
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index e0fa5b8..c985e10 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -1301,6 +1301,9 @@ struct kvm_s390_ucas_mapping {
 #define KVM_S390_GET_IRQ_STATE	  _IOW(KVMIO, 0xb6, struct kvm_s390_irq_state)
 /* Available with KVM_CAP_X86_SMM */
 #define KVM_SMI                   _IO(KVMIO,   0xb7)
+/* Available with KVM_CAP_ARM_RAS_EXTENSION */
+#define KVM_ARM_SEA                 _IO(KVMIO,   0xb8)
+
 
 #define KVM_DEV_ASSIGN_ENABLE_IOMMU	(1 << 0)
 #define KVM_DEV_ASSIGN_PCI_2_3		(1 << 1)
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 4555468..bf6ee4c 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -129,6 +129,39 @@ void kvm_arm_destroy_scratch_host_vcpu(int *fdarray)
     }
 }
 
+typedef struct HWPoisonPage {
+    ram_addr_t ram_addr;
+    QLIST_ENTRY(HWPoisonPage) list;
+} HWPoisonPage;
+
+static QLIST_HEAD(, HWPoisonPage) hwpoison_page_list =
+    QLIST_HEAD_INITIALIZER(hwpoison_page_list);
+
+static void kvm_unpoison_all(void *param)
+{
+    HWPoisonPage *page, *next_page;
+
+    QLIST_FOREACH_SAFE(page, &hwpoison_page_list, list, next_page) {
+        QLIST_REMOVE(page, list);
+        qemu_ram_remap(page->ram_addr, TARGET_PAGE_SIZE);
+        g_free(page);
+    }
+}
+
+void kvm_hwpoison_page_add(ram_addr_t ram_addr)
+{
+    HWPoisonPage *page;
+
+    QLIST_FOREACH(page, &hwpoison_page_list, list) {
+        if (page->ram_addr == ram_addr) {
+            return;
+        }
+    }
+    page = g_new(HWPoisonPage, 1);
+    page->ram_addr = ram_addr;
+    QLIST_INSERT_HEAD(&hwpoison_page_list, page, list);
+}
+
 static void kvm_arm_host_cpu_class_init(ObjectClass *oc, void *data)
 {
     ARMHostCPUClass *ahcc = ARM_HOST_CPU_CLASS(oc);
@@ -176,6 +209,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
 
     cap_has_mp_state = kvm_check_extension(s, KVM_CAP_MP_STATE);
 
+    qemu_register_reset(kvm_unpoison_all, NULL);
     type_register_static(&host_arm_cpu_type_info);
 
     return 0;
diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
index fd30a5a..5eee6f4 100644
--- a/target/arm/kvm64.c
+++ b/target/arm/kvm64.c
@@ -27,6 +27,8 @@
 #include "kvm_arm.h"
 #include "internals.h"
 #include "hw/arm/arm.h"
+#include "hw/acpi/acpi-defs.h"
+#include "hw/acpi/hest_ghes.h"
 
 static bool have_guest_debug;
 
@@ -590,6 +592,21 @@ int kvm_arm_cpreg_level(uint64_t regidx)
     return KVM_PUT_RUNTIME_STATE;
 }
 
+static int kvm_inject_arm_sea(ARMCPU *cpu)
+{
+    CPUState *cs = CPU(cpu);
+    if (cs->exception_index == EXCP_DATA_ABORT) {
+        cs->exception_index = -1;
+        /* Here use a new ioctl KVM_ARM_SEA instead of KVM_SET_ONE_REG,
+         * Becuase kernel has direct injection interface, so simplify
+         * the logic to use kernel interface
+         */
+        return  kvm_vcpu_ioctl(CPU(cpu), KVM_ARM_SEA);
+    }
+
+    return 0;
+}
+
 #define AARCH64_CORE_REG(x)   (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
                  KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(x))
 
@@ -735,6 +752,13 @@ int kvm_arch_put_registers(CPUState *cs, int level)
         return EINVAL;
     }
 
+    if (arm_feature(env, ARM_FEATURE_RAS_EXTENSION)) {
+        ret = kvm_inject_arm_sea(cpu);
+        if (ret < 0) {
+            return ret;
+        }
+    }
+
     kvm_arm_sync_mpstate_to_kvm(cpu);
 
     return ret;
@@ -887,6 +911,42 @@ int kvm_arch_get_registers(CPUState *cs)
     return ret;
 }
 
+void kvm_arch_on_sigbus_vcpu(CPUState *c, int code, void *addr)
+{
+    ARMCPU *cpu = ARM_CPU(c);
+    CPUARMState *env = &cpu->env;
+
+    ram_addr_t ram_addr;
+    hwaddr paddr;
+
+    if (arm_feature(env, ARM_FEATURE_RAS_EXTENSION) && addr) {
+        ram_addr = qemu_ram_addr_from_host(addr);
+        if (ram_addr != RAM_ADDR_INVALID &&
+            kvm_physical_memory_addr_from_host(c->kvm_state, addr, &paddr)) {
+            /* For the hardware error, some are hwpoison errors, some
+             * are other errors, such as translation table walk or hardware
+             * update of translation table. For the hwpoison, the si_code
+             * is BUS_MCEERR_AR or BUS_MCEERR_AO, other errors are 0
+             */
+            if (code == BUS_MCEERR_AR || code == BUS_MCEERR_AO) {
+                kvm_hwpoison_page_add(ram_addr);
+            }
+            ghes_update_guest(ACPI_HEST_NOTIFY_SEA, paddr);
+            c->exception_index = EXCP_DATA_ABORT;
+            kvm_cpu_synchronize_state(c);
+            return;
+        }
+
+        fprintf(stderr, "Hardware memory error for memory used by "
+                "QEMU itself instead of guest system!\n");
+    }
+
+    if (code == BUS_MCEERR_AR) {
+        fprintf(stderr, "Hardware memory error!\n");
+        exit(1);
+    }
+}
+
 /* C6.6.29 BRK instruction */
 static const uint32_t brk_insn = 0xd4200000;
 
diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
index 633d088..7cdde97 100644
--- a/target/arm/kvm_arm.h
+++ b/target/arm/kvm_arm.h
@@ -288,4 +288,5 @@ static inline const char *its_class_name(void)
     }
 }
 
+void kvm_hwpoison_page_add(ram_addr_t ram_addr);
 #endif
-- 
1.8.3.1

^ permalink raw reply related

* [PATCH v3 2/4] target-arm: kvm64: detect guest RAS EXTENSION feature
From: Dongjiu Geng @ 2017-04-30  5:35 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1493530506-26833-1-git-send-email-gengdongjiu@huawei.com>

check if kvm supports guest RAS EXTENSION. if so, set
corresponding feature bit for vcpu.

Signed-off-by: Dongjiu Geng <gengdongjiu@huawei.com>
---
 linux-headers/asm-arm64/kvm.h | 1 +
 linux-headers/linux/kvm.h     | 1 +
 target/arm/cpu.h              | 3 +++
 target/arm/kvm64.c            | 8 ++++++++
 4 files changed, 13 insertions(+)

diff --git a/linux-headers/asm-arm64/kvm.h b/linux-headers/asm-arm64/kvm.h
index 651ec30..acb5c4d 100644
--- a/linux-headers/asm-arm64/kvm.h
+++ b/linux-headers/asm-arm64/kvm.h
@@ -97,6 +97,7 @@ struct kvm_regs {
 #define KVM_ARM_VCPU_EL1_32BIT		1 /* CPU running a 32bit VM */
 #define KVM_ARM_VCPU_PSCI_0_2		2 /* CPU uses PSCI v0.2 */
 #define KVM_ARM_VCPU_PMU_V3		3 /* Support guest PMUv3 */
+#define KVM_ARM_VCPU_RAS_EXTENSION	4
 
 struct kvm_vcpu_init {
 	__u32 target;
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index 4e082a8..e0fa5b8 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -883,6 +883,7 @@ struct kvm_ppc_resize_hpt {
 #define KVM_CAP_PPC_MMU_RADIX 134
 #define KVM_CAP_PPC_MMU_HASH_V3 135
 #define KVM_CAP_IMMEDIATE_EXIT 136
+#define KVM_CAP_ARM_RAS_EXTENSION 137
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index a8aabce..1cf4a5b 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -610,6 +610,8 @@ struct ARMCPU {
 
     /* CPU has memory protection unit */
     bool has_mpu;
+    /* CPU has ras extension unit */
+    bool has_ras_extension;
     /* PMSAv7 MPU number of supported regions */
     uint32_t pmsav7_dregion;
 
@@ -1216,6 +1218,7 @@ enum arm_features {
     ARM_FEATURE_THUMB_DSP, /* DSP insns supported in the Thumb encodings */
     ARM_FEATURE_PMU, /* has PMU support */
     ARM_FEATURE_VBAR, /* has cp15 VBAR */
+    ARM_FEATURE_RAS_EXTENSION, /*has RAS extension support */
 };
 
 static inline int arm_feature(CPUARMState *env, int feature)
diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
index 6111109..fd30a5a 100644
--- a/target/arm/kvm64.c
+++ b/target/arm/kvm64.c
@@ -518,6 +518,14 @@ int kvm_arch_init_vcpu(CPUState *cs)
         unset_feature(&env->features, ARM_FEATURE_PMU);
     }
 
+    if (kvm_check_extension(cs->kvm_state, KVM_CAP_ARM_RAS_EXTENSION)) {
+        cpu->has_ras_extension = true;
+        cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_RAS_EXTENSION;
+    } else {
+        cpu->has_ras_extension = false;
+        unset_feature(&env->features, ARM_FEATURE_RAS_EXTENSION);
+    }
+
     /* Do KVM_ARM_VCPU_INIT ioctl */
     ret = kvm_arm_vcpu_init(cs);
     if (ret) {
-- 
1.8.3.1

^ permalink raw reply related

* [PATCH v3 1/4] ACPI: Add APEI GHES Table Generation support
From: Dongjiu Geng @ 2017-04-30  5:35 UTC (permalink / raw)
  To: linux-arm-kernel

This implements APEI GHES Table by passing the error cper info
to the guest via a fw_cfg_blob. After a CPER info is added, an
SEA/SEI exception will be injected into the guest OS.

Below is the table layout, the max number of error soure is 11,
which is classified by notification type.

etc/acpi/tables                 etc/hardware_errors
================     ==========================================
                     +-----------+
+--------------+     | address   |         +-> +--------------+
|    HEST      +     | registers |         |   | Error Status |
+ +------------+     | +---------+         |   | Data Block 1 |
| | GHES1      | --> | |address1 | --------+   | +------------+
| | GHES2      | --> | |address2 | ------+     | |  CPER      |
| | GHES3      | --> | |address3 | ----+ |     | |  CPER      |
| |  ....      | --> | | ....... |     | |     | |  CPER      |
| | GHES10     | --> | |address10| -+  | |     | |  CPER      |
+-+------------+     +-+---------+  |  | |     +-+------------+
                                    |  | |
                                    |  | +---> +--------------+
                                    |  |       | Error Status |
                                    |  |       | Data Block 2 |
                                    |  |       | +------------+
                                    |  |       | |  CPER      |
                                    |  |       | |  CPER      |
                                    |  |       +-+------------+
                                    |  |
                                    |  +-----> +--------------+
                                    |          | Error Status |
                                    |          | Data Block 3 |
                                    |          | +------------+
                                    |          | |  CPER      |
                                    |          +-+------------+
                                    |            ...........
                                    +--------> +--------------+
                                               | Error Status |
                                               | Data Block 10|
                                               | +------------+
                                               | |  CPER      |
                                               | |  CPER      |
                                               | |  CPER      |
                                               +-+------------+

Signed-off-by: Dongjiu Geng <gengdongjiu@huawei.com>
---
 default-configs/arm-softmmu.mak |   1 +
 hw/acpi/Makefile.objs           |   1 +
 hw/acpi/aml-build.c             |   2 +
 hw/acpi/hest_ghes.c             | 203 +++++++++++++++++++++++++++++++++++
 hw/arm/virt-acpi-build.c        |   6 ++
 include/hw/acpi/acpi-defs.h     | 227 ++++++++++++++++++++++++++++++++++++++++
 include/hw/acpi/aml-build.h     |   1 +
 include/hw/acpi/hest_ghes.h     |  43 ++++++++
 8 files changed, 484 insertions(+)
 create mode 100644 hw/acpi/hest_ghes.c
 create mode 100644 include/hw/acpi/hest_ghes.h

diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index 1e3bd2b..d5f1552 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -121,3 +121,4 @@ CONFIG_ACPI=y
 CONFIG_SMBIOS=y
 CONFIG_ASPEED_SOC=y
 CONFIG_GPIO_KEY=y
+CONFIG_ACPI_APEI_GENERATION=y
diff --git a/hw/acpi/Makefile.objs b/hw/acpi/Makefile.objs
index 11c35bc..776b46e 100644
--- a/hw/acpi/Makefile.objs
+++ b/hw/acpi/Makefile.objs
@@ -6,6 +6,7 @@ common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o
 common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu.o
 common-obj-$(CONFIG_ACPI_NVDIMM) += nvdimm.o
 common-obj-$(CONFIG_ACPI_VMGENID) += vmgenid.o
+common-obj-$(CONFIG_ACPI_APEI_GENERATION) += hest_ghes.o
 common-obj-$(call lnot,$(CONFIG_ACPI_X86)) += acpi-stub.o
 
 common-obj-y += acpi_interface.o
diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
index c6f2032..802b98d 100644
--- a/hw/acpi/aml-build.c
+++ b/hw/acpi/aml-build.c
@@ -1560,6 +1560,7 @@ void acpi_build_tables_init(AcpiBuildTables *tables)
     tables->table_data = g_array_new(false, true /* clear */, 1);
     tables->tcpalog = g_array_new(false, true /* clear */, 1);
     tables->vmgenid = g_array_new(false, true /* clear */, 1);
+    tables->hardware_errors = g_array_new(false, true /* clear */, 1);
     tables->linker = bios_linker_loader_init();
 }
 
@@ -1570,6 +1571,7 @@ void acpi_build_tables_cleanup(AcpiBuildTables *tables, bool mfre)
     g_array_free(tables->table_data, true);
     g_array_free(tables->tcpalog, mfre);
     g_array_free(tables->vmgenid, mfre);
+    g_array_free(tables->hardware_errors, mfre);
 }
 
 /* Build rsdt table */
diff --git a/hw/acpi/hest_ghes.c b/hw/acpi/hest_ghes.c
new file mode 100644
index 0000000..91d382e
--- /dev/null
+++ b/hw/acpi/hest_ghes.c
@@ -0,0 +1,203 @@
+/*
+ *  APEI GHES table Generation
+ *
+ *  Copyright (C) 2017 huawei.
+ *
+ *  Author: Dongjiu Geng <gengdongjiu@huawei.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qmp-commands.h"
+#include "hw/acpi/acpi.h"
+#include "hw/acpi/aml-build.h"
+#include "hw/acpi/hest_ghes.h"
+#include "hw/nvram/fw_cfg.h"
+#include "sysemu/sysemu.h"
+
+static int ghes_generate_cper_record(uint64_t block_error_address,
+                                    uint64_t error_physical_addr)
+{
+    AcpiGenericErrorStatus block;
+    AcpiGenericErrorData *gdata;
+    struct cper_sec_mem_err *mem_err;
+    uint64_t block_data_length;
+    unsigned char *buffer;
+
+    cpu_physical_memory_read(block_error_address, &block,
+                                sizeof(AcpiGenericErrorStatus));
+
+    block_data_length = sizeof(AcpiGenericErrorStatus) + block.data_length;
+
+    /* If the Generic Error Status Block is NULL, update
+     * the block header
+     */
+    if (!block.block_status) {
+        block.block_status = ACPI_BERT_UNCORRECTABLE;
+        block.error_severity = CPER_SEV_FATAL;
+    }
+
+    block.data_length += sizeof(AcpiGenericErrorData);
+    block.data_length += sizeof(struct cper_sec_mem_err);
+
+    /* Write back the Generic Error Status Block to guest memory */
+    cpu_physical_memory_write(block_error_address, &block,
+                        sizeof(AcpiGenericErrorStatus));
+
+    /* Fill in Generic Error Data Entry */
+    buffer = g_malloc(sizeof(AcpiGenericErrorData) + sizeof(cper_sec_mem_err));
+    memset(buffer, 0, sizeof(AcpiGenericErrorData) + sizeof(cper_sec_mem_err));
+    gdata = (AcpiGenericErrorData *)buffer;
+
+    memcpy(gdata->section_type, (void *) &CPER_SEC_PLATFORM_MEM,
+                sizeof(uuid_le));
+    gdata->error_data_length = sizeof(struct cper_sec_mem_err);
+
+    mem_err = (struct cper_sec_mem_err *) (gdata + 1);
+
+    /* In order to simplify simulation, hardcode the CPER section to memory
+     * section.
+     */
+    mem_err->validation_bits |= CPER_MEM_VALID_ERROR_TYPE;
+    mem_err->error_type = 3;
+
+    mem_err->validation_bits |= CPER_MEM_VALID_PA;
+    mem_err->physical_addr = error_physical_addr;
+
+    mem_err->validation_bits |= CPER_MEM_VALID_CARD | CPER_MEM_VALID_MODULE |
+            CPER_MEM_VALID_BANK | CPER_MEM_VALID_ROW |
+            CPER_MEM_VALID_COLUMN | CPER_MEM_VALID_BIT_POSITION;
+    mem_err->card = 1;
+    mem_err->module = 2;
+    mem_err->bank = 3;
+    mem_err->row = 1;
+    mem_err->column = 2;
+    mem_err->bit_pos = 5;
+
+    mem_err->validation_bits |= CPER_MEM_VALID_ERROR_STATUS;
+    mem_err->error_status = 4 << 8;
+
+    /* Write back the Generic Error Data Entry to guest memory */
+    cpu_physical_memory_write(block_error_address + block_data_length, buffer,
+                    sizeof(AcpiGenericErrorData) + sizeof(cper_sec_mem_err));
+
+    g_free(buffer);
+    return BFAPEI_OK;
+}
+
+void ghes_build_acpi(GArray *table_data, GArray *hardware_error,
+                                            BIOSLinker *linker)
+{
+    Aml *hest;
+    uint32_t address_registers_offset;
+    AcpiTableHeader *header;
+    AcpiGenericHardwareErrorSource *error_source;
+    int i;
+
+    int block_reqr_size = sizeof(uint64_t) + MAX_RAW_DATA_LENGTH;
+
+    /* New address register and Error status block table size*/
+    g_array_set_size(hardware_error, MAX_ERROR_SOURCE_COUNT_V6
+                                        * block_reqr_size);
+
+    /* Put this in a HEST table */
+    hest = init_aml_allocator();
+    address_registers_offset = table_data->len
+                                + sizeof(AcpiHardwareErrorSourceTable)
+                                + ERROR_STATUS_ADDRESS_OFFSET
+                                + GAS_ADDRESS_OFFSET;
+    /* Reserve space for HEST table size*/
+    acpi_data_push(hest->buf, sizeof(AcpiHardwareErrorSourceTable)
+                                + MAX_ERROR_SOURCE_COUNT_V6
+                                * sizeof(AcpiGenericHardwareErrorSource));
+
+    g_array_append_vals(table_data, hest->buf->data, hest->buf->len);
+    /* Allocate guest memory for the Data fw_cfg blob */
+    bios_linker_loader_alloc(linker, GHES_ERRORS_FW_CFG_FILE,
+                            hardware_error, 4096,
+                            false /* page boundary, high memory */);
+    header = (AcpiTableHeader *)(table_data->data
+                        + table_data->len - hest->buf->len);
+    *(uint32_t *)(header + 1) = MAX_ERROR_SOURCE_COUNT_V6;
+    error_source = (AcpiGenericHardwareErrorSource *)((char *)header
+                                    + sizeof(AcpiHardwareErrorSourceTable));
+
+    for (i = 0; i < MAX_ERROR_SOURCE_COUNT_V6; i++) {
+        error_source->type = ACPI_HEST_TYPE_GENERIC_ERROR;
+        error_source->source_id = 0;
+        error_source->related_source_id = 0xffff;
+        error_source->flags = 0;
+        error_source->enabled = 1;
+        error_source->number_of_records = 1;
+        error_source->max_sections_per_record = 1;
+        error_source->max_raw_data_length = MAX_RAW_DATA_LENGTH;
+        error_source->error_status_address.space_id =
+                                    ACPI_ADR_SPACE_SYSTEM_MEMORY;
+        error_source->error_status_address.bit_width = 64;
+        error_source->error_status_address.bit_offset = 0;
+        error_source->error_status_address.access_width = 4;
+        error_source->notify.type = i;
+        error_source->notify.length = sizeof(AcpiGenericHardwareErrorSource);
+
+        bios_linker_loader_add_pointer(linker, GHES_ERRORS_FW_CFG_FILE,
+                                sizeof(uint64_t) * i, sizeof(uint64_t),
+                                GHES_ERRORS_FW_CFG_FILE,
+                                MAX_ERROR_SOURCE_COUNT_V6 * sizeof(uint64_t) +
+                                i * MAX_RAW_DATA_LENGTH);
+        bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE,
+                    address_registers_offset
+                    + i * sizeof(AcpiGenericHardwareErrorSource),
+                    sizeof(uint32_t), GHES_ERRORS_FW_CFG_FILE,
+                    i * sizeof(uint64_t));
+
+        bios_linker_loader_write_pointer(linker, GHES_DATA_ADDR_FW_CFG_FILE,
+                                i * sizeof(uint64_t), sizeof(uint64_t),
+                                GHES_ERRORS_FW_CFG_FILE,
+                                MAX_ERROR_SOURCE_COUNT_V6 * sizeof(uint64_t) +
+                                i * MAX_RAW_DATA_LENGTH);
+         error_source++;
+    }
+
+     build_header(linker, table_data,
+        (void *)header, "HEST", hest->buf->len, 1, NULL, "GHES");
+
+    free_aml_allocator();
+}
+
+static GhesErrorState ges;
+void ghes_add_fw_cfg(FWCfgState *s, GArray *hardware_error)
+{
+
+    int block_reqr_size = sizeof(uint64_t) + MAX_RAW_DATA_LENGTH;
+    int size = MAX_ERROR_SOURCE_COUNT_V6 * block_reqr_size;
+
+    /* Create a read-only fw_cfg file for GHES */
+    fw_cfg_add_file(s, GHES_ERRORS_FW_CFG_FILE, hardware_error->data,
+                    size);
+    /* Create a read-write fw_cfg file for Address */
+    fw_cfg_add_file_callback(s, GHES_DATA_ADDR_FW_CFG_FILE, NULL, NULL,
+                            &(ges.ghes_addr_le[0]),
+                            sizeof(uint64_t) * MAX_ERROR_SOURCE_COUNT_V6,
+                            false);
+}
+
+void ghes_update_guest(uint32_t notify, uint64_t physical_address)
+{
+    uint64_t block_error_addr;
+
+    if (physical_address) {
+        ges.physical_addr = physical_address;
+        block_error_addr = ges.ghes_addr_le[notify];
+        block_error_addr = le32_to_cpu(block_error_addr);
+
+        /* A zero value in ghes_addr means that BIOS has not yet written
+         * the address
+         */
+        if (block_error_addr) {
+            ghes_generate_cper_record(block_error_addr, physical_address);
+        }
+    }
+}
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 0835e59..e7ab5dc 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -45,6 +45,8 @@
 #include "hw/arm/virt.h"
 #include "sysemu/numa.h"
 #include "kvm_arm.h"
+#include "hw/acpi/vmgenid.h"
+#include "hw/acpi/hest_ghes.h"
 
 #define ARM_SPI_BASE 32
 #define ACPI_POWER_BUTTON_DEVICE "PWRB"
@@ -778,6 +780,9 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
     acpi_add_table(table_offsets, tables_blob);
     build_spcr(tables_blob, tables->linker, vms);
 
+    acpi_add_table(table_offsets, tables_blob);
+    ghes_build_acpi(tables_blob, tables->hardware_errors, tables->linker);
+
     if (nb_numa_nodes > 0) {
         acpi_add_table(table_offsets, tables_blob);
         build_srat(tables_blob, tables->linker, vms);
@@ -892,6 +897,7 @@ void virt_acpi_setup(VirtMachineState *vms)
 
     build_state->rsdp_mr = acpi_add_rom_blob(build_state, tables.rsdp,
                                               ACPI_BUILD_RSDP_FILE, 0);
+    ghes_add_fw_cfg(vms->fw_cfg, tables.hardware_errors);
 
     qemu_register_reset(virt_acpi_build_reset, build_state);
     virt_acpi_build_reset(build_state);
diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h
index 4cc3630..27adede 100644
--- a/include/hw/acpi/acpi-defs.h
+++ b/include/hw/acpi/acpi-defs.h
@@ -295,6 +295,58 @@ typedef struct AcpiMultipleApicTable AcpiMultipleApicTable;
 #define ACPI_APIC_GENERIC_TRANSLATOR    15
 #define ACPI_APIC_RESERVED              16   /* 16 and greater are reserved */
 
+#define CPER_MEM_VALID_ERROR_STATUS     0x0001
+#define CPER_MEM_VALID_PA               0x0002
+#define CPER_MEM_VALID_PA_MASK          0x0004
+#define CPER_MEM_VALID_NODE             0x0008
+#define CPER_MEM_VALID_CARD             0x0010
+#define CPER_MEM_VALID_MODULE           0x0020
+#define CPER_MEM_VALID_BANK             0x0040
+#define CPER_MEM_VALID_DEVICE           0x0080
+#define CPER_MEM_VALID_ROW              0x0100
+#define CPER_MEM_VALID_COLUMN           0x0200
+#define CPER_MEM_VALID_BIT_POSITION     0x0400
+#define CPER_MEM_VALID_REQUESTOR_ID     0x0800
+#define CPER_MEM_VALID_RESPONDER_ID     0x1000
+#define CPER_MEM_VALID_TARGET_ID        0x2000
+#define CPER_MEM_VALID_ERROR_TYPE       0x4000
+#define CPER_MEM_VALID_RANK_NUMBER      0x8000
+#define CPER_MEM_VALID_CARD_HANDLE      0x10000
+#define CPER_MEM_VALID_MODULE_HANDLE    0x20000
+
+typedef struct {
+    uint8_t b[16];
+} uuid_le;
+
+#define UUID_LE(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7)        \
+((uuid_le)                              \
+{{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \
+    (b) & 0xff, ((b) >> 8) & 0xff,                   \
+    (c) & 0xff, ((c) >> 8) & 0xff,                   \
+    (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) } })
+
+/* Platform Memory */
+#define CPER_SEC_PLATFORM_MEM                   \
+    UUID_LE(0xA5BC1114, 0x6F64, 0x4EDE, 0xB8, 0x63, 0x3E, 0x83, \
+        0xED, 0x7C, 0x83, 0xB1)
+
+/* Values for Notify Type field above */
+
+enum acpi_hest_notify_types {
+    ACPI_HEST_NOTIFY_POLLED = 0,
+    ACPI_HEST_NOTIFY_EXTERNAL = 1,
+    ACPI_HEST_NOTIFY_LOCAL = 2,
+    ACPI_HEST_NOTIFY_SCI = 3,
+    ACPI_HEST_NOTIFY_NMI = 4,
+    ACPI_HEST_NOTIFY_CMCI = 5,  /* ACPI 5.0 */
+    ACPI_HEST_NOTIFY_MCE = 6,   /* ACPI 5.0 */
+    ACPI_HEST_NOTIFY_GPIO = 7,  /* ACPI 6.0 */
+    ACPI_HEST_NOTIFY_SEA = 8,   /* ACPI 6.1 */
+    ACPI_HEST_NOTIFY_SEI = 9,   /* ACPI 6.1 */
+    ACPI_HEST_NOTIFY_GSIV = 10, /* ACPI 6.1 */
+    ACPI_HEST_NOTIFY_RESERVED = 11  /* 11 and greater are reserved */
+};
+
 /*
  * MADT sub-structures (Follow MULTIPLE_APIC_DESCRIPTION_TABLE)
  */
@@ -475,6 +527,181 @@ struct AcpiSystemResourceAffinityTable
 } QEMU_PACKED;
 typedef struct AcpiSystemResourceAffinityTable AcpiSystemResourceAffinityTable;
 
+#define ACPI_ADR_SPACE_SYSTEM_MEMORY    (uint8_t) 0
+#define ACPI_ADR_SPACE_SYSTEM_IO        (uint8_t) 1
+#define ACPI_ADR_SPACE_PCI_CONFIG       (uint8_t) 2
+#define ACPI_ADR_SPACE_EC               (uint8_t) 3
+#define ACPI_ADR_SPACE_SMBUS            (uint8_t) 4
+#define ACPI_ADR_SPACE_CMOS             (uint8_t) 5
+#define ACPI_ADR_SPACE_PCI_BAR_TARGET   (uint8_t) 6
+#define ACPI_ADR_SPACE_IPMI             (uint8_t) 7
+#define ACPI_ADR_SPACE_GPIO             (uint8_t) 8
+#define ACPI_ADR_SPACE_GSBUS            (uint8_t) 9
+#define ACPI_ADR_SPACE_PLATFORM_COMM    (uint8_t) 10
+
+/* GAS - Generic Address Structure */
+struct acpi_generic_address {
+    uint8_t space_id;       /* Address space where
+                             *struct or register exists
+                             */
+    uint8_t bit_width;      /* Size in bits of given register */
+    uint8_t bit_offset;     /* Bit offset within the register */
+    uint8_t access_width;   /* Minimum Access size (ACPI 3.0) */
+    uint64_t address;       /* 64-bit address of struct or register */
+} __attribute__ ((packed));
+
+/* Hardware Error Notification */
+struct acpi_hest_notify {
+    uint8_t type;
+    uint8_t length;
+    uint16_t config_write_enable;
+    uint32_t poll_interval;
+    uint32_t vector;
+    uint32_t polling_threshold_value;
+    uint32_t polling_threshold_window;
+    uint32_t error_threshold_value;
+    uint32_t error_threshold_window;
+};
+
+enum acpi_hest_types {
+    ACPI_HEST_TYPE_IA32_CHECK = 0,
+    ACPI_HEST_TYPE_IA32_CORRECTED_CHECK = 1,
+    ACPI_HEST_TYPE_IA32_NMI = 2,
+    ACPI_HEST_TYPE_NOT_USED3 = 3,
+    ACPI_HEST_TYPE_NOT_USED4 = 4,
+    ACPI_HEST_TYPE_NOT_USED5 = 5,
+    ACPI_HEST_TYPE_AER_ROOT_PORT = 6,
+    ACPI_HEST_TYPE_AER_ENDPOINT = 7,
+    ACPI_HEST_TYPE_AER_BRIDGE = 8,
+    ACPI_HEST_TYPE_GENERIC_ERROR = 9,
+    ACPI_HEST_TYPE_GENERIC_ERROR_V2 = 10,
+    ACPI_HEST_TYPE_RESERVED = 11    /* 11 and greater are reserved */
+};
+
+/* Values for block_status flags above */
+#define ACPI_BERT_UNCORRECTABLE             (1)
+#define ACPI_BERT_CORRECTABLE               (1 << 1)
+#define ACPI_BERT_MULTIPLE_UNCORRECTABLE    (1 << 2)
+#define ACPI_BERT_MULTIPLE_CORRECTABLE      (1 << 3)
+/* 8 bits, error count */
+#define ACPI_BERT_ERROR_ENTRY_COUNT         (0xFF << 4)
+
+/* Generic Hardware Error Source Structure */
+struct AcpiGenericHardwareErrorSource {
+    uint16_t type;
+    uint16_t source_id;
+    uint16_t related_source_id;
+    uint8_t flags;
+    uint8_t enabled;
+    uint32_t number_of_records;
+    uint32_t max_sections_per_record;
+    uint32_t max_raw_data_length;
+    struct acpi_generic_address error_status_address;
+    struct acpi_hest_notify notify;
+    uint32_t error_status_block_length;
+} QEMU_PACKED;
+typedef struct AcpiGenericHardwareErrorSource AcpiGenericHardwareErrorSource;
+
+/* Generic Hardware Error Source , version 2 */
+struct AcpiGenericHardwareErrorSourceV2 {
+    uint16_t type;
+    uint16_t source_id;
+    uint16_t related_source_id;
+    uint8_t flags;
+    uint8_t enabled;
+    uint32_t number_of_records;
+    uint32_t max_sections_per_record;
+    uint32_t max_raw_data_length;
+    struct acpi_generic_address error_status_address;
+    struct acpi_hest_notify notify;
+    uint32_t error_status_block_length;
+    struct acpi_generic_address read_ack_register;
+    uint64_t read_ack_preserve;
+    uint64_t read_ack_write;
+} QEMU_PACKED;
+typedef struct AcpiGenericHardwareErrorSourceV2
+            AcpiGenericHardwareErrorSourceV2;
+
+/* Generic Error Status block */
+
+struct AcpiGenericErrorStatus {
+    uint32_t block_status;
+    uint32_t raw_data_offset;
+    uint32_t raw_data_length;
+    uint32_t data_length;
+    uint32_t error_severity;
+};
+typedef struct AcpiGenericErrorStatus AcpiGenericErrorStatus;
+
+/* Generic Error Data entry */
+
+struct AcpiGenericErrorData {
+    uint8_t section_type[16];
+    uint32_t error_severity;
+    uint16_t revision;
+    uint8_t validation_bits;
+    uint8_t flags;
+    uint32_t error_data_length;
+    uint8_t fru_id[16];
+    uint8_t fru_text[20];
+};
+typedef struct AcpiGenericErrorData AcpiGenericErrorData;
+
+/* Extension for revision 0x0300  */
+struct AcpiGenericErrorDataV300 {
+    uint8_t section_type[16];
+    uint32_t error_severity;
+    uint16_t revision;
+    uint8_t validation_bits;
+    uint8_t flags;
+    uint32_t error_data_length;
+    uint8_t fru_id[16];
+    uint8_t fru_text[20];
+    uint64_t time_stamp;
+};
+typedef struct AcpiGenericErrorDataV300 AcpiGenericErrorDataV300;
+
+enum {
+    CPER_SEV_RECOVERABLE,
+    CPER_SEV_FATAL,
+    CPER_SEV_CORRECTED,
+    CPER_SEV_INFORMATIONAL,
+};
+
+/* Memory Error Section */
+struct cper_sec_mem_err {
+    uint64_t    validation_bits;
+    uint64_t    error_status;
+    uint64_t    physical_addr;
+    uint64_t    physical_addr_mask;
+    uint16_t    node;
+    uint16_t    card;
+    uint16_t    module;
+    uint16_t    bank;
+    uint16_t    device;
+    uint16_t    row;
+    uint16_t    column;
+    uint16_t    bit_pos;
+    uint64_t    requestor_id;
+    uint64_t    responder_id;
+    uint64_t    target_id;
+    uint8_t     error_type;
+    uint8_t     reserved;
+    uint16_t    rank;
+    uint16_t    mem_array_handle;   /* card handle in UEFI 2.4 */
+    uint16_t    mem_dev_handle;     /* module handle in UEFI 2.4 */
+};
+ typedef struct cper_sec_mem_err cper_sec_mem_err;
+
+/*
+ * HEST Description Table
+ */
+struct AcpiHardwareErrorSourceTable {
+    ACPI_TABLE_HEADER_DEF                    /* ACPI common table header */
+    uint32_t           error_source_count;
+} QEMU_PACKED;
+typedef struct AcpiHardwareErrorSourceTable AcpiHardwareErrorSourceTable;
+
 #define ACPI_SRAT_PROCESSOR_APIC     0
 #define ACPI_SRAT_MEMORY             1
 #define ACPI_SRAT_PROCESSOR_x2APIC   2
diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h
index 00c21f1..c1d15b3 100644
--- a/include/hw/acpi/aml-build.h
+++ b/include/hw/acpi/aml-build.h
@@ -211,6 +211,7 @@ struct AcpiBuildTables {
     GArray *rsdp;
     GArray *tcpalog;
     GArray *vmgenid;
+    GArray *hardware_errors;
     BIOSLinker *linker;
 } AcpiBuildTables;
 
diff --git a/include/hw/acpi/hest_ghes.h b/include/hw/acpi/hest_ghes.h
new file mode 100644
index 0000000..0cadc2b
--- /dev/null
+++ b/include/hw/acpi/hest_ghes.h
@@ -0,0 +1,43 @@
+#ifndef ACPI_GHES_H
+#define ACPI_GHES_H
+
+#include "hw/acpi/bios-linker-loader.h"
+
+#define GHES_ERRORS_FW_CFG_FILE      "etc/hardware_errors"
+#define GHES_DATA_ADDR_FW_CFG_FILE      "etc/hardware_errors_addr"
+
+#define GAS_ADDRESS_OFFSET              4
+#define ERROR_STATUS_ADDRESS_OFFSET     20
+#define NOTIFICATION_STRUCTURE          32
+
+#define BFAPEI_OK   0
+#define BFAPEI_FAIL 1
+
+/* The max number of error source, the error sources
+ * are classified by notification type, below is the definition
+ * 0 - Polled
+ * 1 - External Interrupt
+ * 2 - Local Interrupt
+ * 3 - SCI
+ * 4 - NMI
+ * 5 - CMCI
+ * 6 - MCE
+ * 7 - GPIO-Signal
+ * 8 - ARMv8 SEA
+ * 9 - ARMv8 SEI
+ * 10 - External Interrupt - GSIV
+ */
+#define MAX_ERROR_SOURCE_COUNT_V6           11
+/* The max size in Bytes for one error block */
+#define MAX_RAW_DATA_LENGTH                 0x1000
+
+typedef struct GhesErrorState {
+    uint64_t physical_addr;
+    uint64_t ghes_addr_le[8];
+} GhesErrorState;
+
+void ghes_build_acpi(GArray *table_data, GArray *hardware_error,
+                            BIOSLinker *linker);
+void ghes_add_fw_cfg(FWCfgState *s, GArray *guid);
+void ghes_update_guest(uint32_t notify, uint64_t physical_address);
+#endif
-- 
1.8.3.1

^ permalink raw reply related

* [PATCH] net: phy: Allow BCM5481x PHYs to setup internal TX/RX clock delay
From: Abhishek Shah @ 2017-04-30  5:34 UTC (permalink / raw)
  To: linux-arm-kernel

This patch allows users to enable/disable internal TX and/or RX
clock delay for BCM5481x series PHYs so as to satisfy RGMII timing
specifications.

On a particular platform, whether TX and/or RX clock delay is required
depends on how PHY connected to the MAC IP. This requirement can be
specified through "phy-mode" property in the platform device tree.

Signed-off-by: Abhishek Shah <abhishek.shah@broadcom.com>
---
 drivers/net/phy/broadcom.c | 69 ++++++++++++++++++++++------------------------
 1 file changed, 33 insertions(+), 36 deletions(-)

diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c
index 9cd8b27..a32dc5d 100644
--- a/drivers/net/phy/broadcom.c
+++ b/drivers/net/phy/broadcom.c
@@ -74,27 +74,40 @@ static int bcm54612e_config_init(struct phy_device *phydev)
 	return 0;
 }
 
-static int bcm54810_config(struct phy_device *phydev)
+static int bcm5481x_config(struct phy_device *phydev)
 {
 	int rc, val;
 
-	val = bcm_phy_read_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL);
-	val &= ~BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN;
-	rc = bcm_phy_write_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL,
-			       val);
-	if (rc < 0)
-		return rc;
-
+	/* handling PHY's internal RX clock delay */
 	val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
-	val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN;
 	val |= MII_BCM54XX_AUXCTL_MISC_WREN;
+	if (phydev->interface == PHY_INTERFACE_MODE_RGMII ||
+	    phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
+		/* Disable RGMII RXC-RXD skew */
+		val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN;
+	}
+	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
+	    phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
+		/* Enable RGMII RXC-RXD skew */
+		val |= MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN;
+	}
 	rc = bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
 				  val);
 	if (rc < 0)
 		return rc;
 
+	/* handling PHY's internal TX clock delay */
 	val = bcm_phy_read_shadow(phydev, BCM54810_SHD_CLK_CTL);
-	val &= ~BCM54810_SHD_CLK_CTL_GTXCLK_EN;
+	if (phydev->interface == PHY_INTERFACE_MODE_RGMII ||
+	    phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
+		/* Disable internal TX clock delay */
+		val &= ~BCM54810_SHD_CLK_CTL_GTXCLK_EN;
+	}
+	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
+	    phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
+		/* Enable internal TX clock delay */
+		val |= BCM54810_SHD_CLK_CTL_GTXCLK_EN;
+	}
 	rc = bcm_phy_write_shadow(phydev, BCM54810_SHD_CLK_CTL, val);
 	if (rc < 0)
 		return rc;
@@ -244,7 +257,7 @@ static void bcm54xx_adjust_rxrefclk(struct phy_device *phydev)
 
 static int bcm54xx_config_init(struct phy_device *phydev)
 {
-	int reg, err;
+	int reg, err, val;
 
 	reg = phy_read(phydev, MII_BCM54XX_ECR);
 	if (reg < 0)
@@ -283,8 +296,14 @@ static int bcm54xx_config_init(struct phy_device *phydev)
 		if (err)
 			return err;
 	} else if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54810) {
-		err = bcm54810_config(phydev);
-		if (err)
+		/* For BCM54810, we need to disable BroadR-Reach function */
+		val = bcm_phy_read_exp(phydev,
+				       BCM54810_EXP_BROADREACH_LRE_MISC_CTL);
+		val &= ~BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN;
+		err = bcm_phy_write_exp(phydev,
+					BCM54810_EXP_BROADREACH_LRE_MISC_CTL,
+					val);
+		if (err < 0)
 			return err;
 	}
 
@@ -392,29 +411,7 @@ static int bcm5481_config_aneg(struct phy_device *phydev)
 	ret = genphy_config_aneg(phydev);
 
 	/* Then we can set up the delay. */
-	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
-		u16 reg;
-
-		/*
-		 * There is no BCM5481 specification available, so down
-		 * here is everything we know about "register 0x18". This
-		 * at least helps BCM5481 to successfully receive packets
-		 * on MPC8360E-RDK board. Peter Barada <peterb@logicpd.com>
-		 * says: "This sets delay between the RXD and RXC signals
-		 * instead of using trace lengths to achieve timing".
-		 */
-
-		/* Set RDX clk delay. */
-		reg = 0x7 | (0x7 << 12);
-		phy_write(phydev, 0x18, reg);
-
-		reg = phy_read(phydev, 0x18);
-		/* Set RDX-RXC skew. */
-		reg |= (1 << 8);
-		/* Write bits 14:0. */
-		reg |= (1 << 15);
-		phy_write(phydev, 0x18, reg);
-	}
+	bcm5481x_config(phydev);
 
 	if (of_property_read_bool(np, "enet-phy-lane-swap")) {
 		/* Lane Swap - Undocumented register...magic! */
-- 
2.7.4

^ permalink raw reply related

* Updating kernel.org cross compilers?
From: Segher Boessenkool @ 2017-04-30  5:29 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <92b5ff36-ad2b-10bc-de4f-4774babd9625@arm.com>

Hi,

On Wed, Apr 26, 2017 at 03:14:16PM +0100, Andre Przywara wrote:
> It seems that many people (even outside the Linux kernel community) use
> the cross compilers provided at kernel.org/pub/tools/crosstool.
> The latest compiler I find there is 4.9.0, which celebrated its third
> birthday at the weekend, also has been superseded by 4.9.4 meanwhile.
> 
> So I took Segher's buildall scripts from [1] and threw binutils 2.28 and
> GCC 6.3.0 at them.

Happy to see people are still using these!

> After removing --enable-sjlj-exceptions from build-gcc

This was needed to build some targets.  It does prevent aarch64 from
building without patch.

> and adding --disable-multilib (for building x86-64 on a x86-64
> box without 32-bit libs)

Why is this needed?  What error are you seeing.

> I was able to build (bare-metal) toolchains for
> all architectures except arc, m68k, tilegx and tilepro.

arc needs a more recent GCC; the other probably as well.  GCC 7 should
be out very soon, you probably want to wait for that :-)

> $ ./buildall --toolchain
> $ PATH=$PATH:/opt/cross/bin
> $ ./buildall --kernel

You should have the target dir in your PATH before doing anything else.
Is this not documented?  Hrm I guess not, let me fix that.

> And what is a good build setup, so that the binaries run on as many
> systems as possible?

Run contrib/download_prerequisites in the gcc source dir: this will
make GMP, MPFR, MPC statically linked, and use a version of each that
is known to work (and work correctly).

> [1] http://git.infradead.org/users/segher/buildall.git/

I'll push some changes that make aarch64 work out-of-the-box in a
minute.  It does some other things as well (e.g., make ia64 work again
after *that* change); more changes are still needed to make sh4 work
without patches.


Segher

^ permalink raw reply

* [PATCH v1 1/2] PCI: mediatek: Add Mediatek PCIe host controller support
From: kbuild test robot @ 2017-04-30  4:25 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1493370634-7038-2-git-send-email-ryder.lee@mediatek.com>

Hi Ryder,

[auto build test ERROR on pci/next]
[also build test ERROR on v4.11-rc8 next-20170428]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Ryder-Lee/Add-PCIe-host-driver-support-for-Mediatek-SoCs/20170429-181028
base:   https://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci.git next
config: xtensa-allmodconfig (attached as .config)
compiler: xtensa-linux-gcc (GCC) 4.9.0
reproduce:
        wget https://raw.githubusercontent.com/01org/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=xtensa 

All errors (new ones prefixed by >>):

   drivers/built-in.o: In function `pci_host_bridge_of_msi_domain':
>> (.text+0x2f154): undefined reference to `pci_fixup_irqs'
   drivers/built-in.o: In function `mtk_pcie_probe':
   pcie-mediatek.c:(.text+0x2f956): undefined reference to `pci_fixup_irqs'

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
-------------- next part --------------
A non-text attachment was scrubbed...
Name: .config.gz
Type: application/gzip
Size: 49161 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20170430/e036f722/attachment-0001.gz>

^ permalink raw reply

* Updating kernel.org cross compilers?
From: Guenter Roeck @ 2017-04-30  3:37 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <92b5ff36-ad2b-10bc-de4f-4774babd9625@arm.com>

On 04/26/2017 07:14 AM, Andre Przywara wrote:
> Hi!
>
> (Tony: I've seen you redirecting to "Chris" in an older email, but the
> web archive doesn't have his email address)
>
> It seems that many people (even outside the Linux kernel community) use
> the cross compilers provided at kernel.org/pub/tools/crosstool.
> The latest compiler I find there is 4.9.0, which celebrated its third
> birthday at the weekend, also has been superseded by 4.9.4 meanwhile.
>
> So I took Segher's buildall scripts from [1] and threw binutils 2.28 and
> GCC 6.3.0 at them. After removing --enable-sjlj-exceptions from
> build-gcc and adding --disable-multilib (for building x86-64 on a x86-64
> box without 32-bit libs) I was able to build (bare-metal) toolchains for
> all architectures except arc, m68k, tilegx and tilepro.
> Now my understanding is that a baremetal/stage 1 compiler should be
> build with "all-gcc" instead of the implicit "all" make target, and
> "install-gcc" instead of "install". And indeed adding this to build-gcc
> makes all toolchains build now - except arc, which needs an explicit
> "--with-cpu=arc700" on the GCC configure command line.
>
> So after those changes, the sequence:
> $ ./buildall --toolchain
> $ PATH=$PATH:/opt/cross/bin
> $ ./buildall --kernel
> worked reasonably well for me (binutils 2.28, GCC 6.3.0, Linux 4.11-rc8
> on an Intel host with Ubuntu 14.04.5). Just tilegx/pro is still broken
> due to toolchain issues.
>
Those need libgcc, and to build libgcc you'll have to install the kernel
header files. Same is true for cris (and possibly others).

Also, crisv32 builds as well.

> So I wonder what the process is to get those compilers updated?
>
If you find out let me know.

Guenter

> And what is a good build setup, so that the binaries run on as many
> systems as possible?
>
> Also the web page (https://www.kernel.org/pub/tools/crosstool) seems to
> only link outdated builds (4.6.3, mostly), is that on purpose?
>
> Cheers,
> Andre.
>
> [1] http://git.infradead.org/users/segher/buildall.git/
>

^ permalink raw reply

* drivers:soc:fsl:qbman:qman.c: unsigned long jiffies value
From: Karim Eshapa @ 2017-04-30  1:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1493508775.25397.26.camel@buserror.net>

On Sat, 29 Apr 2017 18:32:55 -0500, Scott Wood wrote:
>On Sat, 2017-04-29 at 22:43 +0200, Karim Eshapa wrote:
>
>> unsigned long jiffies value sorry for that.
>>
> You mean unsigned long msecs?
>

Yes, I mean usecs. 

>>
>> Signed-off-by: Karim Eshapa <karim.eshapa@gmail.com>
>> ---
>>  drivers/soc/fsl/qbman/qman.c | 2 +-
>>  1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/drivers/soc/fsl/qbman/qman.c b/drivers/soc/fsl/qbman/qman.c
>> index e0df4d1..6e1a44a 100644
>> --- a/drivers/soc/fsl/qbman/qman.c
>> +++ b/drivers/soc/fsl/qbman/qman.c
>> @@ -1084,7 +1084,7 @@ static int drain_mr_fqrni(struct qm_portal *p)
>>                * entries well before the ring has been fully consumed, so
>>                * we're being *really* paranoid here.
>>                */
>> -             unsigned int udel_time = jiffies_to_usecs(10000);
>> +             unsigned long udel_time = jiffies_to_usecs(10000);
>>  
>>               usleep_range(udel_time/2, udel_time);
>>               msg = qm_mr_current(p);

>If unsigned int isn't big enough, then unsigned long won't be either on 32-
>bit.  With such a long delay why not use msleep()?
>

I agree with you in long int.
After looking at Documentation/timers/timers-howto.txt I think
the msleep() is better as we actually have long delay.
may be we can use jiffies_to_msecs() with msleep() in case of we still have 
this large jiffies difference.

>As for the previous patch[1], you're halving the minimum timeout which may not
>be correct.
>
>

For the minimum timeout, I've read the following comments.

		 /*
                  * if MR was full and h/w had other FQRNI entries to produce, we
                  * need to allow it time to produce those entries once the
                  * existing entries are consumed. A worst-case situation
                  * (fully-loaded system) means h/w sequencers may have to do 3-4
                  * other things before servicing the portal's MR pump, each of
                  * which (if slow) may take ~50 qman cycles (which is ~200
                  * processor cycles). So rounding up and then multiplying this
                  * worst-case estimate by a factor of 10, just to be
                  * ultra-paranoid, goes as high as 10,000 cycles. NB, we consume
                  * one entry at a time, so h/w has an opportunity to produce new
                  * entries well before the ring has been fully consumed, so
                  * we're being *really* paranoid here.
		  */
		  u64 now, then = jiffies;
		
		do {
	                now = jiffies;
                 } while ((then + 10000) > now);  

He needs to guarantee certain action so, he made a very large factor of saftey
therefore I've used sleep in range with approximate delay. But we still need 
the driver owner to define appropriate value to put.

>[1] When fixing a patch you've already posted that hasn't yet been applied,
>send a replacement (v2) patch rather than a separate fix.
>

Thanks so much, I'm just newbies :)


Karim   

^ permalink raw reply

* [PATCH] drivers:soc:fsl:qbman:qman.c: unsigned long jiffies value.
From: Scott Wood @ 2017-04-29 23:32 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1493498620-9975-1-git-send-email-karim.eshapa@gmail.com>

On Sat, 2017-04-29 at 22:43 +0200, Karim Eshapa wrote:
> unsigned long jiffies value sorry for that.

You mean unsigned long msecs?

> 
> Signed-off-by: Karim Eshapa <karim.eshapa@gmail.com>
> ---
> ?drivers/soc/fsl/qbman/qman.c | 2 +-
> ?1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/soc/fsl/qbman/qman.c b/drivers/soc/fsl/qbman/qman.c
> index e0df4d1..6e1a44a 100644
> --- a/drivers/soc/fsl/qbman/qman.c
> +++ b/drivers/soc/fsl/qbman/qman.c
> @@ -1084,7 +1084,7 @@ static int drain_mr_fqrni(struct qm_portal *p)
> ?		?* entries well before the ring has been fully consumed, so
> ?		?* we're being *really* paranoid here.
> ?		?*/
> -		unsigned int udel_time = jiffies_to_usecs(10000);
> +		unsigned long udel_time = jiffies_to_usecs(10000);
> ?
> ?		usleep_range(udel_time/2, udel_time);
> ?		msg = qm_mr_current(p);

If unsigned int isn't big enough, then unsigned long won't be either on 32-
bit.  With such a long delay why not use msleep()?

As for the previous patch[1], you're halving the minimum timeout which may not
be correct.

For the NXP people: Is there *really* no better way to handle this than
waiting for so long?  Nothing that can be checked to exit the loop early (at
least, you could exit early if there is more work to do so only the final
iteration takes the full timeout)?  And why is the desired timeout specified
in jiffies, the duration of which can change based on kernel config and
doesn't reflect anything about the hardware?

-Scott

[1] When fixing a patch you've already posted that hasn't yet been applied,
send a replacement (v2) patch rather than a separate fix.

^ permalink raw reply

* [PATCH v1 1/2] PCI: mediatek: Add Mediatek PCIe host controller support
From: kbuild test robot @ 2017-04-29 23:28 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1493370634-7038-2-git-send-email-ryder.lee@mediatek.com>

Hi Ryder,

[auto build test ERROR on pci/next]
[also build test ERROR on v4.11-rc8 next-20170428]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Ryder-Lee/Add-PCIe-host-driver-support-for-Mediatek-SoCs/20170429-181028
base:   https://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci.git next
config: s390-allmodconfig (attached as .config)
compiler: s390x-linux-gnu-gcc (Debian 6.1.1-9) 6.1.1 20160705
reproduce:
        wget https://raw.githubusercontent.com/01org/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=s390 

All errors (new ones prefixed by >>):

   drivers/built-in.o: In function `mtk_pcie_probe':
>> drivers/pci/host/.tmp_gl_pcie-mediatek.o:(.text+0x5b68c): undefined reference to `pci_fixup_irqs'

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
-------------- next part --------------
A non-text attachment was scrubbed...
Name: .config.gz
Type: application/gzip
Size: 45164 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20170430/27e2afde/attachment-0001.gz>

^ permalink raw reply

* [PATCH] drivers:soc:fsl:qbman:qman.c: unsigned long jiffies value.
From: Karim Eshapa @ 2017-04-29 20:43 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1493495164-8658-1-git-send-email-karim.eshapa@gmail.com>

unsigned long jiffies value sorry for that.

Signed-off-by: Karim Eshapa <karim.eshapa@gmail.com>
---
 drivers/soc/fsl/qbman/qman.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/soc/fsl/qbman/qman.c b/drivers/soc/fsl/qbman/qman.c
index e0df4d1..6e1a44a 100644
--- a/drivers/soc/fsl/qbman/qman.c
+++ b/drivers/soc/fsl/qbman/qman.c
@@ -1084,7 +1084,7 @@ static int drain_mr_fqrni(struct qm_portal *p)
 		 * entries well before the ring has been fully consumed, so
 		 * we're being *really* paranoid here.
 		 */
-		unsigned int udel_time = jiffies_to_usecs(10000);
+		unsigned long udel_time = jiffies_to_usecs(10000);
 
 		usleep_range(udel_time/2, udel_time);
 		msg = qm_mr_current(p);
-- 
2.7.4

^ permalink raw reply related

* [PATCH] drivers:soc:fsl:qbman:qman.c: Sleep instead of stuck hacking jiffies.
From: Karim Eshapa @ 2017-04-29 19:46 UTC (permalink / raw)
  To: linux-arm-kernel

Convert the jiffies into usecs then use it with usleep_range
such that instead of stuck doing nothing until action happens,
sleep with range improves responsiveness and power usage
and avoid hacking jiffies. it's used for approximate time.
You can check /kernel/time/timer.c.

Signed-off-by: Karim Eshapa <karim.eshapa@gmail.com>
---
 drivers/soc/fsl/qbman/qman.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/soc/fsl/qbman/qman.c b/drivers/soc/fsl/qbman/qman.c
index 6f509f6..e0df4d1 100644
--- a/drivers/soc/fsl/qbman/qman.c
+++ b/drivers/soc/fsl/qbman/qman.c
@@ -1084,11 +1084,9 @@ static int drain_mr_fqrni(struct qm_portal *p)
 		 * entries well before the ring has been fully consumed, so
 		 * we're being *really* paranoid here.
 		 */
-		u64 now, then = jiffies;
+		unsigned int udel_time = jiffies_to_usecs(10000);
 
-		do {
-			now = jiffies;
-		} while ((then + 10000) > now);
+		usleep_range(udel_time/2, udel_time);
 		msg = qm_mr_current(p);
 		if (!msg)
 			return 0;
-- 
2.7.4

^ permalink raw reply related

* [PATCH] crypto: stm32 - fix building as a module
From: Herbert Xu @ 2017-04-29 17:54 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170427110907.2515229-1-arnd@arndb.de>

On Thu, Apr 27, 2017 at 01:07:07PM +0200, Arnd Bergmann wrote:
> The names in the MODULE_DEVICE_TABLE and the actual array don't match:
> 
> drivers/crypto/stm32/stm32_crc32.c:309:21: error: 'sti_dt_ids' undeclared here (not in a function); did you mean 'stm32_dt_ids'?
> 
> This changes the reference that was evidently copied incorrectly from
> another driver.
> 
> Fixes: b51dbe90912a ("crypto: stm32 - Support for STM32 CRC32 crypto module")
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>

This has already been fixed by

https://patchwork.kernel.org/patch/9698299/

Thanks,
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply

* [PATCH -next] crypto: stm32 - Fix OF module alias information
From: Herbert Xu @ 2017-04-29 17:54 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170425143542.1069-1-weiyj.lk@gmail.com>

On Tue, Apr 25, 2017 at 02:35:42PM +0000, Wei Yongjun wrote:
> From: Wei Yongjun <weiyongjun1@huawei.com>
> 
> The module alias information passed to MODULE_DEVICE_TABLE()
> should use stm32_dt_ids instead of undefined sti_dt_ids.
> 
> Fixes: b51dbe90912a ("crypto: stm32 - Support for STM32 CRC32 crypto module")
> Signed-off-by: Wei Yongjun <weiyongjun1@huawei.com>

Patch applied.  Thanks.
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply

* [PATCH v2] drm/rockchip: Set line flag config register in vop_crtc_enable
From: jeffy @ 2017-04-29 13:11 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170428150317.tpnj6obddfz5dzng@art_vandelay>

Hi Sean,

On 04/28/2017 11:03 PM, Sean Paul wrote:
> On Fri, Apr 28, 2017 at 03:37:47PM +0800, Jeffy Chen wrote:
>> We need to set vop config done after update line flag config, it's a
>> new requirement for chips newer than rk3368.
>>
>> Since we would only use line flag irq for vact_end, let's move it to
>> vop_crtc_enable.
>>
>> v2: Remove unused check and variables.
>
> Hi Jeffy,
> v1 was already applied. Please send a follow-on patch to clean this up.
Ok, will do.
>
> Sean
>
>>
>> Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
>>
>> ---
>>
>> Changes in v2:
>> Remove unused check and variables.
>>
>>   drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 14 +++-----------
>>   drivers/gpu/drm/rockchip/rockchip_drm_drv.h     |  3 +--
>>   drivers/gpu/drm/rockchip/rockchip_drm_vop.c     | 20 +++++++++-----------
>>   3 files changed, 13 insertions(+), 24 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
>> index d8fa7a9..1bccd82 100644
>> --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
>> +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
>> @@ -104,26 +104,18 @@ static void analogix_dp_psr_work(struct work_struct *work)
>>   {
>>   	struct rockchip_dp_device *dp =
>>   				container_of(work, typeof(*dp), psr_work);
>> -	struct drm_crtc *crtc = dp->encoder.crtc;
>> -	int psr_state = dp->psr_state;
>> -	int vact_end;
>>   	int ret;
>>   	unsigned long flags;
>>
>> -	if (!crtc)
>> -		return;
>> -
>> -	vact_end = crtc->mode.vtotal - crtc->mode.vsync_start + crtc->mode.vdisplay;
>> -
>> -	ret = rockchip_drm_wait_line_flag(dp->encoder.crtc, vact_end,
>> -					  PSR_WAIT_LINE_FLAG_TIMEOUT_MS);
>> +	ret = rockchip_drm_wait_vact_end(dp->encoder.crtc,
>> +					 PSR_WAIT_LINE_FLAG_TIMEOUT_MS);
>>   	if (ret) {
>>   		dev_err(dp->dev, "line flag interrupt did not arrive\n");
>>   		return;
>>   	}
>>
>>   	spin_lock_irqsave(&dp->psr_lock, flags);
>> -	if (psr_state == EDP_VSC_PSR_STATE_ACTIVE)
>> +	if (dp->psr_state == EDP_VSC_PSR_STATE_ACTIVE)
>>   		analogix_dp_enable_psr(dp->dev);
>>   	else
>>   		analogix_dp_disable_psr(dp->dev);
>> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
>> index a48fcce..47905fa 100644
>> --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
>> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
>> @@ -62,8 +62,7 @@ int rockchip_drm_dma_attach_device(struct drm_device *drm_dev,
>>   				   struct device *dev);
>>   void rockchip_drm_dma_detach_device(struct drm_device *drm_dev,
>>   				    struct device *dev);
>> -int rockchip_drm_wait_line_flag(struct drm_crtc *crtc, unsigned int line_num,
>> -				unsigned int mstimeout);
>> +int rockchip_drm_wait_vact_end(struct drm_crtc *crtc, unsigned int mstimeout);
>>
>>   extern struct platform_driver cdn_dp_driver;
>>   extern struct platform_driver dw_hdmi_rockchip_pltfm_driver;
>> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
>> index 3f7a82d..40a5e6e 100644
>> --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
>> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
>> @@ -468,7 +468,7 @@ static bool vop_line_flag_irq_is_enabled(struct vop *vop)
>>   	return !!line_flag_irq;
>>   }
>>
>> -static void vop_line_flag_irq_enable(struct vop *vop, int line_num)
>> +static void vop_line_flag_irq_enable(struct vop *vop)
>>   {
>>   	unsigned long flags;
>>
>> @@ -477,7 +477,6 @@ static void vop_line_flag_irq_enable(struct vop *vop, int line_num)
>>
>>   	spin_lock_irqsave(&vop->irq_lock, flags);
>>
>> -	VOP_CTRL_SET(vop, line_flag_num[0], line_num);
>>   	VOP_INTR_SET_TYPE(vop, clear, LINE_FLAG_INTR, 1);
>>   	VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 1);
>>
>> @@ -981,6 +980,8 @@ static void vop_crtc_enable(struct drm_crtc *crtc)
>>   	VOP_CTRL_SET(vop, vact_st_end, val);
>>   	VOP_CTRL_SET(vop, vpost_st_end, val);
>>
>> +	VOP_CTRL_SET(vop, line_flag_num[0], vact_end);
>> +
>>   	clk_set_rate(vop->dclk, adjusted_mode->clock * 1000);
>>
>>   	VOP_CTRL_SET(vop, standby, 0);
>> @@ -1507,19 +1508,16 @@ static void vop_win_init(struct vop *vop)
>>   }
>>
>>   /**
>> - * rockchip_drm_wait_line_flag - acqiure the give line flag event
>> + * rockchip_drm_wait_vact_end
>>    * @crtc: CRTC to enable line flag
>> - * @line_num: interested line number
>>    * @mstimeout: millisecond for timeout
>>    *
>> - * Driver would hold here until the interested line flag interrupt have
>> - * happened or timeout to wait.
>> + * Wait for vact_end line flag irq or timeout.
>>    *
>>    * Returns:
>>    * Zero on success, negative errno on failure.
>>    */
>> -int rockchip_drm_wait_line_flag(struct drm_crtc *crtc, unsigned int line_num,
>> -				unsigned int mstimeout)
>> +int rockchip_drm_wait_vact_end(struct drm_crtc *crtc, unsigned int mstimeout)
>>   {
>>   	struct vop *vop = to_vop(crtc);
>>   	unsigned long jiffies_left;
>> @@ -1527,14 +1525,14 @@ int rockchip_drm_wait_line_flag(struct drm_crtc *crtc, unsigned int line_num,
>>   	if (!crtc || !vop->is_enabled)
>>   		return -ENODEV;
>>
>> -	if (line_num > crtc->mode.vtotal || mstimeout <= 0)
>> +	if (mstimeout <= 0)
>>   		return -EINVAL;
>>
>>   	if (vop_line_flag_irq_is_enabled(vop))
>>   		return -EBUSY;
>>
>>   	reinit_completion(&vop->line_flag_completion);
>> -	vop_line_flag_irq_enable(vop, line_num);
>> +	vop_line_flag_irq_enable(vop);
>>
>>   	jiffies_left = wait_for_completion_timeout(&vop->line_flag_completion,
>>   						   msecs_to_jiffies(mstimeout));
>> @@ -1547,7 +1545,7 @@ int rockchip_drm_wait_line_flag(struct drm_crtc *crtc, unsigned int line_num,
>>
>>   	return 0;
>>   }
>> -EXPORT_SYMBOL(rockchip_drm_wait_line_flag);
>> +EXPORT_SYMBOL(rockchip_drm_wait_vact_end);
>>
>>   static int vop_bind(struct device *dev, struct device *master, void *data)
>>   {
>> --
>> 2.1.4
>>
>

^ permalink raw reply

* [PATCH] drm/rockchip: analogix_dp: Remove unused check and variables
From: Jeffy Chen @ 2017-04-29 12:39 UTC (permalink / raw)
  To: linux-arm-kernel

Remove unused check and variables after:
drm/rockchip: Set line flag config register in vop_crtc_enable

Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>

---

 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 10 +---------
 1 file changed, 1 insertion(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index 9bfdbc6..1bccd82 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -104,17 +104,9 @@ static void analogix_dp_psr_work(struct work_struct *work)
 {
 	struct rockchip_dp_device *dp =
 				container_of(work, typeof(*dp), psr_work);
-	struct drm_crtc *crtc = dp->encoder.crtc;
-	int psr_state = dp->psr_state;
-	int vact_end;
 	int ret;
 	unsigned long flags;
 
-	if (!crtc)
-		return;
-
-	vact_end = crtc->mode.vtotal - crtc->mode.vsync_start + crtc->mode.vdisplay;
-
 	ret = rockchip_drm_wait_vact_end(dp->encoder.crtc,
 					 PSR_WAIT_LINE_FLAG_TIMEOUT_MS);
 	if (ret) {
@@ -123,7 +115,7 @@ static void analogix_dp_psr_work(struct work_struct *work)
 	}
 
 	spin_lock_irqsave(&dp->psr_lock, flags);
-	if (psr_state == EDP_VSC_PSR_STATE_ACTIVE)
+	if (dp->psr_state == EDP_VSC_PSR_STATE_ACTIVE)
 		analogix_dp_enable_psr(dp->dev);
 	else
 		analogix_dp_disable_psr(dp->dev);
-- 
2.1.4

^ permalink raw reply related

* [patch] propagating controls in libv4l2 was Re: support autofocus / autogain in libv4l2
From: Pavel Machek @ 2017-04-29  9:19 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170426082608.7dd52fbf@vento.lan>

Hi!

> > +	devices[index].subdev_fds[0] = SYS_OPEN("/dev/video_sensor", O_RDWR, 0);
> > +	devices[index].subdev_fds[1] = SYS_OPEN("/dev/video_focus", O_RDWR, 0);
> > +	devices[index].subdev_fds[2] = -1;
> 
> Hardcoding names here is not a good idea. Ideally, it should open
> the MC, using the newgen API, and parse the media graph.
> 
> The problem is that, even with newgen API, without the properties API
> you likely won't be able to write a generic parser. So, we need a
> plugin specific for OMAP3 (or at least some database that would teach
> a generic plugin about OMAP3 specifics).
> 
> I guess that the approach that Jacek was taken were very close to what
> a generic plugin would need:
> 	https://lwn.net/Articles/619449/
> 
> The last version of his patch set is here:
> 	https://patchwork.linuxtv.org/patch/37496/
> 
> I didn't review his patchset, but from what I saw, Sakari is the one
> that found some issues on v7.1 patchset.
> 
> Sakari,
> 
> Could you shed us a light about why this patchset was not merged?
> 
> Are there anything really bad at the code, or just minor issues that
> could be fixed later?
> 
> If it is the last case, perhaps we could merge the code, if this
> would make easier for Pavel to work on a N9 solution using the
> same approach.

It would be nice to get some solution here. Camera without libv4l
support is pretty much useless :-(.

									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 181 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20170429/5a448afb/attachment.sig>

^ permalink raw reply

* [PATCH v2 3/3] mtd: nand: fsmc: remove default timings
From: Thomas Petazzoni @ 2017-04-29  8:52 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1493455956-18362-1-git-send-email-thomas.petazzoni@free-electrons.com>

When timings are no longer provided by the Device Tree, we now use the
SDR timings specified by the NAND flash, and such SDR timings are always
provided. Therefore, it is no longer necessary to keep "default" timings
in the fmsc driver.

Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
 drivers/mtd/nand/fsmc_nand.c | 16 +---------------
 1 file changed, 1 insertion(+), 15 deletions(-)

diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c
index 442e4df..f58c912 100644
--- a/drivers/mtd/nand/fsmc_nand.c
+++ b/drivers/mtd/nand/fsmc_nand.c
@@ -303,26 +303,12 @@ static void fsmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
  * FSMC registers
  */
 static void fsmc_nand_setup(struct fsmc_nand_data *host,
-			    struct fsmc_nand_timings *timings)
+			    struct fsmc_nand_timings *tims)
 {
 	uint32_t value = FSMC_DEVTYPE_NAND | FSMC_ENABLE | FSMC_WAITON;
 	uint32_t tclr, tar, thiz, thold, twait, tset;
 	unsigned int bank = host->bank;
 	void __iomem *regs = host->regs_va;
-	struct fsmc_nand_timings *tims;
-	struct fsmc_nand_timings default_timings = {
-		.tclr	= FSMC_TCLR_1,
-		.tar	= FSMC_TAR_1,
-		.thiz	= FSMC_THIZ_1,
-		.thold	= FSMC_THOLD_4,
-		.twait	= FSMC_TWAIT_6,
-		.tset	= FSMC_TSET_0,
-	};
-
-	if (timings)
-		tims = host->dev_timings;
-	else
-		tims = &default_timings;
 
 	tclr = (tims->tclr & FSMC_TCLR_MASK) << FSMC_TCLR_SHIFT;
 	tar = (tims->tar & FSMC_TAR_MASK) << FSMC_TAR_SHIFT;
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 2/3] mtd: nand: fsmc: add support for SDR timings
From: Thomas Petazzoni @ 2017-04-29  8:52 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1493455956-18362-1-git-send-email-thomas.petazzoni@free-electrons.com>

Until now, the fsmc_nand driver was either using controller timings
specified in the Device Tree (through FSMC specific DT properties) or
alternatively default/fallback timings.

This commit implements support to use the timings advertised by the NAND
chip itself, by implementing the ->setup_data_interface() hook. To
preserve backward compatibility, if timings are specified in the Device
Tree, we use the timings from the Device Tree (and don't implement
->setup_data_interface).

Many thanks to Boris Brezillon for coming up with the logic to convert
the NAND chip timings into the timings expected by the FSMC controller.

Also, since the timings are now not only coming from the DT, the message
warning that default timings will be used is removed.

Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
 drivers/mtd/nand/fsmc_nand.c | 94 +++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 89 insertions(+), 5 deletions(-)

diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c
index 43108dd..442e4df 100644
--- a/drivers/mtd/nand/fsmc_nand.c
+++ b/drivers/mtd/nand/fsmc_nand.c
@@ -346,6 +346,88 @@ static void fsmc_nand_setup(struct fsmc_nand_data *host,
 			FSMC_NAND_REG(regs, bank, ATTRIB));
 }
 
+static int fsmc_calc_timings(struct fsmc_nand_data *host,
+			     const struct nand_sdr_timings *sdrt,
+			     struct fsmc_nand_timings *tims)
+{
+	unsigned long hclk = clk_get_rate(host->clk);
+	unsigned long hclkn = NSEC_PER_SEC / hclk;
+	uint32_t thiz, thold, twait, tset;
+
+	if (sdrt->tRC_min < 30000)
+		return -EOPNOTSUPP;
+
+	tims->tar = DIV_ROUND_UP(sdrt->tAR_min / 1000, hclkn) - 1;
+	if (tims->tar > FSMC_TAR_MASK)
+		tims->tar = FSMC_TAR_MASK;
+	tims->tclr = DIV_ROUND_UP(sdrt->tCLR_min / 1000, hclkn) - 1;
+	if (tims->tclr > FSMC_TCLR_MASK)
+		tims->tclr = FSMC_TCLR_MASK;
+
+	thiz = sdrt->tCS_min - sdrt->tWP_min;
+	tims->thiz = DIV_ROUND_UP(thiz / 1000, hclkn);
+
+	thold = sdrt->tDH_min;
+	if (thold < sdrt->tCH_min)
+		thold = sdrt->tCH_min;
+	if (thold < sdrt->tCLH_min)
+		thold = sdrt->tCLH_min;
+	if (thold < sdrt->tWH_min)
+		thold = sdrt->tWH_min;
+	if (thold < sdrt->tALH_min)
+		thold = sdrt->tALH_min;
+	if (thold < sdrt->tREH_min)
+		thold = sdrt->tREH_min;
+	tims->thold = DIV_ROUND_UP(thold / 1000, hclkn);
+	if (tims->thold == 0)
+		tims->thold = 1;
+	else if (tims->thold > FSMC_THOLD_MASK)
+		tims->thold = FSMC_THOLD_MASK;
+
+	twait = max(sdrt->tRP_min, sdrt->tWP_min);
+	tims->twait = DIV_ROUND_UP(twait / 1000, hclkn) - 1;
+	if (tims->twait == 0)
+		tims->twait = 1;
+	else if (tims->twait > FSMC_TWAIT_MASK)
+		tims->twait = FSMC_TWAIT_MASK;
+
+	tset = max(sdrt->tCS_min - sdrt->tWP_min,
+		   sdrt->tCEA_max - sdrt->tREA_max);
+	tims->tset = DIV_ROUND_UP(tset / 1000, hclkn) - 1;
+	if (tims->tset == 0)
+		tims->tset = 1;
+	else if (tims->tset > FSMC_TSET_MASK)
+		tims->tset = FSMC_TSET_MASK;
+
+	return 0;
+}
+
+static int fsmc_setup_data_interface(struct mtd_info *mtd,
+				     const struct nand_data_interface *conf,
+				     bool check_only)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct fsmc_nand_data *host = nand_get_controller_data(nand);
+	struct fsmc_nand_timings tims;
+	const struct nand_sdr_timings *sdrt;
+	int ret;
+
+	sdrt = nand_get_sdr_timings(conf);
+	if (IS_ERR(sdrt))
+		return PTR_ERR(sdrt);
+
+	ret = fsmc_calc_timings(host, sdrt, &tims);
+	if (ret)
+		return ret;
+
+	if (check_only)
+		return 0;
+
+	fsmc_nand_setup(host, &tims);
+
+	return 0;
+}
+
 /*
  * fsmc_enable_hwecc - Enables Hardware ECC through FSMC registers
  */
@@ -798,10 +880,8 @@ static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
 		return -ENOMEM;
 	ret = of_property_read_u8_array(np, "timings", (u8 *)host->dev_timings,
 						sizeof(*host->dev_timings));
-	if (ret) {
-		dev_info(&pdev->dev, "No timings in dts specified, using default timings!\n");
+	if (ret)
 		host->dev_timings = NULL;
-	}
 
 	/* Set default NAND bank to 0 */
 	host->bank = 0;
@@ -935,7 +1015,10 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
 		break;
 	}
 
-	fsmc_nand_setup(host, host->dev_timings);
+	if (host->dev_timings)
+		fsmc_nand_setup(host, host->dev_timings);
+	else
+		nand->setup_data_interface = fsmc_setup_data_interface;
 
 	if (AMBA_REV_BITS(host->pid) >= 8) {
 		nand->ecc.read_page = fsmc_read_page_hwecc;
@@ -1073,7 +1156,8 @@ static int fsmc_nand_resume(struct device *dev)
 	struct fsmc_nand_data *host = dev_get_drvdata(dev);
 	if (host) {
 		clk_prepare_enable(host->clk);
-		fsmc_nand_setup(host, host->dev_timings);
+		if (host->dev_timings)
+			fsmc_nand_setup(host, host->dev_timings);
 	}
 	return 0;
 }
-- 
2.7.4

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox