Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1613141 > unrolled thread

[PATCH V8 1/6] LIBIO: Introduce a generic PIO mapping method

Started by"zhichang.yuan" <yuanzhichang@hisilicon.com>
First post2017-03-30 17:00 +0200
Last post2017-04-01 08:40 +0200
Articles 2 — 2 participants

Back to article view | Back to linux.kernel

This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by below is the oldest one visible, not the original post.


Contents

  [PATCH V8 1/6] LIBIO: Introduce a generic PIO mapping method "zhichang.yuan" <yuanzhichang@hisilicon.com> - 2017-03-30 17:00 +0200
    Re: [PATCH V8 1/6] LIBIO: Introduce a generic PIO mapping method kbuild test robot <lkp@intel.com> - 2017-04-01 08:40 +0200

#1613141 — [PATCH V8 1/6] LIBIO: Introduce a generic PIO mapping method

From"zhichang.yuan" <yuanzhichang@hisilicon.com>
Date2017-03-30 17:00 +0200
Subject[PATCH V8 1/6] LIBIO: Introduce a generic PIO mapping method
Message-ID<tqJIm-7Se-27@gated-at.bofh.it>
In commit 41f8bba7f55(of/pci: Add pci_register_io_range() and
pci_pio_to_address()), a new I/O space management was supported. With that
driver, the I/O ranges configured for PCI/PCIE hosts on some architectures can
be mapped to logical PIO, converted easily between CPU address and the
corresponding logicial PIO. Based on this, PCI I/O devices can be accessed in a
memory read/write way through the unified in/out accessors.

But on some archs/platforms, there are bus hosts which access I/O peripherals
with host-local I/O port addresses rather than memory addresses after
memory-mapped.
To support those devices, a more generic I/O mapping method is introduced here.
Through this patch, both the CPU addresses and the host-local port can be
mapped into the logical PIO space with different logical/fake PIOs. After this,
all the I/O accesses to either PCI MMIO devices or host-local I/O peripherals
can be unified into the existing I/O accessors defined in asm-generic/io.h and
be redirected to the right device-specific hooks based on the input logical PIO.

Signed-off-by: zhichang.yuan <yuanzhichang@hisilicon.com>
Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
---
 include/asm-generic/io.h  |  50 ++++++
 include/linux/logic_pio.h | 174 +++++++++++++++++++
 lib/Kconfig               |  26 +++
 lib/Makefile              |   2 +
 lib/logic_pio.c           | 413 ++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 665 insertions(+)
 create mode 100644 include/linux/logic_pio.h
 create mode 100644 lib/logic_pio.c

diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h
index 7ef015e..f7fbec3 100644
--- a/include/asm-generic/io.h
+++ b/include/asm-generic/io.h
@@ -351,6 +351,8 @@ static inline void writesq(volatile void __iomem *addr, const void *buffer,
 #define IO_SPACE_LIMIT 0xffff
 #endif
 
+#include <linux/logic_pio.h>
+
 /*
  * {in,out}{b,w,l}() access little endian I/O. {in,out}{b,w,l}_p() can be
  * implemented on hardware that needs an additional delay for I/O accesses to
@@ -358,51 +360,75 @@ static inline void writesq(volatile void __iomem *addr, const void *buffer,
  */
 
 #ifndef inb
+#ifdef CONFIG_INDIRECT_PIO
+#define inb logic_inb
+#else
 #define inb inb
 static inline u8 inb(unsigned long addr)
 {
 	return readb(PCI_IOBASE + addr);
 }
+#endif /* CONFIG_INDIRECT_PIO */
 #endif
 
 #ifndef inw
+#ifdef CONFIG_INDIRECT_PIO
+#define inw logic_inw
+#else
 #define inw inw
 static inline u16 inw(unsigned long addr)
 {
 	return readw(PCI_IOBASE + addr);
 }
+#endif /* CONFIG_INDIRECT_PIO */
 #endif
 
 #ifndef inl
+#ifdef CONFIG_INDIRECT_PIO
+#define inl logic_inl
+#else
 #define inl inl
 static inline u32 inl(unsigned long addr)
 {
 	return readl(PCI_IOBASE + addr);
 }
+#endif /* CONFIG_INDIRECT_PIO */
 #endif
 
 #ifndef outb
+#ifdef CONFIG_INDIRECT_PIO
+#define outb logic_outb
+#else
 #define outb outb
 static inline void outb(u8 value, unsigned long addr)
 {
 	writeb(value, PCI_IOBASE + addr);
 }
+#endif /* CONFIG_INDIRECT_PIO */
 #endif
 
 #ifndef outw
+#ifdef CONFIG_INDIRECT_PIO
+#define outw logic_outw
+#else
 #define outw outw
 static inline void outw(u16 value, unsigned long addr)
 {
 	writew(value, PCI_IOBASE + addr);
 }
+#endif /* CONFIG_INDIRECT_PIO */
 #endif
 
 #ifndef outl
+#ifdef CONFIG_INDIRECT_PIO
+#define outl logic_outl
+#else
 #define outl outl
 static inline void outl(u32 value, unsigned long addr)
 {
 	writel(value, PCI_IOBASE + addr);
 }
+#endif /* CONFIG_INDIRECT_PIO */
 #endif
 
 #ifndef inb_p
@@ -459,54 +485,78 @@ static inline void outl_p(u32 value, unsigned long addr)
  */
 
 #ifndef insb
+#ifdef CONFIG_INDIRECT_PIO
+#define insb logic_insb
+#else
 #define insb insb
 static inline void insb(unsigned long addr, void *buffer, unsigned int count)
 {
 	readsb(PCI_IOBASE + addr, buffer, count);
 }
+#endif /* CONFIG_INDIRECT_PIO */
 #endif
 
 #ifndef insw
+#ifdef CONFIG_INDIRECT_PIO
+#define insw logic_insw
+#else
 #define insw insw
 static inline void insw(unsigned long addr, void *buffer, unsigned int count)
 {
 	readsw(PCI_IOBASE + addr, buffer, count);
 }
+#endif /* CONFIG_INDIRECT_PIO */
 #endif
 
 #ifndef insl
+#ifdef CONFIG_INDIRECT_PIO
+#define insl logic_insl
+#else
 #define insl insl
 static inline void insl(unsigned long addr, void *buffer, unsigned int count)
 {
 	readsl(PCI_IOBASE + addr, buffer, count);
 }
+#endif /* CONFIG_INDIRECT_PIO */
 #endif
 
 #ifndef outsb
+#ifdef CONFIG_INDIRECT_PIO
+#define outsb logic_outsb
+#else
 #define outsb outsb
 static inline void outsb(unsigned long addr, const void *buffer,
 			 unsigned int count)
 {
 	writesb(PCI_IOBASE + addr, buffer, count);
 }
+#endif /* CONFIG_INDIRECT_PIO */
 #endif
 
 #ifndef outsw
+#ifdef CONFIG_INDIRECT_PIO
+#define outsw logic_outsw
+#else
 #define outsw outsw
 static inline void outsw(unsigned long addr, const void *buffer,
 			 unsigned int count)
 {
 	writesw(PCI_IOBASE + addr, buffer, count);
 }
+#endif /* CONFIG_INDIRECT_PIO */
 #endif
 
 #ifndef outsl
+#ifdef CONFIG_INDIRECT_PIO
+#define outsl logic_outsl
+#else
 #define outsl outsl
 static inline void outsl(unsigned long addr, const void *buffer,
 			 unsigned int count)
 {
 	writesl(PCI_IOBASE + addr, buffer, count);
 }
+#endif /* CONFIG_INDIRECT_PIO */
 #endif
 
 #ifndef insb_p
diff --git a/include/linux/logic_pio.h b/include/linux/logic_pio.h
new file mode 100644
index 0000000..e9f5644
--- /dev/null
+++ b/include/linux/logic_pio.h
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2017 Hisilicon Limited, All Rights Reserved.
+ * Author: Zhichang Yuan <yuanzhichang@hisilicon.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LINUX_LIBIO_H
+#define __LINUX_LIBIO_H
+
+#ifdef __KERNEL__
+
+#include <linux/fwnode.h>
+
+/*
+ *		Total IO space is 0 to IO_SPACE_LIMIT
+ *
+ *    section			pio
+ * |________|________________________________________|
+ *
+ * In this division, the benefits are:
+ * 1) The MMIO PIO space is consecutive, then ioport_map() still works well
+ * for MMIO;
+ * 2) The search happened in inX/outX with input PIO will have better
+ * performance for indirect_IO. For MMIO, the performance is nearly same
+ * even when CONFIG_INDIRECT_PIO is enabled;
+ *
+ * Some notes:
+ * 1) Don't increase the IO_SPACE_LIMIT to avoid modification on so many
+ * architectural files;
+ * 2) To reduce the impact on the original I/O space to a minimum, we only
+ * apply this IO space division when CONFIG_INDIRECT_PIO is enabled; And
+ * only allocate the last section to INDIRECT_PIO, all the other PIO space are
+ * for MMIO;
+ * 3) For better efficiency, one more I/O segment can be separated from 'pio'
+ * bit section. But it will make the IO space size decreased. Won't apply at
+ * this moment;
+ */
+#ifdef CONFIG_INDIRECT_PIO
+#define PIO_SECT_BITS		2
+#else
+#define PIO_SECT_BITS		0
+#endif
+#define PIO_MAX_SECT		(0x01UL << PIO_SECT_BITS)
+#define PIO_SECT_MASK		(PIO_MAX_SECT - 1)
+
+/* The last section. */
+#define PIO_INDIRECT		(PIO_MAX_SECT - 1)
+/* This one is for MMIO(PCI) to keep compatibility */
+#define PIO_CPU_MMIO		0x00UL
+
+struct logic_pio_root {
+	struct list_head sec_head;
+	resource_size_t sec_min;
+	resource_size_t sec_max;
+};
+
+#if ((IO_SPACE_LIMIT + 1) & IO_SPACE_LIMIT)
+#error "(IO_SPACE_LIMIT + 1) must be power of 2!"
+#endif
+
+#define PIO_VAL_MASK		(IO_SPACE_LIMIT >> PIO_SECT_BITS)
+#define PIO_VAL_BIT_LEN		(ilog2(PIO_VAL_MASK) + 1)
+
+#define PIO_SECT_MIN(sec_id)	((sec_id) << PIO_VAL_BIT_LEN)
+#define PIO_SECT_MAX(sec_id)	(PIO_SECT_MIN(sec_id) | PIO_VAL_MASK)
+
+#define PIO_SECT_ID(pio)	((pio >> PIO_VAL_BIT_LEN) & PIO_SECT_MASK)
+
+struct logic_pio_sect {
+	struct list_head list;
+	resource_size_t io_start;
+
+	struct logic_pio_hwaddr *hwpeer;
+};
+#define to_pio_sect(node) container_of(node, struct logic_pio_sect, list)
+
+struct logic_pio_hwaddr {
+	struct list_head list;
+	struct fwnode_handle *fwnode;
+	resource_size_t hw_start;
+	resource_size_t size; /* range size populated */
+	unsigned long flags;
+
+	struct logic_pio_sect *pio_peer;
+
+	void *devpara;	/* private parameter of the host device */
+	struct hostio_ops *ops;	/* ops operating on this node */
+};
+#define to_pio_hwaddr(node) container_of(node, struct logic_pio_hwaddr, list)
+
+struct hostio_ops {
+	u32 (*pfin)(void *devobj, unsigned long ptaddr,	size_t dlen);
+	void (*pfout)(void *devobj, unsigned long ptaddr, u32 outval,
+			size_t dlen);
+	u32 (*pfins)(void *devobj, unsigned long ptaddr, void *inbuf,
+			size_t dlen, unsigned int count);
+	void (*pfouts)(void *devobj, unsigned long ptaddr,
+			const void *outbuf, size_t dlen, unsigned int count);
+};
+
+#ifdef CONFIG_INDIRECT_PIO
+#define LPC_MIN_BUS_RANGE	0x0
+
+/*
+ * The default maximal IO size for Hip06/Hip07 LPC bus.
+ * Defining the I/O range size as 0x400 here should be sufficient for
+ * all peripherals under the bus.
+ */
+#define LPC_BUS_IO_SIZE		0x400
+#endif
+
+extern u8 logic_inb(unsigned long addr);
+extern void logic_outb(u8 value, unsigned long addr);
+extern void logic_outw(u16 value, unsigned long addr);
+extern void logic_outl(u32 value, unsigned long addr);
+extern u16 logic_inw(unsigned long addr);
+extern u32 logic_inl(unsigned long addr);
+extern void logic_outb(u8 value, unsigned long addr);
+extern void logic_outw(u16 value, unsigned long addr);
+extern void logic_outl(u32 value, unsigned long addr);
+extern void logic_insb(unsigned long addr, void *buffer, unsigned int count);
+extern void logic_insl(unsigned long addr, void *buffer, unsigned int count);
+extern void logic_insw(unsigned long addr, void *buffer, unsigned int count);
+extern void logic_outsb(unsigned long addr, const void *buffer,
+			unsigned int count);
+extern void logic_outsw(unsigned long addr, const void *buffer,
+			unsigned int count);
+extern void logic_outsl(unsigned long addr, const void *buffer,
+			unsigned int count);
+#ifdef CONFIG_LOGIC_PIO
+extern struct logic_pio_hwaddr
+*find_io_range_by_fwnode(struct fwnode_handle *fwnode);
+
+extern unsigned long logic_pio_trans_hwaddr(struct fwnode_handle *fwnode,
+			resource_size_t hw_addr);
+#else
+static inline struct logic_pio_hwaddr
+*find_io_range_by_fwnode(struct fwnode_handle *fwnode)
+{
+	return NULL;
+}
+
+static inline unsigned long
+logic_pio_trans_hwaddr(struct fwnode_handle *fwnode, resource_size_t hw_addr)
+{
+	return -1;
+}
+#endif
+
+/*
+ * These are used by pci. As LOGIC_PIO is bound with PCI, no need to add dummy
+ * functions for them.
+ */
+extern struct logic_pio_hwaddr
+*logic_pio_register_range(struct logic_pio_hwaddr *newrange,
+	unsigned long align);
+
+extern resource_size_t logic_pio_to_hwaddr(unsigned long pio);
+
+extern unsigned long logic_pio_trans_cpuaddr(resource_size_t hw_addr);
+
+#endif /* __KERNEL__ */
+#endif /* __LINUX_LIBIO_H */
diff --git a/lib/Kconfig b/lib/Kconfig
index 0c8b78a..503c2e0 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -59,6 +59,32 @@ config ARCH_USE_CMPXCHG_LOCKREF
 config ARCH_HAS_FAST_MULTIPLIER
 	bool
 
+config LOGIC_PIO
+	bool "Generic logical I/O management"
+	def_bool y if PCI && !X86 && !IA64 && !POWERPC
+	help
+	  For some architectures, there are no IO space. To support the
+	  accesses to legacy I/O devices on those architectures, kernel
+	  implemented the memory mapped I/O mechanism based on bridge bus
+	  supports. But for some buses which do not support MMIO, the
+	  peripherals there should be accessed with device-specific way.
+	  To abstract those different I/O accesses into unified I/O accessors,
+	  this option provide a generic I/O space management way after mapping
+	  the device I/O to system logical/fake I/O and help to hide all the
+	  hardware detail.
+
+config INDIRECT_PIO
+	bool "Access I/O in non-MMIO mode" if LOGIC_PIO
+	help
+	  On some platforms where no separate I/O space exist, there are I/O
+	  hosts which can not be accessed in MMIO mode. Based on LOGIC_PIO
+	  mechanism, the host-local I/O resource can be mapped into system
+	  logic PIO space shared with MMIO hosts, such as PCI/PCIE, then system
+	  can access the I/O devices with the mapped logic PIO through I/O
+	  accessors.
+	  This way has a little I/O performance cost. Please make sure your
+	  devices really need this configure item enabled.
+
 config CRC_CCITT
 	tristate "CRC-CCITT functions"
 	help
diff --git a/lib/Makefile b/lib/Makefile
index 320ac46a..26dcec0 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -77,6 +77,8 @@ obj-$(CONFIG_HAS_IOMEM) += iomap_copy.o devres.o
 obj-$(CONFIG_CHECK_SIGNATURE) += check_signature.o
 obj-$(CONFIG_DEBUG_LOCKING_API_SELFTESTS) += locking-selftest.o
 
+obj-$(CONFIG_LOGIC_PIO) += logic_pio.o
+
 obj-$(CONFIG_GENERIC_HWEIGHT) += hweight.o
 
 obj-$(CONFIG_BTREE) += btree.o
diff --git a/lib/logic_pio.c b/lib/logic_pio.c
new file mode 100644
index 0000000..ca247e3
--- /dev/null
+++ b/lib/logic_pio.c
@@ -0,0 +1,413 @@
+/*
+ * Copyright (C) 2017 Hisilicon Limited, All Rights Reserved.
+ * Author: Zhichang Yuan <yuanzhichang@hisilicon.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/of.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <linux/rculist.h>
+#include <linux/sizes.h>
+#include <linux/slab.h>
+
+/* The unique hardware address list. */
+static LIST_HEAD(io_range_list);
+static DEFINE_MUTEX(io_range_mutex);
+
+/*
+ * These are the lists for PIO. The highest PIO_SECT_BITS of PIO is the index.
+ */
+static struct logic_pio_root logic_pio_root_list[PIO_MAX_SECT] = {
+#ifdef CONFIG_INDIRECT_PIO
+	/*
+	 * At this moment, assign all the other logic PIO space to MMIO.
+	 * If more elements added, please adjust the ending index and .sec_max;
+	 * Please keep MMIO element started from index ZERO.
+	 */
+	[PIO_CPU_MMIO ... PIO_INDIRECT - 1] = {
+		.sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_CPU_MMIO].sec_head),
+		.sec_min = PIO_SECT_MIN(PIO_CPU_MMIO),
+		.sec_max = PIO_SECT_MAX(PIO_INDIRECT - 1),
+	},
+
+	/* The last element */
+	[PIO_INDIRECT] = {
+		.sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_INDIRECT].sec_head),
+		.sec_min = PIO_SECT_MIN(PIO_INDIRECT),
+		.sec_max = PIO_SECT_MAX(PIO_INDIRECT),
+	},
+#else
+	[PIO_CPU_MMIO] = {
+		.sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_CPU_MMIO].sec_head),
+		.sec_min = PIO_SECT_MIN(PIO_CPU_MMIO),
+		.sec_max = PIO_SECT_MAX(PIO_CPU_MMIO),
+	},
+
+#endif
+};
+
+/*
+ * Search a io_range registered which match the fwnode and addr.
+ *
+ * @fwnode: the host fwnode which must be valid;
+ * @start: the start hardware address of this search;
+ * @end: the end hardware address of this search. can be equal to @start;
+ *
+ * return NULL when there is no matched node; IS_ERR() means ERROR;
+ * valid virtual address represent a matched node was found.
+ */
+static struct logic_pio_hwaddr *
+logic_pio_find_range_byaddr(struct fwnode_handle *fwnode,
+			resource_size_t start, resource_size_t end)
+{
+	struct logic_pio_hwaddr *range;
+
+	list_for_each_entry_rcu(range, &io_range_list, list) {
+		if (!range->pio_peer) {
+			pr_warn("Invalid cpu addr node(%pa) in list!\n",
+				&range->hw_start);
+			continue;
+		}
+		if (range->fwnode != fwnode)
+			continue;
+		/* without any overlap with current range */
+		if (start >= range->hw_start + range->size ||
+			end < range->hw_start)
+			continue;
+		/* overlap is not supported now. */
+		if (start < range->hw_start ||
+			end >= range->hw_start + range->size)
+			return ERR_PTR(-EBUSY);
+		/* had been registered. */
+		return range;
+	}
+
+	return NULL;
+}
+
+
+static int logic_pio_alloc_range(struct logic_pio_root *root,
+		resource_size_t size, unsigned long align,
+		struct list_head **prev, resource_size_t *pio_alloc)
+{
+	struct logic_pio_sect *entry;
+	resource_size_t tmp_start;
+	resource_size_t idle_start, idle_end;
+
+	idle_start = root->sec_min;
+	*prev = &root->sec_head;
+	list_for_each_entry_rcu(entry, &root->sec_head, list) {
+		if (!entry->hwpeer ||
+			idle_start > entry->io_start) {
+			WARN(1, "skip an invalid io range during traversal!\n");
+			goto nextentry;
+		}
+		/* set the end edge. */
+		if (idle_start == entry->io_start) {
+			struct logic_pio_sect *next;
+
+			idle_start = entry->io_start + entry->hwpeer->size;
+			next = list_next_or_null_rcu(&root->sec_head,
+				&entry->list, struct logic_pio_sect, list);
+			if (next) {
+				entry = next;
+			} else {
+				*prev = &entry->list;
+				break;
+			}
+		}
+		idle_end = entry->io_start - 1;
+
+		/* contiguous range... */
+		if (idle_start > idle_end)
+			goto nextentry;
+
+		tmp_start = idle_start;
+		idle_start = ALIGN(idle_start, align);
+		if (idle_start >= tmp_start &&
+			idle_start + size <= idle_end) {
+			*prev = &entry->list;
+			*pio_alloc = idle_start;
+			return 0;
+		}
+
+nextentry:
+		idle_start = entry->io_start + entry->hwpeer->size;
+		*prev = &entry->list;
+	}
+	/* check the last free gap... */
+	idle_end = root->sec_max;
+
+	tmp_start = idle_start;
+	idle_start = ALIGN(idle_start, align);
+	if (idle_start >= tmp_start &&
+		idle_start + size <= idle_end) {
+		*pio_alloc = idle_start;
+		return 0;
+	}
+
+	return -EBUSY;
+}
+
+/*
+ * register a io range node in the io range list.
+ *
+ * @newrange: pointer to the io range to be registered.
+ *
+ * return 'newrange' when success, ERR_VALUE() is for failures.
+ * specially, return a valid pointer which is not equal to 'newrange' when
+ * the io range had been registered before.
+ */
+struct logic_pio_hwaddr
+*logic_pio_register_range(struct logic_pio_hwaddr *newrange,
+		unsigned long align)
+{
+	struct logic_pio_hwaddr *range;
+	struct logic_pio_sect *newsect;
+	resource_size_t pio_alloc;
+	struct list_head *prev, *hwprev;
+	unsigned long sect_id;
+	int err;
+
+	if (!newrange || !newrange->fwnode || !newrange->size)
+		return ERR_PTR(-EINVAL);
+
+	sect_id = newrange->flags;
+	if (sect_id >= PIO_MAX_SECT)
+		return ERR_PTR(-EINVAL);
+
+	mutex_lock(&io_range_mutex);
+	range = logic_pio_find_range_byaddr(newrange->fwnode,
+			newrange->hw_start,
+			newrange->hw_start + newrange->size - 1);
+	if (range) {
+		if (!IS_ERR(range))
+			pr_info("the request IO range had been registered!\n");
+		else
+			pr_err("registering IO[%pa - sz%pa) got failed!\n",
+				&newrange->hw_start, &newrange->size);
+		mutex_unlock(&io_range_mutex);
+		return range;
+	}
+
+	err = logic_pio_alloc_range(&logic_pio_root_list[sect_id],
+			newrange->size, align, &prev, &pio_alloc);
+	if (err) {
+		pr_err("can't find free %pa logical IO range!\n",
+			&newrange->size);
+		goto exitproc;
+	}
+
+	if (prev == &logic_pio_root_list[sect_id].sec_head) {
+		hwprev = &io_range_list;
+	} else {
+		newsect = to_pio_sect(prev);
+		hwprev = &newsect->hwpeer->list;
+	}
+
+	newsect = kzalloc(sizeof(*newsect), GFP_KERNEL);
+	if (!newsect) {
+		err = -ENOMEM;
+		goto exitproc;
+	}
+	newsect->io_start = pio_alloc;
+	newsect->hwpeer = newrange;
+	list_add_rcu(&newsect->list, prev);
+
+	newrange->pio_peer = newsect;
+	list_add_rcu(&newrange->list, hwprev);
+
+exitproc:
+	mutex_unlock(&io_range_mutex);
+	return err ? ERR_PTR(err) : newrange;
+}
+
+/*
+ * traverse the io_range_list to find the registered node whose device node
+ * and/or physical IO address match to.
+ */
+struct logic_pio_hwaddr *find_io_range_by_fwnode(struct fwnode_handle *fwnode)
+{
+	struct logic_pio_hwaddr *range;
+
+	list_for_each_entry_rcu(range, &io_range_list, list) {
+		if (range->fwnode == fwnode)
+			return range;
+	}
+	return NULL;
+}
+
+/*
+ * Translate the input logical pio to the corresponding hardware address.
+ * The input pio should be unique in the whole logical PIO space.
+ */
+resource_size_t logic_pio_to_hwaddr(unsigned long pio)
+{
+	struct logic_pio_sect *entry;
+	struct logic_pio_root *root;
+
+	/* The caller should check the section id is valid. */
+	root = &logic_pio_root_list[PIO_SECT_ID(pio)];
+	list_for_each_entry_rcu(entry, &root->sec_head, list) {
+		if (!entry->hwpeer) {
+			pr_warn("Invalid PIO entry(%pa) in list!\n",
+				&entry->io_start);
+			continue;
+		}
+		if (pio < entry->io_start)
+			break;
+
+		if (pio < entry->io_start + entry->hwpeer->size)
+			return pio - entry->io_start + entry->hwpeer->hw_start;
+	}
+
+	return -1;
+}
+
+/*
+ * This function is generic for translating a hardware address to logical PIO.
+ * @hw_addr: the hardware address of host, can be CPU address or host-local
+ *		address;
+ */
+unsigned long
+logic_pio_trans_hwaddr(struct fwnode_handle *fwnode, resource_size_t addr)
+{
+	struct logic_pio_hwaddr *range;
+
+	range = logic_pio_find_range_byaddr(fwnode, addr, addr);
+	if (!range)
+		return -1;
+
+	return addr - range->hw_start + range->pio_peer->io_start;
+}
+
+unsigned long
+logic_pio_trans_cpuaddr(resource_size_t addr)
+{
+	struct logic_pio_hwaddr *range;
+
+	list_for_each_entry_rcu(range, &io_range_list, list) {
+		if (!range->pio_peer) {
+			pr_warn("Invalid cpu addr node(%pa) in list!\n",
+				&range->hw_start);
+			continue;
+		}
+		if (range->flags != PIO_CPU_MMIO)
+			continue;
+		if (addr >= range->hw_start &&
+			addr < range->hw_start + range->size)
+			return addr - range->hw_start +
+				range->pio_peer->io_start;
+	}
+	return -1;
+}
+
+#if defined(CONFIG_INDIRECT_PIO) && defined(PCI_IOBASE)
+static struct logic_pio_hwaddr *find_io_range(unsigned long pio)
+{
+	struct logic_pio_sect *entry;
+	struct logic_pio_root *root;
+
+	root = &logic_pio_root_list[PIO_SECT_ID(pio)];
+	if (pio < root->sec_min || pio > root->sec_max)
+		return NULL;
+	/*
+	 * non indirectIO section, no need to convert the addr. Jump to mmio ops
+	 * directly.
+	 */
+	if (&root->sec_head == &logic_pio_root_list[PIO_CPU_MMIO].sec_head)
+		return NULL;
+	list_for_each_entry_rcu(entry, &root->sec_head, list) {
+		if (!entry->hwpeer) {
+			pr_warn("Invalid PIO entry(%pa) in list!\n",
+				&entry->io_start);
+			continue;
+		}
+		if (pio < entry->io_start)
+			break;
+
+		if (pio < entry->io_start + entry->hwpeer->size)
+			return entry->hwpeer;
+	}
+
+	return NULL;
+}
+
+#define BUILD_LOGIC_IO(bw, type)					\
+type logic_in##bw(unsigned long addr)					\
+{									\
+	struct logic_pio_hwaddr *entry = find_io_range(addr);		\
+									\
+	if (entry && entry->ops)					\
+		return entry->ops->pfin(entry->devpara,			\
+					addr, sizeof(type));		\
+	return read##bw(PCI_IOBASE + addr);				\
+}									\
+									\
+void logic_out##bw(type value, unsigned long addr)			\
+{									\
+	struct logic_pio_hwaddr *entry = find_io_range(addr);		\
+									\
+	if (entry && entry->ops)					\
+		entry->ops->pfout(entry->devpara,			\
+					addr, value, sizeof(type));	\
+	else								\
+		write##bw(value, PCI_IOBASE + addr);			\
+}									\
+									\
+void logic_ins##bw(unsigned long addr, void *buffer, unsigned int count)\
+{									\
+	struct logic_pio_hwaddr *entry = find_io_range(addr);		\
+									\
+	if (entry && entry->ops)					\
+		entry->ops->pfins(entry->devpara,			\
+				addr, buffer, sizeof(type), count);	\
+	else								\
+		reads##bw(PCI_IOBASE + addr, buffer, count);		\
+}									\
+									\
+void logic_outs##bw(unsigned long addr, const void *buffer,		\
+		    unsigned int count)					\
+{									\
+	struct logic_pio_hwaddr *entry = find_io_range(addr);		\
+									\
+	if (entry && entry->ops)					\
+		entry->ops->pfouts(entry->devpara,			\
+				addr, buffer, sizeof(type), count);	\
+	else								\
+		writes##bw(PCI_IOBASE + addr, buffer, count);	\
+}
+
+BUILD_LOGIC_IO(b, u8)
+
+EXPORT_SYMBOL(logic_inb);
+EXPORT_SYMBOL(logic_outb);
+EXPORT_SYMBOL(logic_insb);
+EXPORT_SYMBOL(logic_outsb);
+
+BUILD_LOGIC_IO(w, u16)
+
+EXPORT_SYMBOL(logic_inw);
+EXPORT_SYMBOL(logic_outw);
+EXPORT_SYMBOL(logic_insw);
+EXPORT_SYMBOL(logic_outsw);
+
+BUILD_LOGIC_IO(l, u32)
+
+EXPORT_SYMBOL(logic_inl);
+EXPORT_SYMBOL(logic_outl);
+EXPORT_SYMBOL(logic_insl);
+EXPORT_SYMBOL(logic_outsl);
+#endif /* CONFIG_INDIRECT_PIO && PCI_IOBASE */
-- 
1.9.1

[toc] | [next] | [standalone]


#1614401

Fromkbuild test robot <lkp@intel.com>
Date2017-04-01 08:40 +0200
Message-ID<trkRz-7or-3@gated-at.bofh.it>
In reply to#1613141

[Multipart message — attachments visible in raw view] — view raw

Hi zhichang.yuan,

[auto build test ERROR on linus/master]
[also build test ERROR on v4.11-rc4 next-20170331]
[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/zhichang-yuan/LIBIO-Introduce-a-generic-PIO-mapping-method/20170401-104801
config: m68k-m5475evb_defconfig (attached as .config)
compiler: m68k-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=m68k 

All error/warnings (new ones prefixed by >>):

   lib/logic_pio.c:32:50: error: 'PIO_MAX_SECT' undeclared here (not in a function)
    static struct logic_pio_root logic_pio_root_list[PIO_MAX_SECT] = {
                                                     ^
   lib/logic_pio.c:52:3: error: 'PIO_CPU_MMIO' undeclared here (not in a function)
     [PIO_CPU_MMIO] = {
      ^
   lib/logic_pio.c:52:2: error: array index in initializer not of integer type
     [PIO_CPU_MMIO] = {
     ^
   lib/logic_pio.c:52:2: error: (near initialization for 'logic_pio_root_list')
   lib/logic_pio.c:53:3: error: field name not in record or union initializer
      .sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_CPU_MMIO].sec_head),
      ^
   lib/logic_pio.c:53:3: error: (near initialization for 'logic_pio_root_list')
   lib/logic_pio.c:54:3: error: field name not in record or union initializer
      .sec_min = PIO_SECT_MIN(PIO_CPU_MMIO),
      ^
   lib/logic_pio.c:54:3: error: (near initialization for 'logic_pio_root_list')
   lib/logic_pio.c:54:3: error: implicit declaration of function 'PIO_SECT_MIN' [-Werror=implicit-function-declaration]
   lib/logic_pio.c:55:3: error: field name not in record or union initializer
      .sec_max = PIO_SECT_MAX(PIO_CPU_MMIO),
      ^
   lib/logic_pio.c:55:3: error: (near initialization for 'logic_pio_root_list')
   lib/logic_pio.c:55:3: error: implicit declaration of function 'PIO_SECT_MAX' [-Werror=implicit-function-declaration]
   In file included from include/linux/list.h:8:0,
                    from include/linux/kobject.h:20,
                    from include/linux/of.h:21,
                    from lib/logic_pio.c:18:
   lib/logic_pio.c: In function 'logic_pio_find_range_byaddr':
>> include/linux/rculist.h:351:49: error: dereferencing pointer to incomplete type
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                                                    ^
   include/linux/kernel.h:852:18: note: in definition of macro 'container_of'
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                     ^
   include/linux/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   include/linux/kernel.h:852:48: warning: initialization from incompatible pointer type
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
   include/linux/rculist.h:277:2: note: in expansion of macro 'container_of'
     container_of(lockless_dereference(ptr), type, member)
     ^
   include/linux/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
>> include/linux/rculist.h:351:49: error: dereferencing pointer to incomplete type
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                                                    ^
   include/linux/kernel.h:853:3: note: in definition of macro 'container_of'
     (type *)( (char *)__mptr - offsetof(type,member) );})
      ^
   include/linux/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   In file included from include/linux/compiler.h:62:0,
                    from include/uapi/linux/stddef.h:1,
                    from include/linux/stddef.h:4,
                    from include/uapi/linux/posix_types.h:4,
                    from include/uapi/linux/types.h:13,
                    from include/linux/types.h:5,
                    from include/linux/of.h:18,
                    from lib/logic_pio.c:18:
>> include/linux/rculist.h:351:49: error: dereferencing pointer to incomplete type
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                                                    ^
   include/linux/compiler-gcc.h:161:21: note: in definition of macro '__compiler_offsetof'
     __builtin_offsetof(a, b)
                        ^
   include/linux/kernel.h:853:29: note: in expansion of macro 'offsetof'
     (type *)( (char *)__mptr - offsetof(type,member) );})
                                ^
   include/linux/rculist.h:277:2: note: in expansion of macro 'container_of'
     container_of(lockless_dereference(ptr), type, member)
     ^
   include/linux/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   In file included from include/linux/pid.h:4:0,
                    from include/linux/sched.h:13,
                    from arch/m68k/include/asm/pgtable_mm.h:10,
                    from arch/m68k/include/asm/pgtable.h:4,
                    from include/linux/mm.h:68,
                    from lib/logic_pio.c:20:
   include/linux/rculist.h:352:7: error: dereferencing pointer to incomplete type
      &pos->member != (head); \
          ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   In file included from include/linux/list.h:8:0,
                    from include/linux/kobject.h:20,
                    from include/linux/of.h:21,
                    from lib/logic_pio.c:18:
   include/linux/rculist.h:353:49: error: dereferencing pointer to incomplete type
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
                                                    ^
   include/linux/kernel.h:852:18: note: in definition of macro 'container_of'
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                     ^
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   include/linux/rculist.h:353:27: error: dereferencing pointer to incomplete type
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
                              ^
   include/linux/kernel.h:852:49: note: in definition of macro 'container_of'
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                    ^
>> include/linux/rculist.h:277:15: note: in expansion of macro 'lockless_dereference'
     container_of(lockless_dereference(ptr), type, member)
                  ^
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   include/linux/rculist.h:353:27: error: dereferencing pointer to incomplete type
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
                              ^
   include/linux/kernel.h:852:49: note: in definition of macro 'container_of'
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                    ^
   include/linux/compiler.h:323:22: note: in expansion of macro '__READ_ONCE'
    #define READ_ONCE(x) __READ_ONCE(x, 1)
                         ^
>> include/linux/compiler.h:574:26: note: in expansion of macro 'READ_ONCE'
     typeof(p) _________p1 = READ_ONCE(p); \
                             ^
>> include/linux/rculist.h:277:15: note: in expansion of macro 'lockless_dereference'
     container_of(lockless_dereference(ptr), type, member)
                  ^
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   include/linux/rculist.h:353:27: error: dereferencing pointer to incomplete type
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
                              ^
   include/linux/kernel.h:852:49: note: in definition of macro 'container_of'
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                    ^
   include/linux/compiler.h:323:22: note: in expansion of macro '__READ_ONCE'
    #define READ_ONCE(x) __READ_ONCE(x, 1)
                         ^
>> include/linux/compiler.h:574:26: note: in expansion of macro 'READ_ONCE'
     typeof(p) _________p1 = READ_ONCE(p); \
                             ^
>> include/linux/rculist.h:277:15: note: in expansion of macro 'lockless_dereference'
     container_of(lockless_dereference(ptr), type, member)
                  ^
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   include/linux/rculist.h:353:27: error: dereferencing pointer to incomplete type
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
                              ^
   include/linux/kernel.h:852:49: note: in definition of macro 'container_of'
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                    ^
   include/linux/compiler.h:323:22: note: in expansion of macro '__READ_ONCE'
    #define READ_ONCE(x) __READ_ONCE(x, 1)
                         ^
>> include/linux/compiler.h:574:26: note: in expansion of macro 'READ_ONCE'
     typeof(p) _________p1 = READ_ONCE(p); \
                             ^
>> include/linux/rculist.h:277:15: note: in expansion of macro 'lockless_dereference'
     container_of(lockless_dereference(ptr), type, member)
                  ^
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   include/linux/rculist.h:353:27: error: dereferencing pointer to incomplete type
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
                              ^
   include/linux/kernel.h:852:49: note: in definition of macro 'container_of'
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                    ^
   include/linux/compiler.h:323:22: note: in expansion of macro '__READ_ONCE'
    #define READ_ONCE(x) __READ_ONCE(x, 1)
                         ^
>> include/linux/compiler.h:574:26: note: in expansion of macro 'READ_ONCE'
     typeof(p) _________p1 = READ_ONCE(p); \
                             ^
>> include/linux/rculist.h:277:15: note: in expansion of macro 'lockless_dereference'
     container_of(lockless_dereference(ptr), type, member)
                  ^
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   include/linux/rculist.h:353:27: error: dereferencing pointer to incomplete type
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
                              ^
   include/linux/kernel.h:852:49: note: in definition of macro 'container_of'
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                    ^
   include/linux/compiler.h:323:22: note: in expansion of macro '__READ_ONCE'
    #define READ_ONCE(x) __READ_ONCE(x, 1)
                         ^
>> include/linux/compiler.h:574:26: note: in expansion of macro 'READ_ONCE'
     typeof(p) _________p1 = READ_ONCE(p); \
                             ^
>> include/linux/rculist.h:277:15: note: in expansion of macro 'lockless_dereference'
     container_of(lockless_dereference(ptr), type, member)
                  ^
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   include/linux/rculist.h:353:27: error: dereferencing pointer to incomplete type
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
                              ^
   include/linux/kernel.h:852:49: note: in definition of macro 'container_of'
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                    ^
>> include/linux/rculist.h:277:15: note: in expansion of macro 'lockless_dereference'
     container_of(lockless_dereference(ptr), type, member)
                  ^
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   include/linux/kernel.h:852:48: warning: initialization makes pointer from integer without a cast
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
   include/linux/rculist.h:277:2: note: in expansion of macro 'container_of'
     container_of(lockless_dereference(ptr), type, member)
     ^
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   include/linux/rculist.h:353:49: error: dereferencing pointer to incomplete type
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
                                                    ^
   include/linux/kernel.h:853:3: note: in definition of macro 'container_of'
     (type *)( (char *)__mptr - offsetof(type,member) );})
      ^
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
   In file included from include/linux/compiler.h:62:0,
                    from include/uapi/linux/stddef.h:1,
                    from include/linux/stddef.h:4,
                    from include/uapi/linux/posix_types.h:4,
                    from include/uapi/linux/types.h:13,
                    from include/linux/types.h:5,
                    from include/linux/of.h:18,
                    from lib/logic_pio.c:18:
   include/linux/rculist.h:353:49: error: dereferencing pointer to incomplete type
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
                                                    ^
   include/linux/compiler-gcc.h:161:21: note: in definition of macro '__compiler_offsetof'
     __builtin_offsetof(a, b)
                        ^
   include/linux/kernel.h:853:29: note: in expansion of macro 'offsetof'
     (type *)( (char *)__mptr - offsetof(type,member) );})
                                ^
   include/linux/rculist.h:277:2: note: in expansion of macro 'container_of'
     container_of(lockless_dereference(ptr), type, member)
     ^
   include/linux/rculist.h:353:9: note: in expansion of macro 'list_entry_rcu'
      pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
            ^
   lib/logic_pio.c:77:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(range, &io_range_list, list) {
     ^
>> lib/logic_pio.c:78:13: error: dereferencing pointer to incomplete type
      if (!range->pio_peer) {
                ^
   In file included from include/linux/kernel.h:13:0,
                    from include/linux/list.h:8,
                    from include/linux/kobject.h:20,
                    from include/linux/of.h:21,
                    from lib/logic_pio.c:18:
   lib/logic_pio.c:80:11: error: dereferencing pointer to incomplete type
        &range->hw_start);
              ^
   include/linux/printk.h:303:37: note: in definition of macro 'pr_warning'
     printk(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__)
                                        ^
>> lib/logic_pio.c:79:4: note: in expansion of macro 'pr_warn'
       pr_warn("Invalid cpu addr node(%pa) in list!\n",
       ^
   lib/logic_pio.c:83:12: error: dereferencing pointer to incomplete type
      if (range->fwnode != fwnode)
               ^
   lib/logic_pio.c:86:21: error: dereferencing pointer to incomplete type
      if (start >= range->hw_start + range->size ||
                        ^
   lib/logic_pio.c:86:39: error: dereferencing pointer to incomplete type
      if (start >= range->hw_start + range->size ||
                                          ^
   lib/logic_pio.c:87:15: error: dereferencing pointer to incomplete type
       end < range->hw_start)
                  ^
   lib/logic_pio.c:90:20: error: dereferencing pointer to incomplete type
      if (start < range->hw_start ||
                       ^
   lib/logic_pio.c:91:16: error: dereferencing pointer to incomplete type
       end >= range->hw_start + range->size)
                   ^
   lib/logic_pio.c:91:34: error: dereferencing pointer to incomplete type
       end >= range->hw_start + range->size)
                                     ^
   lib/logic_pio.c: In function 'logic_pio_alloc_range':
   lib/logic_pio.c:109:19: error: dereferencing pointer to incomplete type
     idle_start = root->sec_min;
                      ^
   lib/logic_pio.c:110:15: error: dereferencing pointer to incomplete type
     *prev = &root->sec_head;
                  ^
   In file included from include/linux/list.h:8:0,
                    from include/linux/kobject.h:20,
                    from include/linux/of.h:21,
                    from lib/logic_pio.c:18:
>> include/linux/rculist.h:351:49: error: dereferencing pointer to incomplete type
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                                                    ^
   include/linux/kernel.h:852:18: note: in definition of macro 'container_of'
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                     ^
   include/linux/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                ^
   lib/logic_pio.c:111:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(entry, &root->sec_head, list) {
     ^
   lib/logic_pio.c:111:38: error: dereferencing pointer to incomplete type
     list_for_each_entry_rcu(entry, &root->sec_head, list) {
                                         ^
   include/linux/kernel.h:852:49: note: in definition of macro 'container_of'
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                    ^
>> include/linux/rculist.h:277:15: note: in expansion of macro 'lockless_dereference'
     container_of(lockless_dereference(ptr), type, member)
                  ^
   include/linux/rculist.h:351:13: note: in expansion of macro 'list_entry_rcu'
     for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
                ^
   lib/logic_pio.c:111:2: note: in expansion of macro 'list_for_each_entry_rcu'
     list_for_each_entry_rcu(entry, &root->sec_head, list) {
     ^
   lib/logic_pio.c:111:38: error: dereferencing pointer to incomplete type
     list_for_each_entry_rcu(entry, &root->sec_head, list) {
                                         ^
   include/linux/kernel.h:852:49: note: in definition of macro 'container_of'
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                    ^
   include/linux/compiler.h:323:22: note: in expansion of macro '__READ_ONCE'
    #define READ_ONCE(x) __READ_ONCE(x, 1)
                         ^
>> include/linux/compiler.h:574:26: note: in expansion of macro 'READ_ONCE'
     typeof(p) _________p1 = READ_ONCE(p); \
                             ^

vim +351 include/linux/rculist.h

3943f42c Andrey Utkin         2014-11-14  271   * @member:     the name of the list_head within the struct.
72c6a987 Jiri Pirko           2009-04-14  272   *
72c6a987 Jiri Pirko           2009-04-14  273   * This primitive may safely run concurrently with the _rcu list-mutation
72c6a987 Jiri Pirko           2009-04-14  274   * primitives such as list_add_rcu() as long as it's guarded by rcu_read_lock().
72c6a987 Jiri Pirko           2009-04-14  275   */
72c6a987 Jiri Pirko           2009-04-14  276  #define list_entry_rcu(ptr, type, member) \
8db70b13 Patrick Marlier      2015-09-11 @277  	container_of(lockless_dereference(ptr), type, member)
72c6a987 Jiri Pirko           2009-04-14  278  
72c6a987 Jiri Pirko           2009-04-14  279  /**
f88022a4 Michel Machado       2012-04-10  280   * Where are list_empty_rcu() and list_first_entry_rcu()?
f88022a4 Michel Machado       2012-04-10  281   *
f88022a4 Michel Machado       2012-04-10  282   * Implementing those functions following their counterparts list_empty() and
f88022a4 Michel Machado       2012-04-10  283   * list_first_entry() is not advisable because they lead to subtle race
f88022a4 Michel Machado       2012-04-10  284   * conditions as the following snippet shows:
f88022a4 Michel Machado       2012-04-10  285   *
f88022a4 Michel Machado       2012-04-10  286   * if (!list_empty_rcu(mylist)) {
f88022a4 Michel Machado       2012-04-10  287   *	struct foo *bar = list_first_entry_rcu(mylist, struct foo, list_member);
f88022a4 Michel Machado       2012-04-10  288   *	do_something(bar);
f88022a4 Michel Machado       2012-04-10  289   * }
f88022a4 Michel Machado       2012-04-10  290   *
f88022a4 Michel Machado       2012-04-10  291   * The list may not be empty when list_empty_rcu checks it, but it may be when
f88022a4 Michel Machado       2012-04-10  292   * list_first_entry_rcu rereads the ->next pointer.
f88022a4 Michel Machado       2012-04-10  293   *
f88022a4 Michel Machado       2012-04-10  294   * Rereading the ->next pointer is not a problem for list_empty() and
f88022a4 Michel Machado       2012-04-10  295   * list_first_entry() because they would be protected by a lock that blocks
f88022a4 Michel Machado       2012-04-10  296   * writers.
f88022a4 Michel Machado       2012-04-10  297   *
f88022a4 Michel Machado       2012-04-10  298   * See list_first_or_null_rcu for an alternative.
f88022a4 Michel Machado       2012-04-10  299   */
f88022a4 Michel Machado       2012-04-10  300  
f88022a4 Michel Machado       2012-04-10  301  /**
f88022a4 Michel Machado       2012-04-10  302   * list_first_or_null_rcu - get the first element from a list
72c6a987 Jiri Pirko           2009-04-14  303   * @ptr:        the list head to take the element from.
72c6a987 Jiri Pirko           2009-04-14  304   * @type:       the type of the struct this is embedded in.
3943f42c Andrey Utkin         2014-11-14  305   * @member:     the name of the list_head within the struct.
72c6a987 Jiri Pirko           2009-04-14  306   *
f88022a4 Michel Machado       2012-04-10  307   * Note that if the list is empty, it returns NULL.
72c6a987 Jiri Pirko           2009-04-14  308   *
72c6a987 Jiri Pirko           2009-04-14  309   * This primitive may safely run concurrently with the _rcu list-mutation
72c6a987 Jiri Pirko           2009-04-14  310   * primitives such as list_add_rcu() as long as it's guarded by rcu_read_lock().
72c6a987 Jiri Pirko           2009-04-14  311   */
f88022a4 Michel Machado       2012-04-10  312  #define list_first_or_null_rcu(ptr, type, member) \
0adab9b9 Joe Perches          2013-12-05  313  ({ \
0adab9b9 Joe Perches          2013-12-05  314  	struct list_head *__ptr = (ptr); \
7d0ae808 Paul E. McKenney     2015-03-03  315  	struct list_head *__next = READ_ONCE(__ptr->next); \
0adab9b9 Joe Perches          2013-12-05  316  	likely(__ptr != __next) ? list_entry_rcu(__next, type, member) : NULL; \
f88022a4 Michel Machado       2012-04-10  317  })
72c6a987 Jiri Pirko           2009-04-14  318  
82524746 Franck Bui-Huu       2008-05-12  319  /**
ff3c44e6 Tom Herbert          2016-03-07  320   * list_next_or_null_rcu - get the first element from a list
ff3c44e6 Tom Herbert          2016-03-07  321   * @head:	the head for the list.
ff3c44e6 Tom Herbert          2016-03-07  322   * @ptr:        the list head to take the next element from.
ff3c44e6 Tom Herbert          2016-03-07  323   * @type:       the type of the struct this is embedded in.
ff3c44e6 Tom Herbert          2016-03-07  324   * @member:     the name of the list_head within the struct.
ff3c44e6 Tom Herbert          2016-03-07  325   *
ff3c44e6 Tom Herbert          2016-03-07  326   * Note that if the ptr is at the end of the list, NULL is returned.
ff3c44e6 Tom Herbert          2016-03-07  327   *
ff3c44e6 Tom Herbert          2016-03-07  328   * This primitive may safely run concurrently with the _rcu list-mutation
ff3c44e6 Tom Herbert          2016-03-07  329   * primitives such as list_add_rcu() as long as it's guarded by rcu_read_lock().
ff3c44e6 Tom Herbert          2016-03-07  330   */
ff3c44e6 Tom Herbert          2016-03-07  331  #define list_next_or_null_rcu(head, ptr, type, member) \
ff3c44e6 Tom Herbert          2016-03-07  332  ({ \
ff3c44e6 Tom Herbert          2016-03-07  333  	struct list_head *__head = (head); \
ff3c44e6 Tom Herbert          2016-03-07  334  	struct list_head *__ptr = (ptr); \
ff3c44e6 Tom Herbert          2016-03-07  335  	struct list_head *__next = READ_ONCE(__ptr->next); \
ff3c44e6 Tom Herbert          2016-03-07  336  	likely(__next != __head) ? list_entry_rcu(__next, type, \
ff3c44e6 Tom Herbert          2016-03-07  337  						  member) : NULL; \
ff3c44e6 Tom Herbert          2016-03-07  338  })
ff3c44e6 Tom Herbert          2016-03-07  339  
ff3c44e6 Tom Herbert          2016-03-07  340  /**
82524746 Franck Bui-Huu       2008-05-12  341   * list_for_each_entry_rcu	-	iterate over rcu list of given type
82524746 Franck Bui-Huu       2008-05-12  342   * @pos:	the type * to use as a loop cursor.
82524746 Franck Bui-Huu       2008-05-12  343   * @head:	the head for your list.
3943f42c Andrey Utkin         2014-11-14  344   * @member:	the name of the list_head within the struct.
82524746 Franck Bui-Huu       2008-05-12  345   *
82524746 Franck Bui-Huu       2008-05-12  346   * This list-traversal primitive may safely run concurrently with
82524746 Franck Bui-Huu       2008-05-12  347   * the _rcu list-mutation primitives such as list_add_rcu()
82524746 Franck Bui-Huu       2008-05-12  348   * as long as the traversal is guarded by rcu_read_lock().
82524746 Franck Bui-Huu       2008-05-12  349   */
82524746 Franck Bui-Huu       2008-05-12  350  #define list_for_each_entry_rcu(pos, head, member) \
72c6a987 Jiri Pirko           2009-04-14 @351  	for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
e66eed65 Linus Torvalds       2011-05-19  352  		&pos->member != (head); \
72c6a987 Jiri Pirko           2009-04-14 @353  		pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
82524746 Franck Bui-Huu       2008-05-12  354  
82524746 Franck Bui-Huu       2008-05-12  355  /**
69b90729 Alexey Kardashevskiy 2015-12-05  356   * list_entry_lockless - get the struct for this entry

:::::: The code at line 351 was first introduced by commit
:::::: 72c6a9870f901045f2464c3dc6ee8914bfdc07aa rculist.h: introduce list_entry_rcu() and list_first_entry_rcu()

:::::: TO: Jiri Pirko <jpirko@redhat.com>
:::::: CC: Ingo Molnar <mingo@elte.hu>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web