* [PATCH 1/2] powerpc: Add 64bit optimised memcmp
From: Anton Blanchard @ 2015-01-09 1:56 UTC (permalink / raw)
To: benh, paulus, mpe; +Cc: linuxppc-dev
I noticed ksm spending quite a lot of time in memcmp on a large
KVM box. The current memcmp loop is very unoptimised - byte at a
time compares with no loop unrolling. We can do much much better.
Optimise the loop in a few ways:
- Unroll the byte at a time loop
- For large (at least 32 byte) comparisons that are also 8 byte
aligned, use an unrolled modulo scheduled loop using 8 byte
loads. This is similar to our glibc memcmp.
A simple microbenchmark testing 10000000 iterations of an 8192 byte
memcmp was used to measure the performance:
baseline: 29.93 s
modified: 1.70 s
Just over 17x faster.
Signed-off-by: Anton Blanchard <anton@samba.org>
---
arch/powerpc/lib/Makefile | 3 +-
arch/powerpc/lib/memcmp_64.S | 233 +++++++++++++++++++++++++++++++++++++++++++
arch/powerpc/lib/string.S | 2 +
3 files changed, 237 insertions(+), 1 deletion(-)
create mode 100644 arch/powerpc/lib/memcmp_64.S
diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile
index 1b01159..5526156 100644
--- a/arch/powerpc/lib/Makefile
+++ b/arch/powerpc/lib/Makefile
@@ -15,7 +15,8 @@ obj-$(CONFIG_PPC32) += div64.o copy_32.o
obj-$(CONFIG_PPC64) += copypage_64.o copyuser_64.o \
usercopy_64.o mem_64.o hweight_64.o \
- copyuser_power7.o string_64.o copypage_power7.o
+ copyuser_power7.o string_64.o copypage_power7.o \
+ memcmp_64.o
ifeq ($(CONFIG_GENERIC_CSUM),)
obj-y += checksum_$(CONFIG_WORD_SIZE).o
obj-$(CONFIG_PPC64) += checksum_wrappers_64.o
diff --git a/arch/powerpc/lib/memcmp_64.S b/arch/powerpc/lib/memcmp_64.S
new file mode 100644
index 0000000..d71880b
--- /dev/null
+++ b/arch/powerpc/lib/memcmp_64.S
@@ -0,0 +1,233 @@
+/*
+ * Author: Author: Anton Blanchard <anton@au.ibm.com>
+ * Copyright 2015 IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <asm/ppc_asm.h>
+
+#define off8 r6
+#define off16 r7
+#define off24 r8
+
+#define rA r9
+#define rB r10
+#define rC r11
+#define rD r27
+#define rE r28
+#define rF r29
+#define rG r30
+#define rH r31
+
+#ifdef __LITTLE_ENDIAN__
+#define LD ldbrx
+#else
+#define LD ldx
+#endif
+
+_GLOBAL(memcmp)
+ cmpdi cr1,r5,0
+
+ /* Use the short loop if both strings are not 8B aligned */
+ or r6,r3,r4
+ rldicl. r6,r6,0,(64-3)
+
+ /* Use the short loop if length is less than 32B */
+ cmpdi cr5,r5,31
+
+ beq cr1,.Lzero
+ bne .Lshort
+ bgt cr5,.Llong
+
+.Lshort:
+ mtctr r5
+
+1: lbz rA,0(r3)
+ lbz rB,0(r4)
+ subf. rC,rB,rA
+ bne .Lnon_zero
+ bdz .Lzero
+
+ lbz rA,1(r3)
+ lbz rB,1(r4)
+ subf. rC,rB,rA
+ bne .Lnon_zero
+ bdz .Lzero
+
+ lbz rA,2(r3)
+ lbz rB,2(r4)
+ subf. rC,rB,rA
+ bne .Lnon_zero
+ bdz .Lzero
+
+ lbz rA,3(r3)
+ lbz rB,3(r4)
+ subf. rC,rB,rA
+ bne .Lnon_zero
+
+ addi r3,r3,4
+ addi r4,r4,4
+
+ bdnzt eq,1b
+
+.Lzero:
+ li r3,0
+ blr
+
+.Lnon_zero:
+ mr r3,rC
+ blr
+
+.Llong:
+ li off8,8
+ li off16,16
+ li off24,24
+
+ std r31,-8(r1)
+ std r30,-16(r1)
+ std r29,-24(r1)
+ std r28,-32(r1)
+ std r27,-40(r1)
+
+ srdi r0,r5,5
+ mtctr r0
+ andi. r5,r5,31
+
+ LD rA,0,r3
+ LD rB,0,r4
+
+ LD rC,off8,r3
+ LD rD,off8,r4
+
+ LD rE,off16,r3
+ LD rF,off16,r4
+
+ LD rG,off24,r3
+ LD rH,off24,r4
+ cmpld cr0,rA,rB
+
+ addi r3,r3,32
+ addi r4,r4,32
+
+ bdz .Lfirst32
+
+ LD rA,0,r3
+ LD rB,0,r4
+ cmpld cr1,rC,rD
+
+ LD rC,off8,r3
+ LD rD,off8,r4
+ cmpld cr5,rE,rF
+
+ LD rE,off16,r3
+ LD rF,off16,r4
+ cmpld cr6,rG,rH
+ bne cr0,.LcmpAB
+
+ LD rG,off24,r3
+ LD rH,off24,r4
+ cmpld cr0,rA,rB
+ bne cr1,.LcmpCD
+
+ addi r3,r3,32
+ addi r4,r4,32
+
+ bdz .Lsecond32
+
+ .balign 16
+
+1: LD rA,0,r3
+ LD rB,0,r4
+ cmpld cr1,rC,rD
+ bne cr5,.LcmpEF
+
+ LD rC,off8,r3
+ LD rD,off8,r4
+ cmpld cr5,rE,rF
+ bne cr6,.LcmpGH
+
+ LD rE,off16,r3
+ LD rF,off16,r4
+ cmpld cr6,rG,rH
+ bne cr0,.LcmpAB
+
+ LD rG,off24,r3
+ LD rH,off24,r4
+ cmpld cr0,rA,rB
+ bne cr1,.LcmpCD
+
+ addi r3,r3,32
+ addi r4,r4,32
+
+ bdnz 1b
+
+.Lsecond32:
+ cmpld cr1,rC,rD
+ bne cr5,.LcmpEF
+
+ cmpld cr5,rE,rF
+ bne cr6,.LcmpGH
+
+ cmpld cr6,rG,rH
+ bne cr0,.LcmpAB
+
+ bne cr1,.LcmpCD
+ bne cr5,.LcmpEF
+ bne cr6,.LcmpGH
+
+.Ltail:
+ ld r31,-8(r1)
+ ld r30,-16(r1)
+ ld r29,-24(r1)
+ ld r28,-32(r1)
+ ld r27,-40(r1)
+
+ cmpdi r5,0
+ beq .Lzero
+ b .Lshort
+
+.Lfirst32:
+ cmpld cr1,rC,rD
+ cmpld cr5,rE,rF
+ cmpld cr6,rG,rH
+
+ bne cr0,.LcmpAB
+ bne cr1,.LcmpCD
+ bne cr5,.LcmpEF
+ bne cr6,.LcmpGH
+
+ b .Ltail
+
+.LcmpAB:
+ li r3,1
+ bgt cr0,.Lout
+ li r3,-1
+ b .Lout
+
+.LcmpCD:
+ li r3,1
+ bgt cr1,.Lout
+ li r3,-1
+ b .Lout
+
+.LcmpEF:
+ li r3,1
+ bgt cr5,.Lout
+ li r3,-1
+ b .Lout
+
+.LcmpGH:
+ li r3,1
+ bgt cr6,.Lout
+ li r3,-1
+
+.Lout:
+ ld r31,-8(r1)
+ ld r30,-16(r1)
+ ld r29,-24(r1)
+ ld r28,-32(r1)
+ ld r27,-40(r1)
+ blr
diff --git a/arch/powerpc/lib/string.S b/arch/powerpc/lib/string.S
index 1b5a0a0..c80fb49 100644
--- a/arch/powerpc/lib/string.S
+++ b/arch/powerpc/lib/string.S
@@ -93,6 +93,7 @@ _GLOBAL(strlen)
subf r3,r3,r4
blr
+#ifdef CONFIG_PPC32
_GLOBAL(memcmp)
PPC_LCMPI 0,r5,0
beq- 2f
@@ -106,6 +107,7 @@ _GLOBAL(memcmp)
blr
2: li r3,0
blr
+#endif
_GLOBAL(memchr)
PPC_LCMPI 0,r5,0
--
2.1.0
^ permalink raw reply related
* [PATCH 2/2] powerpc: Add memcmp testcase
From: Anton Blanchard @ 2015-01-09 1:56 UTC (permalink / raw)
To: benh, paulus, mpe; +Cc: linuxppc-dev
In-Reply-To: <1420768591-6831-1-git-send-email-anton@samba.org>
Add a testcase for the new ppc64 memcmp.
Signed-off-by: Anton Blanchard <anton@samba.org>
---
.../testing/selftests/powerpc/stringloops/Makefile | 21 +++++
.../selftests/powerpc/stringloops/asm/ppc_asm.h | 7 ++
.../selftests/powerpc/stringloops/memcmp_64.S | 1 +
.../selftests/powerpc/stringloops/test_memcmp.c | 103 +++++++++++++++++++++
4 files changed, 132 insertions(+)
create mode 100644 tools/testing/selftests/powerpc/stringloops/Makefile
create mode 100644 tools/testing/selftests/powerpc/stringloops/asm/ppc_asm.h
create mode 120000 tools/testing/selftests/powerpc/stringloops/memcmp_64.S
create mode 100644 tools/testing/selftests/powerpc/stringloops/test_memcmp.c
diff --git a/tools/testing/selftests/powerpc/stringloops/Makefile b/tools/testing/selftests/powerpc/stringloops/Makefile
new file mode 100644
index 0000000..159a299
--- /dev/null
+++ b/tools/testing/selftests/powerpc/stringloops/Makefile
@@ -0,0 +1,21 @@
+# The loops are all 64-bit code
+CFLAGS += -m64
+CFLAGS += -I$(CURDIR)
+CFLAGS += -D SELFTEST
+
+PROGS := test_memcmp
+EXTRA_SOURCES := memcmp_64.S ../harness.c
+
+all: $(PROGS)
+
+$(PROGS): $(EXTRA_SOURCES)
+
+run_tests: all
+ @-for PROG in $(PROGS); do \
+ ./$$PROG; \
+ done;
+
+clean:
+ rm -f $(PROGS) *.o
+
+.PHONY: all run_tests clean
diff --git a/tools/testing/selftests/powerpc/stringloops/asm/ppc_asm.h b/tools/testing/selftests/powerpc/stringloops/asm/ppc_asm.h
new file mode 100644
index 0000000..11bece8
--- /dev/null
+++ b/tools/testing/selftests/powerpc/stringloops/asm/ppc_asm.h
@@ -0,0 +1,7 @@
+#include <ppc-asm.h>
+
+#ifndef r1
+#define r1 sp
+#endif
+
+#define _GLOBAL(A) FUNC_START(test_ ## A)
diff --git a/tools/testing/selftests/powerpc/stringloops/memcmp_64.S b/tools/testing/selftests/powerpc/stringloops/memcmp_64.S
new file mode 120000
index 0000000..9bc87e4
--- /dev/null
+++ b/tools/testing/selftests/powerpc/stringloops/memcmp_64.S
@@ -0,0 +1 @@
+../../../../../arch/powerpc/lib/memcmp_64.S
\ No newline at end of file
diff --git a/tools/testing/selftests/powerpc/stringloops/test_memcmp.c b/tools/testing/selftests/powerpc/stringloops/test_memcmp.c
new file mode 100644
index 0000000..17417dd
--- /dev/null
+++ b/tools/testing/selftests/powerpc/stringloops/test_memcmp.c
@@ -0,0 +1,103 @@
+#include <malloc.h>
+#include <stdlib.h>
+#include <string.h>
+#include "../utils.h"
+
+#define SIZE 256
+#define ITERATIONS 10000
+
+int test_memcmp(const void *s1, const void *s2, size_t n);
+
+/* test all offsets and lengths */
+static void test_one(char *s1, char *s2)
+{
+ unsigned long offset, size;
+
+ for (offset = 0; offset < SIZE; offset++) {
+ for (size = 0; size < (SIZE-offset); size++) {
+ int x, y;
+ unsigned long i;
+
+ y = memcmp(s1+offset, s2+offset, size);
+ x = test_memcmp(s1+offset, s2+offset, size);
+
+ if (((x ^ y) < 0) && /* Trick to compare sign */
+ ((x | y) != 0)) { /* check for zero */
+ printf("memcmp returned %d, should have returned %d (offset %ld size %ld)\n", x, y, offset, size);
+
+ for (i = offset; i < offset+size; i++)
+ printf("%02x ", s1[i]);
+ printf("\n");
+
+ for (i = offset; i < offset+size; i++)
+ printf("%02x ", s2[i]);
+ printf("\n");
+ abort();
+ }
+ }
+ }
+}
+
+static int testcase(void)
+{
+ char *s1;
+ char *s2;
+ unsigned long i;
+
+ s1 = memalign(128, SIZE);
+ if (!s1) {
+ perror("memalign");
+ exit(1);
+ }
+
+ s2 = memalign(128, SIZE);
+ if (!s2) {
+ perror("memalign");
+ exit(1);
+ }
+
+ srandom(1);
+
+ for (i = 0; i < ITERATIONS; i++) {
+ unsigned long j;
+ unsigned long change;
+
+ for (j = 0; j < SIZE; j++)
+ s1[j] = random();
+
+ memcpy(s2, s1, SIZE);
+
+ /* change one byte */
+ change = random() % SIZE;
+ s2[change] = random() & 0xff;
+
+ test_one(s1, s2);
+ }
+
+ srandom(1);
+
+ for (i = 0; i < ITERATIONS; i++) {
+ unsigned long j;
+ unsigned long change;
+
+ for (j = 0; j < SIZE; j++)
+ s1[j] = random();
+
+ memcpy(s2, s1, SIZE);
+
+ /* change multiple bytes, 1/8 of total */
+ for (j = 0; j < SIZE / 8; j++) {
+ change = random() % SIZE;
+ s2[change] = random() & 0xff;
+ }
+
+ test_one(s1, s2);
+ }
+
+ return 0;
+}
+
+int main(void)
+{
+ return test_harness(testcase, "memcmp");
+}
--
2.1.0
^ permalink raw reply related
* Re: [PATCH] cxl: remove redundant increment of hwirq
From: Ian Munsie @ 2015-01-09 2:20 UTC (permalink / raw)
To: Colin King; +Cc: Michael Neuling, linuxppc-dev, linux-kernel
In-Reply-To: <1420756607-23459-1-git-send-email-colin.king@canonical.com>
Acked-By: Ian Munsie <imunsie@au1.ibm.com>
^ permalink raw reply
* Re: PROBLEM: USB isochronous urb leak on EHCI driver
From: Peter Chen @ 2015-01-09 7:20 UTC (permalink / raw)
To: Alan Stern
Cc: Michael Tessier, linuxppc-dev@lists.ozlabs.org,
linux-usb@vger.kernel.org
In-Reply-To: <Pine.LNX.4.44L0.1501061316030.1602-100000@iolanthe.rowland.org>
On Wed, Jan 7, 2015 at 2:22 AM, Alan Stern <stern@rowland.harvard.edu> wrote:
> On Tue, 6 Jan 2015, Michael Tessier wrote:
>
>> > > > > That is interresting, however, I have an older kernel running an
>> > > > > OHCI driver which is able to handle 4 codecs. Same usb hardware
>> > > > > (codecs and hub), but older kernel on a different CPU, with much
>> > > > > less power. This makes me believe that there's a solution to make it work...
>> > > >
>> > > > Of course there is: Install an OHCI host controller and use it to drive your codecs. It should work fine.
>>
>> What do you mean by that? The host controller is embedded in the i.MX CPU...
>> Changing the CPU is not really an option to me. Unless I am missing
>> something?
>
> I didn't realize you were talking about an i.MX-based system. On a
> computer with a free PCI slot, it's easy to add an OHCI controller.
> iMX isn't as accomodating.
>
iMX uses chipidea controller which TT is build-in, and it does NOT support
OHCI controller.
> If there's no way to add an extra USB controller to your system then
> the only choice is to upgrade the driver software.
>
> Alan Stern
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-usb" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
BR,
Peter Chen
^ permalink raw reply
* [PATCH] cxl: Add tracepoints
From: Ian Munsie @ 2015-01-09 9:34 UTC (permalink / raw)
To: mpe
Cc: cbe-oss-dev, mikey, Aneesh Kumar K.V, linux-kernel, Ryan Grimm,
linuxppc-dev, anton, imunsie, jk
From: Ian Munsie <imunsie@au1.ibm.com>
This patch adds tracepoints throughout the cxl driver, which can provide
insight into:
- Context lifetimes
- Commands sent to the PSL and AFU and their completion status
- Segment and page table misses and their resolution
- PSL and AFU interrupts
- slbia calls from the powerpc copro_fault code
These tracepoints are mostly intended to aid in debugging (particularly
for new AFU designs), and may be useful standalone or in conjunction
with hardware traces collected by the PSL (read out via the trace
interface in debugfs) and AFUs.
Signed-off-by: Ian Munsie <imunsie@au1.ibm.com>
---
drivers/misc/cxl/Makefile | 5 +-
drivers/misc/cxl/fault.c | 5 +
drivers/misc/cxl/file.c | 3 +
drivers/misc/cxl/irq.c | 4 +
drivers/misc/cxl/main.c | 2 +
drivers/misc/cxl/native.c | 38 +++-
drivers/misc/cxl/trace.c | 13 ++
drivers/misc/cxl/trace.h | 459 ++++++++++++++++++++++++++++++++++++++++++++++
8 files changed, 520 insertions(+), 9 deletions(-)
create mode 100644 drivers/misc/cxl/trace.c
create mode 100644 drivers/misc/cxl/trace.h
diff --git a/drivers/misc/cxl/Makefile b/drivers/misc/cxl/Makefile
index 165e98f..edb494d 100644
--- a/drivers/misc/cxl/Makefile
+++ b/drivers/misc/cxl/Makefile
@@ -1,3 +1,6 @@
-cxl-y += main.o file.o irq.o fault.o native.o context.o sysfs.o debugfs.o pci.o
+cxl-y += main.o file.o irq.o fault.o native.o context.o sysfs.o debugfs.o pci.o trace.o
obj-$(CONFIG_CXL) += cxl.o
obj-$(CONFIG_CXL_BASE) += base.o
+
+# For tracepoints to include our trace.h from tracepoint infrastructure:
+CFLAGS_trace.o := -I$(src)
diff --git a/drivers/misc/cxl/fault.c b/drivers/misc/cxl/fault.c
index e010302..5286b8b 100644
--- a/drivers/misc/cxl/fault.c
+++ b/drivers/misc/cxl/fault.c
@@ -20,6 +20,7 @@
#include <asm/mmu.h>
#include "cxl.h"
+#include "trace.h"
static bool sste_matches(struct cxl_sste *sste, struct copro_slb *slb)
{
@@ -75,6 +76,7 @@ static void cxl_load_segment(struct cxl_context *ctx, struct copro_slb *slb)
pr_devel("CXL Populating SST[%li]: %#llx %#llx\n",
sste - ctx->sstp, slb->vsid, slb->esid);
+ trace_cxl_ste_write(ctx, sste - ctx->sstp, slb->esid, slb->vsid);
sste->vsid_data = cpu_to_be64(slb->vsid);
sste->esid_data = cpu_to_be64(slb->esid);
@@ -116,6 +118,7 @@ static int cxl_handle_segment_miss(struct cxl_context *ctx,
int rc;
pr_devel("CXL interrupt: Segment fault pe: %i ea: %#llx\n", ctx->pe, ea);
+ trace_cxl_ste_miss(ctx, ea);
if ((rc = cxl_fault_segment(ctx, mm, ea)))
cxl_ack_ae(ctx);
@@ -135,6 +138,8 @@ static void cxl_handle_page_fault(struct cxl_context *ctx,
int result;
unsigned long access, flags, inv_flags = 0;
+ trace_cxl_pte_miss(ctx, dsisr, dar);
+
if ((result = copro_handle_mm_fault(mm, dar, dsisr, &flt))) {
pr_devel("copro_handle_mm_fault failed: %#x\n", result);
return cxl_ack_ae(ctx);
diff --git a/drivers/misc/cxl/file.c b/drivers/misc/cxl/file.c
index 4e85028..2364bca 100644
--- a/drivers/misc/cxl/file.c
+++ b/drivers/misc/cxl/file.c
@@ -23,6 +23,7 @@
#include <asm/copro.h>
#include "cxl.h"
+#include "trace.h"
#define CXL_NUM_MINORS 256 /* Total to reserve */
#define CXL_DEV_MINORS 13 /* 1 control + 4 AFUs * 3 (dedicated/master/shared) */
@@ -186,6 +187,8 @@ static long afu_ioctl_start_work(struct cxl_context *ctx,
*/
ctx->pid = get_pid(get_task_pid(current, PIDTYPE_PID));
+ trace_cxl_attach(ctx, work.work_element_descriptor, work.num_interrupts, amr);
+
if ((rc = cxl_attach_process(ctx, false, work.work_element_descriptor,
amr))) {
afu_release_irqs(ctx);
diff --git a/drivers/misc/cxl/irq.c b/drivers/misc/cxl/irq.c
index c294925..ef52af7 100644
--- a/drivers/misc/cxl/irq.c
+++ b/drivers/misc/cxl/irq.c
@@ -17,6 +17,7 @@
#include <misc/cxl.h>
#include "cxl.h"
+#include "trace.h"
/* XXX: This is implementation specific */
static irqreturn_t handle_psl_slice_error(struct cxl_context *ctx, u64 dsisr, u64 errstat)
@@ -100,6 +101,8 @@ static irqreturn_t cxl_irq(int irq, void *data, struct cxl_irq_info *irq_info)
dsisr = irq_info->dsisr;
dar = irq_info->dar;
+ trace_cxl_psl_irq(ctx, irq, dsisr, dar);
+
pr_devel("CXL interrupt %i for afu pe: %i DSISR: %#llx DAR: %#llx\n", irq, ctx->pe, dsisr, dar);
if (dsisr & CXL_PSL_DSISR_An_DS) {
@@ -237,6 +240,7 @@ static irqreturn_t cxl_irq_afu(int irq, void *data)
return IRQ_HANDLED;
}
+ trace_cxl_afu_irq(ctx, afu_irq, irq, hwirq);
pr_devel("Received AFU interrupt %i for pe: %i (virq %i hwirq %lx)\n",
afu_irq, ctx->pe, irq, hwirq);
diff --git a/drivers/misc/cxl/main.c b/drivers/misc/cxl/main.c
index 4cde9b6..8ccddce 100644
--- a/drivers/misc/cxl/main.c
+++ b/drivers/misc/cxl/main.c
@@ -23,6 +23,7 @@
#include <misc/cxl.h>
#include "cxl.h"
+#include "trace.h"
static DEFINE_SPINLOCK(adapter_idr_lock);
static DEFINE_IDR(cxl_adapter_idr);
@@ -48,6 +49,7 @@ static inline void _cxl_slbia(struct cxl_context *ctx, struct mm_struct *mm)
ctx->afu->adapter->adapter_num, ctx->afu->slice, ctx->pe);
spin_lock_irqsave(&ctx->sste_lock, flags);
+ trace_cxl_slbia(ctx);
memset(ctx->sstp, 0, ctx->sst_size);
spin_unlock_irqrestore(&ctx->sste_lock, flags);
mb();
diff --git a/drivers/misc/cxl/native.c b/drivers/misc/cxl/native.c
index 0f24fa5..29185fc 100644
--- a/drivers/misc/cxl/native.c
+++ b/drivers/misc/cxl/native.c
@@ -18,24 +18,28 @@
#include <misc/cxl.h>
#include "cxl.h"
+#include "trace.h"
static int afu_control(struct cxl_afu *afu, u64 command,
u64 result, u64 mask, bool enabled)
{
u64 AFU_Cntl = cxl_p2n_read(afu, CXL_AFU_Cntl_An);
unsigned long timeout = jiffies + (HZ * CXL_TIMEOUT);
+ int rc = 0;
spin_lock(&afu->afu_cntl_lock);
pr_devel("AFU command starting: %llx\n", command);
+ trace_cxl_afu_ctrl(afu, command);
+
cxl_p2n_write(afu, CXL_AFU_Cntl_An, AFU_Cntl | command);
AFU_Cntl = cxl_p2n_read(afu, CXL_AFU_Cntl_An);
while ((AFU_Cntl & mask) != result) {
if (time_after_eq(jiffies, timeout)) {
dev_warn(&afu->dev, "WARNING: AFU control timed out!\n");
- spin_unlock(&afu->afu_cntl_lock);
- return -EBUSY;
+ rc = -EBUSY;
+ goto out;
}
pr_devel_ratelimited("AFU control... (0x%.16llx)\n",
AFU_Cntl | command);
@@ -44,9 +48,11 @@ static int afu_control(struct cxl_afu *afu, u64 command,
};
pr_devel("AFU command complete: %llx\n", command);
afu->enabled = enabled;
+out:
+ trace_cxl_afu_ctrl_done(afu, command, rc);
spin_unlock(&afu->afu_cntl_lock);
- return 0;
+ return rc;
}
static int afu_enable(struct cxl_afu *afu)
@@ -91,6 +97,9 @@ int cxl_psl_purge(struct cxl_afu *afu)
u64 dsisr, dar;
u64 start, end;
unsigned long timeout = jiffies + (HZ * CXL_TIMEOUT);
+ int rc = 0;
+
+ trace_cxl_psl_ctrl(afu, CXL_PSL_SCNTL_An_Pc);
pr_devel("PSL purge request\n");
@@ -107,7 +116,8 @@ int cxl_psl_purge(struct cxl_afu *afu)
== CXL_PSL_SCNTL_An_Ps_Pending) {
if (time_after_eq(jiffies, timeout)) {
dev_warn(&afu->dev, "WARNING: PSL Purge timed out!\n");
- return -EBUSY;
+ rc = -EBUSY;
+ goto out;
}
dsisr = cxl_p2n_read(afu, CXL_PSL_DSISR_An);
pr_devel_ratelimited("PSL purging... PSL_CNTL: 0x%.16llx PSL_DSISR: 0x%.16llx\n", PSL_CNTL, dsisr);
@@ -128,7 +138,9 @@ int cxl_psl_purge(struct cxl_afu *afu)
cxl_p1n_write(afu, CXL_PSL_SCNTL_An,
PSL_CNTL & ~CXL_PSL_SCNTL_An_Pc);
- return 0;
+out:
+ trace_cxl_psl_ctrl_done(afu, CXL_PSL_SCNTL_An_Pc, rc);
+ return rc;
}
static int spa_max_procs(int spa_size)
@@ -279,6 +291,9 @@ static int do_process_element_cmd(struct cxl_context *ctx,
{
u64 state;
unsigned long timeout = jiffies + (HZ * CXL_TIMEOUT);
+ int rc = 0;
+
+ trace_cxl_llcmd(ctx, cmd);
WARN_ON(!ctx->afu->enabled);
@@ -290,12 +305,14 @@ static int do_process_element_cmd(struct cxl_context *ctx,
while (1) {
if (time_after_eq(jiffies, timeout)) {
dev_warn(&ctx->afu->dev, "WARNING: Process Element Command timed out!\n");
- return -EBUSY;
+ rc = -EBUSY;
+ goto out;
}
state = be64_to_cpup(ctx->afu->sw_command_status);
if (state == ~0ULL) {
pr_err("cxl: Error adding process element to AFU\n");
- return -1;
+ rc = -1;
+ goto out;
}
if ((state & (CXL_SPA_SW_CMD_MASK | CXL_SPA_SW_STATE_MASK | CXL_SPA_SW_LINK_MASK)) ==
(cmd | (cmd >> 16) | ctx->pe))
@@ -310,7 +327,9 @@ static int do_process_element_cmd(struct cxl_context *ctx,
schedule();
}
- return 0;
+out:
+ trace_cxl_llcmd_done(ctx, cmd, rc);
+ return rc;
}
static int add_process_element(struct cxl_context *ctx)
@@ -630,6 +649,8 @@ static inline int detach_process_native_afu_directed(struct cxl_context *ctx)
int cxl_detach_process(struct cxl_context *ctx)
{
+ trace_cxl_detach(ctx);
+
if (ctx->afu->current_mode == CXL_MODE_DEDICATED)
return detach_process_native_dedicated(ctx);
@@ -668,6 +689,7 @@ static void recover_psl_err(struct cxl_afu *afu, u64 errstat)
int cxl_ack_irq(struct cxl_context *ctx, u64 tfc, u64 psl_reset_mask)
{
+ trace_cxl_psl_irq_ack(ctx, tfc);
if (tfc)
cxl_p2n_write(ctx->afu, CXL_PSL_TFC_An, tfc);
if (psl_reset_mask)
diff --git a/drivers/misc/cxl/trace.c b/drivers/misc/cxl/trace.c
new file mode 100644
index 0000000..c2b06d3
--- /dev/null
+++ b/drivers/misc/cxl/trace.c
@@ -0,0 +1,13 @@
+/*
+ * Copyright 2015 IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef __CHECKER__
+#define CREATE_TRACE_POINTS
+#include "trace.h"
+#endif
diff --git a/drivers/misc/cxl/trace.h b/drivers/misc/cxl/trace.h
new file mode 100644
index 0000000..ae434d8
--- /dev/null
+++ b/drivers/misc/cxl/trace.h
@@ -0,0 +1,459 @@
+/*
+ * Copyright 2015 IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM cxl
+
+#if !defined(_CXL_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _CXL_TRACE_H
+
+#include <linux/tracepoint.h>
+
+#include "cxl.h"
+
+#define DSISR_FLAGS \
+ { CXL_PSL_DSISR_An_DS, "DS" }, \
+ { CXL_PSL_DSISR_An_DM, "DM" }, \
+ { CXL_PSL_DSISR_An_ST, "ST" }, \
+ { CXL_PSL_DSISR_An_UR, "UR" }, \
+ { CXL_PSL_DSISR_An_PE, "PE" }, \
+ { CXL_PSL_DSISR_An_AE, "AE" }, \
+ { CXL_PSL_DSISR_An_OC, "OC" }, \
+ { CXL_PSL_DSISR_An_M, "M" }, \
+ { CXL_PSL_DSISR_An_P, "P" }, \
+ { CXL_PSL_DSISR_An_A, "A" }, \
+ { CXL_PSL_DSISR_An_S, "S" }, \
+ { CXL_PSL_DSISR_An_K, "K" }
+
+#define TFC_FLAGS \
+ { CXL_PSL_TFC_An_A, "A" }, \
+ { CXL_PSL_TFC_An_C, "C" }, \
+ { CXL_PSL_TFC_An_AE, "AE" }, \
+ { CXL_PSL_TFC_An_R, "R" }
+
+#define LLCMD_NAMES \
+ { CXL_SPA_SW_CMD_TERMINATE, "TERMINATE" }, \
+ { CXL_SPA_SW_CMD_REMOVE, "REMOVE" }, \
+ { CXL_SPA_SW_CMD_SUSPEND, "SUSPEND" }, \
+ { CXL_SPA_SW_CMD_RESUME, "RESUME" }, \
+ { CXL_SPA_SW_CMD_ADD, "ADD" }, \
+ { CXL_SPA_SW_CMD_UPDATE, "UPDATE" }
+
+#define AFU_COMMANDS \
+ { 0, "DISABLE" }, \
+ { CXL_AFU_Cntl_An_E, "ENABLE" }, \
+ { CXL_AFU_Cntl_An_RA, "RESET" }
+
+#define PSL_COMMANDS \
+ { CXL_PSL_SCNTL_An_Pc, "PURGE" }, \
+ { CXL_PSL_SCNTL_An_Sc, "SUSPEND" }
+
+
+DECLARE_EVENT_CLASS(cxl_pe_class,
+ TP_PROTO(struct cxl_context *ctx),
+
+ TP_ARGS(ctx),
+
+ TP_STRUCT__entry(
+ __field(u8, card)
+ __field(u8, afu)
+ __field(u16, pe)
+ ),
+
+ TP_fast_assign(
+ __entry->card = ctx->afu->adapter->adapter_num;
+ __entry->afu = ctx->afu->slice;
+ __entry->pe = ctx->pe;
+ ),
+
+ TP_printk("afu%i.%i pe=%i",
+ __entry->card,
+ __entry->afu,
+ __entry->pe
+ )
+);
+
+
+TRACE_EVENT(cxl_attach,
+ TP_PROTO(struct cxl_context *ctx, u64 wed, s16 num_interrupts, u64 amr),
+
+ TP_ARGS(ctx, wed, num_interrupts, amr),
+
+ TP_STRUCT__entry(
+ __field(u8, card)
+ __field(u8, afu)
+ __field(u16, pe)
+ __field(pid_t, pid)
+ __field(u64, wed)
+ __field(u64, amr)
+ __field(s16, num_interrupts)
+ ),
+
+ TP_fast_assign(
+ __entry->card = ctx->afu->adapter->adapter_num;
+ __entry->afu = ctx->afu->slice;
+ __entry->pe = ctx->pe;
+ __entry->pid = pid_nr(ctx->pid);
+ __entry->wed = wed;
+ __entry->amr = amr;
+ __entry->num_interrupts = num_interrupts;
+ ),
+
+ TP_printk("afu%i.%i pid=%i pe=%i wed=0x%.16llx irqs=%i amr=0x%llx",
+ __entry->card,
+ __entry->afu,
+ __entry->pid,
+ __entry->pe,
+ __entry->wed,
+ __entry->num_interrupts,
+ __entry->amr
+ )
+);
+
+DEFINE_EVENT(cxl_pe_class, cxl_detach,
+ TP_PROTO(struct cxl_context *ctx),
+ TP_ARGS(ctx)
+);
+
+TRACE_EVENT(cxl_afu_irq,
+ TP_PROTO(struct cxl_context *ctx, int afu_irq, int virq, irq_hw_number_t hwirq),
+
+ TP_ARGS(ctx, afu_irq, virq, hwirq),
+
+ TP_STRUCT__entry(
+ __field(u8, card)
+ __field(u8, afu)
+ __field(u16, pe)
+ __field(u16, afu_irq)
+ __field(int, virq)
+ __field(irq_hw_number_t, hwirq)
+ ),
+
+ TP_fast_assign(
+ __entry->card = ctx->afu->adapter->adapter_num;
+ __entry->afu = ctx->afu->slice;
+ __entry->pe = ctx->pe;
+ __entry->afu_irq = afu_irq;
+ __entry->virq = virq;
+ __entry->hwirq = hwirq;
+ ),
+
+ TP_printk("afu%i.%i pe=%i afu_irq=%i virq=%i hwirq=0x%lx",
+ __entry->card,
+ __entry->afu,
+ __entry->pe,
+ __entry->afu_irq,
+ __entry->virq,
+ __entry->hwirq
+ )
+);
+
+TRACE_EVENT(cxl_psl_irq,
+ TP_PROTO(struct cxl_context *ctx, int irq, u64 dsisr, u64 dar),
+
+ TP_ARGS(ctx, irq, dsisr, dar),
+
+ TP_STRUCT__entry(
+ __field(u8, card)
+ __field(u8, afu)
+ __field(u16, pe)
+ __field(int, irq)
+ __field(u64, dsisr)
+ __field(u64, dar)
+ ),
+
+ TP_fast_assign(
+ __entry->card = ctx->afu->adapter->adapter_num;
+ __entry->afu = ctx->afu->slice;
+ __entry->pe = ctx->pe;
+ __entry->irq = irq;
+ __entry->dsisr = dsisr;
+ __entry->dar = dar;
+ ),
+
+ TP_printk("afu%i.%i pe=%i irq=%i dsisr=%s dar=0x%.16llx",
+ __entry->card,
+ __entry->afu,
+ __entry->pe,
+ __entry->irq,
+ __print_flags(__entry->dsisr, "|", DSISR_FLAGS),
+ __entry->dar
+ )
+);
+
+TRACE_EVENT(cxl_psl_irq_ack,
+ TP_PROTO(struct cxl_context *ctx, u64 tfc),
+
+ TP_ARGS(ctx, tfc),
+
+ TP_STRUCT__entry(
+ __field(u8, card)
+ __field(u8, afu)
+ __field(u16, pe)
+ __field(u64, tfc)
+ ),
+
+ TP_fast_assign(
+ __entry->card = ctx->afu->adapter->adapter_num;
+ __entry->afu = ctx->afu->slice;
+ __entry->pe = ctx->pe;
+ __entry->tfc = tfc;
+ ),
+
+ TP_printk("afu%i.%i pe=%i tfc=%s",
+ __entry->card,
+ __entry->afu,
+ __entry->pe,
+ __print_flags(__entry->tfc, "|", TFC_FLAGS)
+ )
+);
+
+TRACE_EVENT(cxl_ste_miss,
+ TP_PROTO(struct cxl_context *ctx, u64 dar),
+
+ TP_ARGS(ctx, dar),
+
+ TP_STRUCT__entry(
+ __field(u8, card)
+ __field(u8, afu)
+ __field(u16, pe)
+ __field(u64, dar)
+ ),
+
+ TP_fast_assign(
+ __entry->card = ctx->afu->adapter->adapter_num;
+ __entry->afu = ctx->afu->slice;
+ __entry->pe = ctx->pe;
+ __entry->dar = dar;
+ ),
+
+ TP_printk("afu%i.%i pe=%i dar=0x%.16llx",
+ __entry->card,
+ __entry->afu,
+ __entry->pe,
+ __entry->dar
+ )
+);
+
+TRACE_EVENT(cxl_ste_write,
+ TP_PROTO(struct cxl_context *ctx, unsigned int idx, u64 e, u64 v),
+
+ TP_ARGS(ctx, idx, e, v),
+
+ TP_STRUCT__entry(
+ __field(u8, card)
+ __field(u8, afu)
+ __field(u16, pe)
+ __field(unsigned int, idx)
+ __field(u64, e)
+ __field(u64, v)
+ ),
+
+ TP_fast_assign(
+ __entry->card = ctx->afu->adapter->adapter_num;
+ __entry->afu = ctx->afu->slice;
+ __entry->pe = ctx->pe;
+ __entry->idx = idx;
+ __entry->e = e;
+ __entry->v = v;
+ ),
+
+ TP_printk("afu%i.%i pe=%i SSTE[%i] E=0x%.16llx V=0x%.16llx",
+ __entry->card,
+ __entry->afu,
+ __entry->pe,
+ __entry->idx,
+ __entry->e,
+ __entry->v
+ )
+);
+
+TRACE_EVENT(cxl_pte_miss,
+ TP_PROTO(struct cxl_context *ctx, u64 dsisr, u64 dar),
+
+ TP_ARGS(ctx, dsisr, dar),
+
+ TP_STRUCT__entry(
+ __field(u8, card)
+ __field(u8, afu)
+ __field(u16, pe)
+ __field(u64, dsisr)
+ __field(u64, dar)
+ ),
+
+ TP_fast_assign(
+ __entry->card = ctx->afu->adapter->adapter_num;
+ __entry->afu = ctx->afu->slice;
+ __entry->pe = ctx->pe;
+ __entry->dsisr = dsisr;
+ __entry->dar = dar;
+ ),
+
+ TP_printk("afu%i.%i pe=%i dsisr=%s dar=0x%.16llx",
+ __entry->card,
+ __entry->afu,
+ __entry->pe,
+ __print_flags(__entry->dsisr, "|", DSISR_FLAGS),
+ __entry->dar
+ )
+);
+
+TRACE_EVENT(cxl_llcmd,
+ TP_PROTO(struct cxl_context *ctx, u64 cmd),
+
+ TP_ARGS(ctx, cmd),
+
+ TP_STRUCT__entry(
+ __field(u8, card)
+ __field(u8, afu)
+ __field(u16, pe)
+ __field(u64, cmd)
+ ),
+
+ TP_fast_assign(
+ __entry->card = ctx->afu->adapter->adapter_num;
+ __entry->afu = ctx->afu->slice;
+ __entry->pe = ctx->pe;
+ __entry->cmd = cmd;
+ ),
+
+ TP_printk("afu%i.%i pe=%i cmd=%s",
+ __entry->card,
+ __entry->afu,
+ __entry->pe,
+ __print_symbolic_u64(__entry->cmd, LLCMD_NAMES)
+ )
+);
+
+TRACE_EVENT(cxl_llcmd_done,
+ TP_PROTO(struct cxl_context *ctx, u64 cmd, int rc),
+
+ TP_ARGS(ctx, cmd, rc),
+
+ TP_STRUCT__entry(
+ __field(u8, card)
+ __field(u8, afu)
+ __field(u16, pe)
+ __field(u64, cmd)
+ __field(int, rc)
+ ),
+
+ TP_fast_assign(
+ __entry->card = ctx->afu->adapter->adapter_num;
+ __entry->afu = ctx->afu->slice;
+ __entry->pe = ctx->pe;
+ __entry->rc = rc;
+ __entry->cmd = cmd;
+ ),
+
+ TP_printk("afu%i.%i pe=%i cmd=%s rc=%i",
+ __entry->card,
+ __entry->afu,
+ __entry->pe,
+ __print_symbolic_u64(__entry->cmd, LLCMD_NAMES),
+ __entry->rc
+ )
+);
+
+DECLARE_EVENT_CLASS(cxl_afu_psl_ctrl,
+ TP_PROTO(struct cxl_afu *afu, u64 cmd),
+
+ TP_ARGS(afu, cmd),
+
+ TP_STRUCT__entry(
+ __field(u8, card)
+ __field(u8, afu)
+ __field(u64, cmd)
+ ),
+
+ TP_fast_assign(
+ __entry->card = afu->adapter->adapter_num;
+ __entry->afu = afu->slice;
+ __entry->cmd = cmd;
+ ),
+
+ TP_printk("afu%i.%i cmd=%s",
+ __entry->card,
+ __entry->afu,
+ __print_symbolic_u64(__entry->cmd, AFU_COMMANDS)
+ )
+);
+
+DECLARE_EVENT_CLASS(cxl_afu_psl_ctrl_done,
+ TP_PROTO(struct cxl_afu *afu, u64 cmd, int rc),
+
+ TP_ARGS(afu, cmd, rc),
+
+ TP_STRUCT__entry(
+ __field(u8, card)
+ __field(u8, afu)
+ __field(u64, cmd)
+ __field(int, rc)
+ ),
+
+ TP_fast_assign(
+ __entry->card = afu->adapter->adapter_num;
+ __entry->afu = afu->slice;
+ __entry->rc = rc;
+ __entry->cmd = cmd;
+ ),
+
+ TP_printk("afu%i.%i cmd=%s rc=%i",
+ __entry->card,
+ __entry->afu,
+ __print_symbolic_u64(__entry->cmd, AFU_COMMANDS),
+ __entry->rc
+ )
+);
+
+DEFINE_EVENT(cxl_afu_psl_ctrl, cxl_afu_ctrl,
+ TP_PROTO(struct cxl_afu *afu, u64 cmd),
+ TP_ARGS(afu, cmd)
+);
+
+DEFINE_EVENT(cxl_afu_psl_ctrl_done, cxl_afu_ctrl_done,
+ TP_PROTO(struct cxl_afu *afu, u64 cmd, int rc),
+ TP_ARGS(afu, cmd, rc)
+);
+
+DEFINE_EVENT_PRINT(cxl_afu_psl_ctrl, cxl_psl_ctrl,
+ TP_PROTO(struct cxl_afu *afu, u64 cmd),
+ TP_ARGS(afu, cmd),
+
+ TP_printk("psl%i.%i cmd=%s",
+ __entry->card,
+ __entry->afu,
+ __print_symbolic_u64(__entry->cmd, PSL_COMMANDS)
+ )
+);
+
+DEFINE_EVENT_PRINT(cxl_afu_psl_ctrl_done, cxl_psl_ctrl_done,
+ TP_PROTO(struct cxl_afu *afu, u64 cmd, int rc),
+ TP_ARGS(afu, cmd, rc),
+
+ TP_printk("psl%i.%i cmd=%s rc=%i",
+ __entry->card,
+ __entry->afu,
+ __print_symbolic_u64(__entry->cmd, PSL_COMMANDS),
+ __entry->rc
+ )
+);
+
+DEFINE_EVENT(cxl_pe_class, cxl_slbia,
+ TP_PROTO(struct cxl_context *ctx),
+ TP_ARGS(ctx)
+);
+
+#endif /* _CXL_TRACE_H */
+
+/* This part must be outside protection */
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#define TRACE_INCLUDE_FILE trace
+#include <trace/define_trace.h>
--
2.1.4
^ permalink raw reply related
* RE: [PATCH 1/2] powerpc: Add 64bit optimised memcmp
From: David Laight @ 2015-01-09 10:06 UTC (permalink / raw)
To: 'Anton Blanchard', benh@kernel.crashing.org,
paulus@samba.org, mpe@ellerman.id.au
Cc: linuxppc-dev@lists.ozlabs.org
In-Reply-To: <1420768591-6831-1-git-send-email-anton@samba.org>
RnJvbTogQW50b24gQmxhbmNoYXJkDQo+IEkgbm90aWNlZCBrc20gc3BlbmRpbmcgcXVpdGUgYSBs
b3Qgb2YgdGltZSBpbiBtZW1jbXAgb24gYSBsYXJnZQ0KPiBLVk0gYm94LiBUaGUgY3VycmVudCBt
ZW1jbXAgbG9vcCBpcyB2ZXJ5IHVub3B0aW1pc2VkIC0gYnl0ZSBhdCBhDQo+IHRpbWUgY29tcGFy
ZXMgd2l0aCBubyBsb29wIHVucm9sbGluZy4gV2UgY2FuIGRvIG11Y2ggbXVjaCBiZXR0ZXIuDQo+
IA0KPiBPcHRpbWlzZSB0aGUgbG9vcCBpbiBhIGZldyB3YXlzOg0KPiANCj4gLSBVbnJvbGwgdGhl
IGJ5dGUgYXQgYSB0aW1lIGxvb3ANCj4gDQo+IC0gRm9yIGxhcmdlIChhdCBsZWFzdCAzMiBieXRl
KSBjb21wYXJpc29ucyB0aGF0IGFyZSBhbHNvIDggYnl0ZQ0KPiAgIGFsaWduZWQsIHVzZSBhbiB1
bnJvbGxlZCBtb2R1bG8gc2NoZWR1bGVkIGxvb3AgdXNpbmcgOCBieXRlDQo+ICAgbG9hZHMuIFRo
aXMgaXMgc2ltaWxhciB0byBvdXIgZ2xpYmMgbWVtY21wLg0KPiANCj4gQSBzaW1wbGUgbWljcm9i
ZW5jaG1hcmsgdGVzdGluZyAxMDAwMDAwMCBpdGVyYXRpb25zIG9mIGFuIDgxOTIgYnl0ZQ0KPiBt
ZW1jbXAgd2FzIHVzZWQgdG8gbWVhc3VyZSB0aGUgcGVyZm9ybWFuY2U6DQo+IA0KPiBiYXNlbGlu
ZToJMjkuOTMgcw0KPiANCj4gbW9kaWZpZWQ6CSAxLjcwIHMNCj4gDQo+IEp1c3Qgb3ZlciAxN3gg
ZmFzdGVyLg0KDQpUaGUgdW5yb2xsZWQgbG9vcCAoZGVsZXRlZCkgbG9va3MgZXhjZXNzaXZlLg0K
T24gYSBtb2Rlcm4gY3B1IHdpdGggbXVsdGlwbGUgZXhlY3V0aW9uIHVuaXRzIHlvdSBjYW4gdXN1
YWxseQ0KbWFuYWdlIHRvIGdldCB0aGUgbG9vcCBvdmVyaGVhZCB0byBleGVjdXRlIGluIHBhcmFs
bGVsIHRvIHRoZQ0KYWN0dWFsICd3b3JrJy4NClNvIEkgc3VzcGVjdCB0aGF0IGEgbXVjaCBzaW1w
bGVyICd3b3JkIGF0IGEgdGltZScgbG9vcCB3aWxsIGJlDQphbG1vc3QgYXMgZmFzdCAtIGVzcGVj
aWFsbHkgaW4gdGhlIGNhc2Ugd2hlcmUgdGhlIGNvZGUgaXNuJ3QNCmFscmVhZHkgaW4gdGhlIGNh
Y2hlIGFuZCB0aGUgY29tcGFyZSBpcyByZWxhdGl2ZWx5IHNob3J0Lg0KVHJ5IHNvbWV0aGluZyBi
YXNlZCBvbjoNCglhMSA9ICphKys7DQoJYjEgPSAqYisrOw0KCXdoaWxlIHsNCgkJYTIgPSAqYSsr
Ow0KCQliMiA9ICpiKys7DQoJCWlmIChhMSAhPSBhMikNCgkJCWJyZWFrOw0KCQlhMSA9ICphKys7
DQoJCWIxID0gKmIrKzsNCgl9IHdoaWxlIChhMiAhPSBhMSk7DQoNCglEYXZpZA0KDQo=
^ permalink raw reply
* Re: [PATCH 1/2] powerpc: Add 64bit optimised memcmp
From: Adhemerval Zanella @ 2015-01-09 11:01 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <1420768591-6831-1-git-send-email-anton@samba.org>
On 08-01-2015 23:56, Anton Blanchard wrote:
> I noticed ksm spending quite a lot of time in memcmp on a large
> KVM box. The current memcmp loop is very unoptimised - byte at a
> time compares with no loop unrolling. We can do much much better.
>
> Optimise the loop in a few ways:
>
> - Unroll the byte at a time loop
>
> - For large (at least 32 byte) comparisons that are also 8 byte
> aligned, use an unrolled modulo scheduled loop using 8 byte
> loads. This is similar to our glibc memcmp.
>
> A simple microbenchmark testing 10000000 iterations of an 8192 byte
> memcmp was used to measure the performance:
>
> baseline: 29.93 s
>
> modified: 1.70 s
>
> Just over 17x faster.
>
> Signed-off-by: Anton Blanchard <anton@samba.org>
>
Why not use glibc implementations instead? All of them (ppc64, power4, and
power7) avoids use byte at time compares for unaligned cases inputs; while
showing the same performance for aligned one than this new implementation.
To give you an example, a 8192 bytes compare with input alignment of 63/18
shows:
__memcmp_power7: 320 cycles
__memcmp_power4: 320 cycles
__memcmp_ppc64: 340 cycles
this memcmp: 3185 cycles
^ permalink raw reply
* Re: [PATCH 0/6] kbuild: refactor Makefiles related with cc-version
From: Michal Marek @ 2015-01-09 16:27 UTC (permalink / raw)
To: Masahiro Yamada, linux-kbuild
Cc: Jonathan Corbet, Andi Kleen, linux-parisc, linux-doc,
Peter Oberparleiter, Helge Deller, x86, linux-kernel,
James E.J. Bottomley, Robert Richter, Ingo Molnar, Paul Mackerras,
H. Peter Anvin, Thomas Gleixner, H. Peter Anvin, linuxppc-dev
In-Reply-To: <1419485488-22336-1-git-send-email-yamada.m@jp.panasonic.com>
On 2014-12-25 06:31, Masahiro Yamada wrote:
> Masahiro Yamada (6):
> kbuild: fix cc-ifversion macro
> kbuild: do not add $(call ...) to invoke cc-version or cc-fullversion
> kbuild,gcov: remove unnecessary workaround
> kbuild,gcov: simplify kernel/gcov/Makefile
> kbuild: allow cc-ifversion to have the argument for false condition
> kbuild,gcov: simplify kernel/gcov/Makefile more
Applied to kbuild.git#kbuild, thanks.
Michal
^ permalink raw reply
* [RFC 03/11] i2c: at91: make use of the new infrastructure for quirks
From: Wolfram Sang @ 2015-01-09 17:21 UTC (permalink / raw)
To: linux-i2c
Cc: linux-mips, Wolfram Sang, linux-kernel, Ludovic Desroches,
Yingjoe Chen, linuxppc-dev, linux-arm-kernel
In-Reply-To: <1420824103-24169-1-git-send-email-wsa@the-dreams.de>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
drivers/i2c/busses/i2c-at91.c | 32 +++++++++++---------------------
1 file changed, 11 insertions(+), 21 deletions(-)
diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
index 636fd2efad88..8be7cf6e2747 100644
--- a/drivers/i2c/busses/i2c-at91.c
+++ b/drivers/i2c/busses/i2c-at91.c
@@ -487,30 +487,10 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num)
if (ret < 0)
goto out;
- /*
- * The hardware can handle at most two messages concatenated by a
- * repeated start via it's internal address feature.
- */
- if (num > 2) {
- dev_err(dev->dev,
- "cannot handle more than two concatenated messages.\n");
- ret = 0;
- goto out;
- } else if (num == 2) {
+ if (num == 2) {
int internal_address = 0;
int i;
- if (msg->flags & I2C_M_RD) {
- dev_err(dev->dev, "first transfer must be write.\n");
- ret = -EINVAL;
- goto out;
- }
- if (msg->len > 3) {
- dev_err(dev->dev, "first message size must be <= 3.\n");
- ret = -EINVAL;
- goto out;
- }
-
/* 1st msg is put into the internal address, start with 2nd */
m_start = &msg[1];
for (i = 0; i < msg->len; ++i) {
@@ -540,6 +520,15 @@ out:
return ret;
}
+/*
+ * The hardware can handle at most two messages concatenated by a
+ * repeated start via it's internal address feature.
+ */
+static struct i2c_adapter_quirks at91_twi_quirks = {
+ .flags = I2C_ADAPTER_QUIRK_COMB_WRITE_FIRST,
+ .max_comb_write_len = 3,
+};
+
static u32 at91_twi_func(struct i2c_adapter *adapter)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL
@@ -777,6 +766,7 @@ static int at91_twi_probe(struct platform_device *pdev)
dev->adapter.owner = THIS_MODULE;
dev->adapter.class = I2C_CLASS_DEPRECATED;
dev->adapter.algo = &at91_twi_algorithm;
+ dev->adapter.quirks = &at91_twi_quirks;
dev->adapter.dev.parent = dev->dev;
dev->adapter.nr = pdev->id;
dev->adapter.timeout = AT91_I2C_TIMEOUT;
--
2.1.3
^ permalink raw reply related
* [RFC 05/11] i2c: qup: make use of the new infrastructure for quirks
From: Wolfram Sang @ 2015-01-09 17:21 UTC (permalink / raw)
To: linux-i2c
Cc: linux-mips, Wolfram Sang, linux-kernel, Ludovic Desroches,
Yingjoe Chen, linuxppc-dev, linux-arm-kernel
In-Reply-To: <1420824103-24169-1-git-send-email-wsa@the-dreams.de>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
drivers/i2c/busses/i2c-qup.c | 21 ++++++++++-----------
1 file changed, 10 insertions(+), 11 deletions(-)
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 4dad23bdffbe..fdcbdab808e9 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -412,17 +412,6 @@ static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
unsigned long left;
int ret;
- /*
- * The QUP block will issue a NACK and STOP on the bus when reaching
- * the end of the read, the length of the read is specified as one byte
- * which limits the possible read to 256 (QUP_READ_LIMIT) bytes.
- */
- if (msg->len > QUP_READ_LIMIT) {
- dev_err(qup->dev, "HW not capable of reads over %d bytes\n",
- QUP_READ_LIMIT);
- return -EINVAL;
- }
-
qup->msg = msg;
qup->pos = 0;
@@ -534,6 +523,15 @@ static const struct i2c_algorithm qup_i2c_algo = {
.functionality = qup_i2c_func,
};
+/*
+ * The QUP block will issue a NACK and STOP on the bus when reaching
+ * the end of the read, the length of the read is specified as one byte
+ * which limits the possible read to 256 (QUP_READ_LIMIT) bytes.
+ */
+static struct i2c_adapter_quirks qup_i2c_quirks = {
+ .max_read_len = QUP_READ_LIMIT,
+};
+
static void qup_i2c_enable_clocks(struct qup_i2c_dev *qup)
{
clk_prepare_enable(qup->clk);
@@ -670,6 +668,7 @@ static int qup_i2c_probe(struct platform_device *pdev)
i2c_set_adapdata(&qup->adap, qup);
qup->adap.algo = &qup_i2c_algo;
+ qup->adap.quirks = &qup_i2c_quirks;
qup->adap.dev.parent = qup->dev;
qup->adap.dev.of_node = pdev->dev.of_node;
strlcpy(qup->adap.name, "QUP I2C adapter", sizeof(qup->adap.name));
--
2.1.3
^ permalink raw reply related
* [RFC 00/11] i2c: add generic quirk infrastructure
From: Wolfram Sang @ 2015-01-09 17:21 UTC (permalink / raw)
To: linux-i2c
Cc: linux-mips, Wolfram Sang, linux-kernel, Ludovic Desroches,
Yingjoe Chen, linuxppc-dev, linux-arm-kernel
Recently, a number of submitted I2C master drivers could not fully handle all
I2C type transfers due to limited HW. So, they had to bail out with some errno
although the user supplied a valid I2C transfer. In order to centralize such
quirks, a central structure describing the quirks is introduced. The next patch
lets the core do the checks based on the information about the quirks. Then
existing drivers with quirks are converted.
This already has the advantage of avoiding code duplication and having
consistent error handling. Later, once the structure is tested and stable, we
can pass it over to the users, so they can actually check what the current HW
is capable of and react accordingly.
These patches are RFC and only build-tested so far. Yet, I wanted to show what
I am up to. I will do some testing on HW once I finished my task of fixing the
slave interface, hopefully after next week.
I'd really love to see this go into v3.20, but this will need assistance. I
really need testers, at least for the recent hardware. Other comments/reviews
are also appreciated.
Patches are based on v3.19-rc3 and the branch is here
git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git i2c/quirks
Thanks,
Wolfram
Wolfram Sang (11):
i2c: add quirk structure to describe adapter flaws
i2c: add quirk checks to core
i2c: at91: make use of the new infrastructure for quirks
i2c: opal: make use of the new infrastructure for quirks
i2c: qup: make use of the new infrastructure for quirks
i2c: cpm: make use of the new infrastructure for quirks
i2c: axxia: make use of the new infrastructure for quirks
i2c: dln2: make use of the new infrastructure for quirks
i2c: powermac: make use of the new infrastructure for quirks
i2c: viperboard: make use of the new infrastructure for quirks
i2c: pmcmsp: make use of the new infrastructure for quirks
drivers/i2c/busses/i2c-at91.c | 32 ++++++++--------------
drivers/i2c/busses/i2c-axxia.c | 11 ++++----
drivers/i2c/busses/i2c-cpm.c | 20 +++++++-------
drivers/i2c/busses/i2c-dln2.c | 12 ++++-----
drivers/i2c/busses/i2c-opal.c | 22 +++++++--------
drivers/i2c/busses/i2c-pmcmsp.c | 42 +++++++++++------------------
drivers/i2c/busses/i2c-powermac.c | 10 +++----
drivers/i2c/busses/i2c-qup.c | 21 +++++++--------
drivers/i2c/busses/i2c-viperboard.c | 10 ++++---
drivers/i2c/i2c-core.c | 53 +++++++++++++++++++++++++++++++++++++
include/linux/i2c.h | 35 ++++++++++++++++++++++++
11 files changed, 167 insertions(+), 101 deletions(-)
--
2.1.3
^ permalink raw reply
* [RFC 01/11] i2c: add quirk structure to describe adapter flaws
From: Wolfram Sang @ 2015-01-09 17:21 UTC (permalink / raw)
To: linux-i2c
Cc: linux-mips, Wolfram Sang, linux-kernel, Ludovic Desroches,
Yingjoe Chen, linuxppc-dev, linux-arm-kernel
In-Reply-To: <1420824103-24169-1-git-send-email-wsa@the-dreams.de>
The number of I2C adapters which are not fully I2C compatible is rising,
sadly. Drivers usually do handle the flaws, still the user receives only
some errno for a transfer which normally can be expected to work. This
patch introduces a formal description of flaws. One advantage is that
the core can check before the actual transfer if the messages could be
transferred at all. This is done in the next patch. Another advantage is
that we can pass this information to the user so the restrictions are
exactly known and further actions can be based on that. This will be
done later after some stabilization period for this description.
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
include/linux/i2c.h | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index e3a1721c8354..f8a642713706 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -447,6 +447,40 @@ int i2c_recover_bus(struct i2c_adapter *adap);
int i2c_generic_gpio_recovery(struct i2c_adapter *adap);
int i2c_generic_scl_recovery(struct i2c_adapter *adap);
+/**
+ * struct i2c_adapter_quirks - describe flaws of an i2c adapter
+ * @flags: see I2C_ADAPTER_QUIRK_* for possible flags
+ * @max_num_msgs: maximum number of messages per transfer
+ * @max_write_len: maximum length of a write message
+ * @max_read_len: maximum length of a read message
+ * @max_comb_write_len: maximum length of a write in a combined message
+ * @max_comb_read_len: maximum length of a read in a combined message
+ *
+ * Note about combined messages: Some I2C controllers can only send one
+ * message per transfer, plus something called combined message or
+ * write-then-read. This is a (usually) small write message followed by
+ * a read message and barely enough to access register based slaves like
+ * EEPROMs. There is a flag to support this mode. It implies max_num_msg = 2
+ * and does the length checks with max_comb_*_len because combined message mode
+ * usually has its own limitations. Read/write flags of the messages are also
+ * checked to be proper. Because of HW implementation, some controllers can
+ * actually do write-then-anything. To support that, write-then-read has been
+ * broken out into write-first and read-second.
+ */
+struct i2c_adapter_quirks {
+ u64 flags;
+ int max_num_msgs;
+ u16 max_write_len;
+ u16 max_read_len;
+ u16 max_comb_write_len;
+ u16 max_comb_read_len;
+};
+
+#define I2C_ADAPTER_QUIRK_COMB_WRITE_FIRST BIT(0)
+#define I2C_ADAPTER_QUIRK_COMB_READ_SECOND BIT(1)
+#define I2C_ADAPTER_QUIRK_COMB_WRITE_THEN_READ (I2C_ADAPTER_QUIRK_COMB_WRITE_FIRST | \
+ I2C_ADAPTER_QUIRK_COMB_READ_SECOND)
+
/*
* i2c_adapter is the structure used to identify a physical i2c bus along
* with the access algorithms necessary to access it.
@@ -472,6 +506,7 @@ struct i2c_adapter {
struct list_head userspace_clients;
struct i2c_bus_recovery_info *bus_recovery_info;
+ struct i2c_adapter_quirks *quirks;
};
#define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev)
--
2.1.3
^ permalink raw reply related
* [RFC 02/11] i2c: add quirk checks to core
From: Wolfram Sang @ 2015-01-09 17:21 UTC (permalink / raw)
To: linux-i2c
Cc: linux-mips, Wolfram Sang, linux-kernel, Ludovic Desroches,
Yingjoe Chen, linuxppc-dev, linux-arm-kernel
In-Reply-To: <1420824103-24169-1-git-send-email-wsa@the-dreams.de>
Let the core do the checks if HW quirks prevent a transfer. Saves code
from drivers and adds consistency.
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
drivers/i2c/i2c-core.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 53 insertions(+)
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 39d25a8cb1ad..7b10a19abf5b 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -2063,6 +2063,56 @@ module_exit(i2c_exit);
* ----------------------------------------------------
*/
+/* Check if val is exceeding the quirk IFF quirk is non 0 */
+#define i2c_quirk_exceeded(val, quirk) ((quirk) && ((val) > (quirk)))
+
+static int i2c_quirk_error(struct i2c_adapter *adap, struct i2c_msg *msg, char *err_msg)
+{
+ dev_err(&adap->dev, "quirk: %s (addr 0x%04x, size %u)\n", err_msg, msg->addr, msg->len);
+ return -EOPNOTSUPP;
+}
+
+static int i2c_check_for_quirks(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+ struct i2c_adapter_quirks *q = adap->quirks;
+ u16 max_read = q->max_read_len, max_write = q->max_write_len;
+ int max_num = q->max_num_msgs, i;
+
+ if (q->flags & I2C_ADAPTER_QUIRK_COMB_WRITE_THEN_READ)
+ max_num = 2;
+
+ if (i2c_quirk_exceeded(num, max_num))
+ return i2c_quirk_error(adap, &msgs[0], "too many messages");
+
+ if (num == 2 && q->flags & I2C_ADAPTER_QUIRK_COMB_WRITE_FIRST) {
+ if (msgs[0].flags & I2C_M_RD)
+ return i2c_quirk_error(adap, &msgs[0], "invalid first write msg");
+
+ max_write = q->max_comb_write_len;
+ }
+
+ if (num == 2 && q->flags & I2C_ADAPTER_QUIRK_COMB_READ_SECOND) {
+ if (!(msgs[1].flags & I2C_M_RD) || msgs[0].addr != msgs[1].addr)
+ return i2c_quirk_error(adap, &msgs[1], "invalid second read msg");
+
+ max_read = q->max_comb_read_len;
+ }
+
+ for (i = 0; i < num; i++) {
+ u16 len = msgs[i].len;
+
+ if (msgs[i].flags & I2C_M_RD) {
+ if (i2c_quirk_exceeded(len, max_read))
+ return i2c_quirk_error(adap, &msgs[i], "msg too long");
+ } else {
+ if (i2c_quirk_exceeded(len, max_write))
+ return i2c_quirk_error(adap, &msgs[i], "msg too long");
+ }
+ }
+
+ return 0;
+}
+
/**
* __i2c_transfer - unlocked flavor of i2c_transfer
* @adap: Handle to I2C bus
@@ -2080,6 +2130,9 @@ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
unsigned long orig_jiffies;
int ret, try;
+ if (adap->quirks && i2c_check_for_quirks(adap, msgs, num))
+ return -EOPNOTSUPP;
+
/* i2c_trace_msg gets enabled when tracepoint i2c_transfer gets
* enabled. This is an efficient way of keeping the for-loop from
* being executed when not needed.
--
2.1.3
^ permalink raw reply related
* [RFC 04/11] i2c: opal: make use of the new infrastructure for quirks
From: Wolfram Sang @ 2015-01-09 17:21 UTC (permalink / raw)
To: linux-i2c
Cc: linux-mips, Wolfram Sang, linux-kernel, Ludovic Desroches,
Yingjoe Chen, linuxppc-dev, linux-arm-kernel
In-Reply-To: <1420824103-24169-1-git-send-email-wsa@the-dreams.de>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
drivers/i2c/busses/i2c-opal.c | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/drivers/i2c/busses/i2c-opal.c b/drivers/i2c/busses/i2c-opal.c
index 16f90b1a7508..f463eae44bf2 100644
--- a/drivers/i2c/busses/i2c-opal.c
+++ b/drivers/i2c/busses/i2c-opal.c
@@ -104,17 +104,6 @@ static int i2c_opal_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
req.buffer_ra = cpu_to_be64(__pa(msgs[0].buf));
break;
case 2:
- /* For two messages, we basically support only simple
- * smbus transactions of a write plus a read. We might
- * want to allow also two writes but we'd have to bounce
- * the data into a single buffer.
- */
- if ((msgs[0].flags & I2C_M_RD) || !(msgs[1].flags & I2C_M_RD))
- return -EOPNOTSUPP;
- if (msgs[0].len > 4)
- return -EOPNOTSUPP;
- if (msgs[0].addr != msgs[1].addr)
- return -EOPNOTSUPP;
req.type = OPAL_I2C_SM_READ;
req.addr = cpu_to_be16(msgs[0].addr);
req.subaddr_sz = msgs[0].len;
@@ -210,6 +199,16 @@ static const struct i2c_algorithm i2c_opal_algo = {
.functionality = i2c_opal_func,
};
+/* For two messages, we basically support only simple
+ * smbus transactions of a write plus a read. We might
+ * want to allow also two writes but we'd have to bounce
+ * the data into a single buffer.
+ */
+static struct i2c_adapter_quirks i2c_opal_quirks = {
+ .flags = I2C_ADAPTER_QUIRK_COMB_WRITE_THEN_READ,
+ .max_comb_write_len = 4,
+};
+
static int i2c_opal_probe(struct platform_device *pdev)
{
struct i2c_adapter *adapter;
@@ -232,6 +231,7 @@ static int i2c_opal_probe(struct platform_device *pdev)
adapter->algo = &i2c_opal_algo;
adapter->algo_data = (void *)(unsigned long)opal_id;
+ adapter->quirks = &i2c_opal_quirks;
adapter->dev.parent = &pdev->dev;
adapter->dev.of_node = of_node_get(pdev->dev.of_node);
pname = of_get_property(pdev->dev.of_node, "ibm,port-name", NULL);
--
2.1.3
^ permalink raw reply related
* [RFC 06/11] i2c: cpm: make use of the new infrastructure for quirks
From: Wolfram Sang @ 2015-01-09 17:21 UTC (permalink / raw)
To: linux-i2c
Cc: linux-mips, Wolfram Sang, linux-kernel, Ludovic Desroches,
Yingjoe Chen, linuxppc-dev, linux-arm-kernel
In-Reply-To: <1420824103-24169-1-git-send-email-wsa@the-dreams.de>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
drivers/i2c/busses/i2c-cpm.c | 20 +++++++++-----------
1 file changed, 9 insertions(+), 11 deletions(-)
diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c
index 2d466538b2e2..714bdc837769 100644
--- a/drivers/i2c/busses/i2c-cpm.c
+++ b/drivers/i2c/busses/i2c-cpm.c
@@ -308,22 +308,12 @@ static int cpm_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
struct i2c_reg __iomem *i2c_reg = cpm->i2c_reg;
struct i2c_ram __iomem *i2c_ram = cpm->i2c_ram;
struct i2c_msg *pmsg;
- int ret, i;
+ int ret;
int tptr;
int rptr;
cbd_t __iomem *tbdf;
cbd_t __iomem *rbdf;
- if (num > CPM_MAXBD)
- return -EINVAL;
-
- /* Check if we have any oversized READ requests */
- for (i = 0; i < num; i++) {
- pmsg = &msgs[i];
- if (pmsg->len >= CPM_MAX_READ)
- return -EINVAL;
- }
-
/* Reset to use first buffer */
out_be16(&i2c_ram->rbptr, in_be16(&i2c_ram->rbase));
out_be16(&i2c_ram->tbptr, in_be16(&i2c_ram->tbase));
@@ -424,10 +414,18 @@ static const struct i2c_algorithm cpm_i2c_algo = {
.functionality = cpm_i2c_func,
};
+/* CPM_MAX_READ is also limiting writes according to the code! */
+static struct i2c_adapter_quirks cpm_i2c_quirks = {
+ .max_num_msgs = CPM_MAXBD,
+ .max_read_len = CPM_MAX_READ,
+ .max_write_len = CPM_MAX_READ,
+};
+
static const struct i2c_adapter cpm_ops = {
.owner = THIS_MODULE,
.name = "i2c-cpm",
.algo = &cpm_i2c_algo,
+ .quirks = &cpm_i2c_quirks,
};
static int cpm_i2c_setup(struct cpm_i2c *cpm)
--
2.1.3
^ permalink raw reply related
* [RFC 07/11] i2c: axxia: make use of the new infrastructure for quirks
From: Wolfram Sang @ 2015-01-09 17:21 UTC (permalink / raw)
To: linux-i2c
Cc: linux-mips, Wolfram Sang, linux-kernel, Ludovic Desroches,
Yingjoe Chen, linuxppc-dev, linux-arm-kernel
In-Reply-To: <1420824103-24169-1-git-send-email-wsa@the-dreams.de>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
drivers/i2c/busses/i2c-axxia.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/drivers/i2c/busses/i2c-axxia.c b/drivers/i2c/busses/i2c-axxia.c
index 768a598d8d03..488c5d3bf9db 100644
--- a/drivers/i2c/busses/i2c-axxia.c
+++ b/drivers/i2c/busses/i2c-axxia.c
@@ -336,11 +336,6 @@ static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg)
u32 addr_1, addr_2;
int ret;
- if (msg->len > 255) {
- dev_warn(idev->dev, "unsupported length %u\n", msg->len);
- return -EINVAL;
- }
-
idev->msg = msg;
idev->msg_xfrd = 0;
idev->msg_err = 0;
@@ -454,6 +449,11 @@ static const struct i2c_algorithm axxia_i2c_algo = {
.functionality = axxia_i2c_func,
};
+static struct i2c_adapter_quirks axxia_i2c_quirks = {
+ .max_read_len = 255,
+ .max_write_len = 255,
+};
+
static int axxia_i2c_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@@ -511,6 +511,7 @@ static int axxia_i2c_probe(struct platform_device *pdev)
strlcpy(idev->adapter.name, pdev->name, sizeof(idev->adapter.name));
idev->adapter.owner = THIS_MODULE;
idev->adapter.algo = &axxia_i2c_algo;
+ idev->adapter.quirks = &axxia_i2c_quirks;
idev->adapter.dev.parent = &pdev->dev;
idev->adapter.dev.of_node = pdev->dev.of_node;
--
2.1.3
^ permalink raw reply related
* [RFC 08/11] i2c: dln2: make use of the new infrastructure for quirks
From: Wolfram Sang @ 2015-01-09 17:21 UTC (permalink / raw)
To: linux-i2c
Cc: linux-mips, Wolfram Sang, linux-kernel, Ludovic Desroches,
Yingjoe Chen, linuxppc-dev, linux-arm-kernel
In-Reply-To: <1420824103-24169-1-git-send-email-wsa@the-dreams.de>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
drivers/i2c/busses/i2c-dln2.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/i2c/busses/i2c-dln2.c b/drivers/i2c/busses/i2c-dln2.c
index b3fb86af4cbb..b6f9ba7eb175 100644
--- a/drivers/i2c/busses/i2c-dln2.c
+++ b/drivers/i2c/busses/i2c-dln2.c
@@ -144,7 +144,6 @@ static int dln2_i2c_xfer(struct i2c_adapter *adapter,
{
struct dln2_i2c *dln2 = i2c_get_adapdata(adapter);
struct i2c_msg *pmsg;
- struct device *dev = &dln2->adapter.dev;
int i;
for (i = 0; i < num; i++) {
@@ -152,11 +151,6 @@ static int dln2_i2c_xfer(struct i2c_adapter *adapter,
pmsg = &msgs[i];
- if (pmsg->len > DLN2_I2C_MAX_XFER_SIZE) {
- dev_warn(dev, "maximum transfer size exceeded\n");
- return -EOPNOTSUPP;
- }
-
if (pmsg->flags & I2C_M_RD) {
ret = dln2_i2c_read(dln2, pmsg->addr, pmsg->buf,
pmsg->len);
@@ -187,6 +181,11 @@ static const struct i2c_algorithm dln2_i2c_usb_algorithm = {
.functionality = dln2_i2c_func,
};
+static struct i2c_adapter_quirks dln2_i2c_quirks = {
+ .max_read_len = DLN2_I2C_MAX_XFER_SIZE,
+ .max_write_len = DLN2_I2C_MAX_XFER_SIZE,
+};
+
static int dln2_i2c_probe(struct platform_device *pdev)
{
int ret;
@@ -209,6 +208,7 @@ static int dln2_i2c_probe(struct platform_device *pdev)
dln2->adapter.owner = THIS_MODULE;
dln2->adapter.class = I2C_CLASS_HWMON;
dln2->adapter.algo = &dln2_i2c_usb_algorithm;
+ dln2->adapter.quirks = &dln2_i2c_quirks;
dln2->adapter.dev.parent = dev;
i2c_set_adapdata(&dln2->adapter, dln2);
snprintf(dln2->adapter.name, sizeof(dln2->adapter.name), "%s-%s-%d",
--
2.1.3
^ permalink raw reply related
* [RFC 09/11] i2c: powermac: make use of the new infrastructure for quirks
From: Wolfram Sang @ 2015-01-09 17:21 UTC (permalink / raw)
To: linux-i2c
Cc: linux-mips, Wolfram Sang, linux-kernel, Ludovic Desroches,
Yingjoe Chen, linuxppc-dev, linux-arm-kernel
In-Reply-To: <1420824103-24169-1-git-send-email-wsa@the-dreams.de>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
drivers/i2c/busses/i2c-powermac.c | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c
index 60a53c169ed2..6abcf696e359 100644
--- a/drivers/i2c/busses/i2c-powermac.c
+++ b/drivers/i2c/busses/i2c-powermac.c
@@ -153,12 +153,6 @@ static int i2c_powermac_master_xfer( struct i2c_adapter *adap,
int read;
int addrdir;
- if (num != 1) {
- dev_err(&adap->dev,
- "Multi-message I2C transactions not supported\n");
- return -EOPNOTSUPP;
- }
-
if (msgs->flags & I2C_M_TEN)
return -EINVAL;
read = (msgs->flags & I2C_M_RD) != 0;
@@ -205,6 +199,9 @@ static const struct i2c_algorithm i2c_powermac_algorithm = {
.functionality = i2c_powermac_func,
};
+static struct i2c_adapter_quirks i2c_powermac_quirks = {
+ .max_num_msgs = 1,
+};
static int i2c_powermac_remove(struct platform_device *dev)
{
@@ -434,6 +431,7 @@ static int i2c_powermac_probe(struct platform_device *dev)
platform_set_drvdata(dev, adapter);
adapter->algo = &i2c_powermac_algorithm;
+ adapter->quirks = &i2c_powermac_quirks;
i2c_set_adapdata(adapter, bus);
adapter->dev.parent = &dev->dev;
--
2.1.3
^ permalink raw reply related
* [RFC 10/11] i2c: viperboard: make use of the new infrastructure for quirks
From: Wolfram Sang @ 2015-01-09 17:21 UTC (permalink / raw)
To: linux-i2c
Cc: linux-mips, Wolfram Sang, linux-kernel, Ludovic Desroches,
Yingjoe Chen, linuxppc-dev, linux-arm-kernel
In-Reply-To: <1420824103-24169-1-git-send-email-wsa@the-dreams.de>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
drivers/i2c/busses/i2c-viperboard.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/drivers/i2c/busses/i2c-viperboard.c b/drivers/i2c/busses/i2c-viperboard.c
index 7533fa34d737..47e88adf2011 100644
--- a/drivers/i2c/busses/i2c-viperboard.c
+++ b/drivers/i2c/busses/i2c-viperboard.c
@@ -288,10 +288,6 @@ static int vprbrd_i2c_xfer(struct i2c_adapter *i2c, struct i2c_msg *msgs,
i, pmsg->flags & I2C_M_RD ? "read" : "write",
pmsg->flags, pmsg->len, pmsg->addr);
- /* msgs longer than 2048 bytes are not supported by adapter */
- if (pmsg->len > 2048)
- return -EINVAL;
-
mutex_lock(&vb->lock);
/* directly send the message */
if (pmsg->flags & I2C_M_RD) {
@@ -358,6 +354,11 @@ static const struct i2c_algorithm vprbrd_algorithm = {
.functionality = vprbrd_i2c_func,
};
+static struct i2c_adapter_quirks vprbrd_quirks = {
+ .max_read_len = 2048,
+ .max_write_len = 2048,
+};
+
static int vprbrd_i2c_probe(struct platform_device *pdev)
{
struct vprbrd *vb = dev_get_drvdata(pdev->dev.parent);
@@ -373,6 +374,7 @@ static int vprbrd_i2c_probe(struct platform_device *pdev)
vb_i2c->i2c.owner = THIS_MODULE;
vb_i2c->i2c.class = I2C_CLASS_HWMON;
vb_i2c->i2c.algo = &vprbrd_algorithm;
+ vb_i2c->i2c.quirks = &vprbrd_quirks;
vb_i2c->i2c.algo_data = vb;
/* save the param in usb capabable memory */
vb_i2c->bus_freq_param = i2c_bus_param;
--
2.1.3
^ permalink raw reply related
* [RFC 11/11] i2c: pmcmsp: make use of the new infrastructure for quirks
From: Wolfram Sang @ 2015-01-09 17:21 UTC (permalink / raw)
To: linux-i2c
Cc: linux-mips, Wolfram Sang, linux-kernel, Ludovic Desroches,
Yingjoe Chen, linuxppc-dev, linux-arm-kernel
In-Reply-To: <1420824103-24169-1-git-send-email-wsa@the-dreams.de>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
drivers/i2c/busses/i2c-pmcmsp.c | 42 ++++++++++++++++-------------------------
1 file changed, 16 insertions(+), 26 deletions(-)
diff --git a/drivers/i2c/busses/i2c-pmcmsp.c b/drivers/i2c/busses/i2c-pmcmsp.c
index 44f03eed00dd..e06efee9fa70 100644
--- a/drivers/i2c/busses/i2c-pmcmsp.c
+++ b/drivers/i2c/busses/i2c-pmcmsp.c
@@ -463,14 +463,6 @@ static enum pmcmsptwi_xfer_result pmcmsptwi_xfer_cmd(
return -EINVAL;
}
- if (cmd->read_len > MSP_MAX_BYTES_PER_RW ||
- cmd->write_len > MSP_MAX_BYTES_PER_RW) {
- dev_err(&pmcmsptwi_adapter.dev,
- "%s: Cannot transfer more than %d bytes\n",
- __func__, MSP_MAX_BYTES_PER_RW);
- return -EINVAL;
- }
-
mutex_lock(&data->lock);
dev_dbg(&pmcmsptwi_adapter.dev,
"Setting address to 0x%04x\n", cmd->addr);
@@ -527,25 +519,14 @@ static int pmcmsptwi_master_xfer(struct i2c_adapter *adap,
struct pmcmsptwi_cfg oldcfg, newcfg;
int ret;
- if (num > 2) {
- dev_dbg(&adap->dev, "%d messages unsupported\n", num);
- return -EINVAL;
- } else if (num == 2) {
- /* Check for a dual write-then-read command */
+ if (num == 2) {
struct i2c_msg *nextmsg = msg + 1;
- if (!(msg->flags & I2C_M_RD) &&
- (nextmsg->flags & I2C_M_RD) &&
- msg->addr == nextmsg->addr) {
- cmd.type = MSP_TWI_CMD_WRITE_READ;
- cmd.write_len = msg->len;
- cmd.write_data = msg->buf;
- cmd.read_len = nextmsg->len;
- cmd.read_data = nextmsg->buf;
- } else {
- dev_dbg(&adap->dev,
- "Non write-read dual messages unsupported\n");
- return -EINVAL;
- }
+
+ cmd.type = MSP_TWI_CMD_WRITE_READ;
+ cmd.write_len = msg->len;
+ cmd.write_data = msg->buf;
+ cmd.read_len = nextmsg->len;
+ cmd.read_data = nextmsg->buf;
} else if (msg->flags & I2C_M_RD) {
cmd.type = MSP_TWI_CMD_READ;
cmd.read_len = msg->len;
@@ -605,6 +586,14 @@ static u32 pmcmsptwi_i2c_func(struct i2c_adapter *adapter)
I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_PROC_CALL;
}
+static struct i2c_adapter_quirks pmcmsptwi_i2c_quirks = {
+ .flags = I2C_ADAPTER_QUIRK_COMB_WRITE_THEN_READ,
+ .max_write_len = MSP_MAX_BYTES_PER_RW,
+ .max_read_len = MSP_MAX_BYTES_PER_RW,
+ .max_comb_write_len = MSP_MAX_BYTES_PER_RW,
+ .max_comb_read_len = MSP_MAX_BYTES_PER_RW,
+};
+
/* -- Initialization -- */
static struct i2c_algorithm pmcmsptwi_algo = {
@@ -616,6 +605,7 @@ static struct i2c_adapter pmcmsptwi_adapter = {
.owner = THIS_MODULE,
.class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
.algo = &pmcmsptwi_algo,
+ .quirks = &pmcmsptwi_i2c_quirks,
.name = DRV_NAME,
};
--
2.1.3
^ permalink raw reply related
* Re: [PATCH 3/5] powerpc/powernv: Introduce pnv_pci_poll()
From: Bjorn Helgaas @ 2015-01-09 17:43 UTC (permalink / raw)
To: Gavin Shan; +Cc: linux-pci, linuxppc-dev
In-Reply-To: <1417672488-27341-4-git-send-email-gwshan@linux.vnet.ibm.com>
On Thu, Dec 04, 2014 at 04:54:46PM +1100, Gavin Shan wrote:
> We might not get some PCI slot information (e.g. power status)
> immediately by OPAL API. Instead, opal_pci_poll() need to be called
> for the required information.
>
> The patch introduces pnv_pci_poll(), which bases on original
> ioda_eeh_poll(), to cover the above case
>
> Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Hi Gavin,
This patch doesn't apply cleanly on v3.19-rc1. Can you refresh this
series, please?
Bjorn
> ---
> arch/powerpc/platforms/powernv/eeh-ioda.c | 28 ++--------------------------
> arch/powerpc/platforms/powernv/pci.c | 19 +++++++++++++++++++
> arch/powerpc/platforms/powernv/pci.h | 1 +
> 3 files changed, 22 insertions(+), 26 deletions(-)
>
> diff --git a/arch/powerpc/platforms/powernv/eeh-ioda.c b/arch/powerpc/platforms/powernv/eeh-ioda.c
> index cf38781..21fa033 100644
> --- a/arch/powerpc/platforms/powernv/eeh-ioda.c
> +++ b/arch/powerpc/platforms/powernv/eeh-ioda.c
> @@ -490,24 +490,6 @@ static int ioda_eeh_get_state(struct eeh_pe *pe)
> return ioda_eeh_get_pe_state(pe);
> }
>
> -static s64 ioda_eeh_poll(uint64_t id)
> -{
> - s64 rc = OPAL_HARDWARE;
> -
> - while (1) {
> - rc = opal_pci_poll(id, NULL);
> - if (rc <= 0)
> - break;
> -
> - if (system_state < SYSTEM_RUNNING)
> - udelay(1000 * rc);
> - else
> - msleep(rc);
> - }
> -
> - return rc;
> -}
> -
> int ioda_eeh_phb_reset(struct pci_controller *hose, int option)
> {
> struct pnv_phb *phb = hose->private_data;
> @@ -536,10 +518,7 @@ int ioda_eeh_phb_reset(struct pci_controller *hose, int option)
>
> /* Issue reset and poll until it's completed */
> rc = opal_pci_reset(phb->opal_id, scope, OPAL_ASSERT_RESET);
> - if (rc > 0)
> - rc = ioda_eeh_poll(phb->opal_id);
> -
> - return (rc == OPAL_SUCCESS) ? 0 : -EIO;
> + return pnv_pci_poll(phb->opal_id, rc, NULL);
> }
>
> static int __ioda_eeh_bridge_reset(struct pci_dev *dev, int option)
> @@ -630,10 +609,7 @@ static int ioda_eeh_bridge_reset(struct pci_dev *dev, int option)
> phb = hose->private_data;
> id |= (dev->bus->number << 24) | (dev->devfn << 16) | phb->opal_id;
> rc = opal_pci_reset(id, scope, OPAL_ASSERT_RESET);
> - if (rc > 0)
> - ioda_eeh_poll(id);
> -
> - return (rc == OPAL_SUCCESS) ? 0 : -EIO;
> + return pnv_pci_poll(id, rc, NULL);
> }
>
> static int pnv_pci_dev_reset_type(struct pci_dev *pdev, void *data)
> diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c
> index 4b20f2c..6dc8ea9 100644
> --- a/arch/powerpc/platforms/powernv/pci.c
> +++ b/arch/powerpc/platforms/powernv/pci.c
> @@ -45,6 +45,25 @@
> #define cfg_dbg(fmt...) do { } while(0)
> //#define cfg_dbg(fmt...) printk(fmt)
>
> +int pnv_pci_poll(uint64_t id, int64_t rval, uint8_t *pval)
> +{
> + while (rval > 0) {
> + rval = opal_pci_poll(id, pval);
> + if (rval == OPAL_SUCCESS && pval)
> + rval = opal_pci_poll(id, pval);
> +
> + if (rval <= 0)
> + break;
> +
> + if (system_state < SYSTEM_RUNNING)
> + udelay(1000 * rval);
> + else
> + msleep(rval);
> + }
> +
> + return rval ? -EIO : 0;
> +}
> +
> #ifdef CONFIG_PCI_MSI
> static int pnv_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
> {
> diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h
> index 6c02ff8..396fe02 100644
> --- a/arch/powerpc/platforms/powernv/pci.h
> +++ b/arch/powerpc/platforms/powernv/pci.h
> @@ -217,6 +217,7 @@ extern struct pci_ops pnv_pci_ops;
> extern struct pnv_eeh_ops ioda_eeh_ops;
> #endif
>
> +int pnv_pci_poll(uint64_t id, int64_t rval, uint8_t *pval);
> void pnv_pci_dump_phb_diag_data(struct pci_controller *hose,
> unsigned char *log_buff);
> int pnv_pci_cfg_read(struct device_node *dn,
> --
> 1.8.3.2
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pci" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [RFC 02/11] i2c: add quirk checks to core
From: Sergei Shtylyov @ 2015-01-09 19:35 UTC (permalink / raw)
To: Wolfram Sang, linux-i2c
Cc: linux-mips, linux-kernel, Ludovic Desroches, Yingjoe Chen,
linuxppc-dev, linux-arm-kernel
In-Reply-To: <1420824103-24169-3-git-send-email-wsa@the-dreams.de>
Hello.
On 01/09/2015 08:21 PM, Wolfram Sang wrote:
> Let the core do the checks if HW quirks prevent a transfer. Saves code
> from drivers and adds consistency.
> Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
> ---
> drivers/i2c/i2c-core.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 53 insertions(+)
>
> diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
> index 39d25a8cb1ad..7b10a19abf5b 100644
> --- a/drivers/i2c/i2c-core.c
> +++ b/drivers/i2c/i2c-core.c
> @@ -2063,6 +2063,56 @@ module_exit(i2c_exit);
> * ----------------------------------------------------
> */
>
> +/* Check if val is exceeding the quirk IFF quirk is non 0 */
> +#define i2c_quirk_exceeded(val, quirk) ((quirk) && ((val) > (quirk)))
> +
> +static int i2c_quirk_error(struct i2c_adapter *adap, struct i2c_msg *msg, char *err_msg)
> +{
> + dev_err(&adap->dev, "quirk: %s (addr 0x%04x, size %u)\n", err_msg, msg->addr, msg->len);
> + return -EOPNOTSUPP;
> +}
Always returning the same value doesn't make much sense. Are you trying to
save space on the call sites?
[...]
> @@ -2080,6 +2130,9 @@ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
> unsigned long orig_jiffies;
> int ret, try;
>
> + if (adap->quirks && i2c_check_for_quirks(adap, msgs, num))
So, you only check for non-zero result of this function? Perhaps it makes
sense to return true/false instead?
> + return -EOPNOTSUPP;
> +
WBR, Sergei
^ permalink raw reply
* Re: [RFC 02/11] i2c: add quirk checks to core
From: Wolfram Sang @ 2015-01-09 20:45 UTC (permalink / raw)
To: Sergei Shtylyov
Cc: linux-mips, linux-kernel, Ludovic Desroches, linux-i2c,
Yingjoe Chen, linuxppc-dev, linux-arm-kernel
In-Reply-To: <54B02D7F.7040501@cogentembedded.com>
[-- Attachment #1: Type: text/plain, Size: 1794 bytes --]
On Fri, Jan 09, 2015 at 10:35:27PM +0300, Sergei Shtylyov wrote:
> Hello.
>
> On 01/09/2015 08:21 PM, Wolfram Sang wrote:
>
> >Let the core do the checks if HW quirks prevent a transfer. Saves code
> >from drivers and adds consistency.
>
> >Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
> >---
> > drivers/i2c/i2c-core.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++
> > 1 file changed, 53 insertions(+)
> >
> >diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
> >index 39d25a8cb1ad..7b10a19abf5b 100644
> >--- a/drivers/i2c/i2c-core.c
> >+++ b/drivers/i2c/i2c-core.c
> >@@ -2063,6 +2063,56 @@ module_exit(i2c_exit);
> > * ----------------------------------------------------
> > */
> >
> >+/* Check if val is exceeding the quirk IFF quirk is non 0 */
> >+#define i2c_quirk_exceeded(val, quirk) ((quirk) && ((val) > (quirk)))
> >+
> >+static int i2c_quirk_error(struct i2c_adapter *adap, struct i2c_msg *msg, char *err_msg)
> >+{
> >+ dev_err(&adap->dev, "quirk: %s (addr 0x%04x, size %u)\n", err_msg, msg->addr, msg->len);
> >+ return -EOPNOTSUPP;
> >+}
>
> Always returning the same value doesn't make much sense. Are you trying
> to save space on the call sites?
Please elaborate. I think it does. If a quirk matches, we report that we
don't support this transfer.
> [...]
> >@@ -2080,6 +2130,9 @@ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
> > unsigned long orig_jiffies;
> > int ret, try;
> >
> >+ if (adap->quirks && i2c_check_for_quirks(adap, msgs, num))
>
> So, you only check for non-zero result of this function? Perhaps it makes
> sense to return true/false instead?
Could be done, but what would be the advantage? A lot of functions
return errno or 0.
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply
* Re: [RFC 02/11] i2c: add quirk checks to core
From: Sergei Shtylyov @ 2015-01-09 21:05 UTC (permalink / raw)
To: Wolfram Sang
Cc: linux-mips, linux-kernel, Ludovic Desroches, linux-i2c,
Yingjoe Chen, linuxppc-dev, linux-arm-kernel
In-Reply-To: <20150109204522.GB1904@katana>
Hello.
On 01/09/2015 11:45 PM, Wolfram Sang wrote:
>>> Let the core do the checks if HW quirks prevent a transfer. Saves code
>> >from drivers and adds consistency.
>>> Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
>>> ---
>>> drivers/i2c/i2c-core.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++
>>> 1 file changed, 53 insertions(+)
>>>
>>> diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
>>> index 39d25a8cb1ad..7b10a19abf5b 100644
>>> --- a/drivers/i2c/i2c-core.c
>>> +++ b/drivers/i2c/i2c-core.c
>>> @@ -2063,6 +2063,56 @@ module_exit(i2c_exit);
>>> * ----------------------------------------------------
>>> */
>>>
>>> +/* Check if val is exceeding the quirk IFF quirk is non 0 */
>>> +#define i2c_quirk_exceeded(val, quirk) ((quirk) && ((val) > (quirk)))
>>> +
>>> +static int i2c_quirk_error(struct i2c_adapter *adap, struct i2c_msg *msg, char *err_msg)
>>> +{
>>> + dev_err(&adap->dev, "quirk: %s (addr 0x%04x, size %u)\n", err_msg, msg->addr, msg->len);
>>> + return -EOPNOTSUPP;
>>> +}
>> Always returning the same value doesn't make much sense. Are you trying
>> to save space on the call sites?
> Please elaborate. I think it does. If a quirk matches, we report that we
> don't support this transfer.
OK, but what's the point of having this function return *int* if it always
returns the same value? AFAIU, you're trying to save the code space on the
call sites of this function by not having *return* -EOPNOTSUPP there each time?
>> [...]
>>> @@ -2080,6 +2130,9 @@ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
>>> unsigned long orig_jiffies;
>>> int ret, try;
>>>
>>> + if (adap->quirks && i2c_check_for_quirks(adap, msgs, num))
>> So, you only check for non-zero result of this function? Perhaps it makes
>> sense to return true/false instead?
> Could be done, but what would be the advantage? A lot of functions
> return errno or 0.
It would have been OK if you were actually caring about the result, e.g.
returning it from __i2c_transfer(). Since you don't, IMO it would make more
sense to return true from i2c_check_for_quirks() (making it *bool*) iff it did
find/apply a quirk.
WBR, Sergei
^ permalink raw reply
* [PATCH 00/16] PCI generic configuration space accessors
From: Rob Herring @ 2015-01-10 2:34 UTC (permalink / raw)
To: linux-kernel
Cc: linux-mips, linux-sh, linux-pci, Linus Walleij, Will Deacon,
David Howells, linux-tegra, Thierry Reding, Paul Mackerras,
Tanmay Inamdar, Greg Ungerer, Alexandre Courbot, linux-am33-list,
Russell King, Stephen Warren, Michal Simek, linux-arm-kernel,
cbe-oss-dev, Arnd Bergmann, Rob Herring, Simon Horman,
Krzysztof Halasa, Bjorn Helgaas, Sören Brinkmann,
Ralf Baechle, Koichi Yasutake, linuxppc-dev
This series adds common accessor functions for PCI configuration space
accesses. This supports most PCI hosts with memory mapped configuration
space like ECAM or hosts with memory mapped address/data registers. ECAM
is not generically supported by this series, but could be added on top
of this. While some hosts have standard address decoding which could be
common as well, the various checks on bus numbers and device numbers are
quite varied. It is unclear how much of that is really necessary or
could be common.
The first 4 patches are preparatory cleanup. Patch 5 introduces the
common accessors. The remaining patches convert several PCI host
controllers. This is in no way a complete list of host controllers. The
conversion of more hosts should be possible. The Designware controller
in particular should be able to be converted, but its config space
accessors are a mess of override-able functions that I've not gotten my
head around.
This series is available here [1].
Rob
[1] git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git pci-config-access
Rob Herring (16):
frv: add struct pci_ops member names to initialization
mips: add struct pci_ops member names to initialization
mn10300: add struct pci_ops member names to initialization
powerpc: add struct pci_ops member names to initialization
pci: introduce common pci config space accessors
ARM: cns3xxx: convert PCI to use generic config accesses
ARM: integrator: convert PCI to use generic config accesses
ARM: sa1100: convert PCI to use generic config accesses
ARM: ks8695: convert PCI to use generic config accesses
powerpc: fsl_pci: convert PCI to use generic config accesses
powerpc: powermac: convert PCI to use generic config accesses
pci/host: generic: convert to use generic config accesses
pci/host: rcar-gen2: convert to use generic config accesses
pci/host: tegra: convert to use generic config accesses
pci/host: xgene: convert to use generic config accesses
pci/host: xilinx: convert to use generic config accesses
arch/arm/mach-cns3xxx/pcie.c | 52 ++----
arch/arm/mach-integrator/pci_v3.c | 61 +-------
arch/arm/mach-ks8695/pci.c | 77 +--------
arch/arm/mach-sa1100/pci-nanoengine.c | 94 +----------
arch/frv/mb93090-mb00/pci-vdk.c | 4 +-
arch/mips/pci/pci-bcm1480.c | 4 +-
arch/mips/pci/pci-octeon.c | 4 +-
arch/mips/pci/pcie-octeon.c | 12 +-
arch/mn10300/unit-asb2305/pci.c | 4 +-
arch/powerpc/platforms/cell/celleb_scc_pciex.c | 4 +-
arch/powerpc/platforms/powermac/pci.c | 209 +++++--------------------
arch/powerpc/sysdev/fsl_pci.c | 46 +-----
drivers/pci/access.c | 87 ++++++++++
drivers/pci/host/pci-host-generic.c | 51 +-----
drivers/pci/host/pci-rcar-gen2.c | 51 +-----
drivers/pci/host/pci-tegra.c | 55 +------
drivers/pci/host/pci-xgene.c | 150 ++----------------
drivers/pci/host/pcie-xilinx.c | 88 ++---------
include/linux/pci.h | 11 ++
19 files changed, 212 insertions(+), 852 deletions(-)
--
2.1.0
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox