Message ID | 1490887619-61732-2-git-send-email-yuanzhichang@hisilicon.com |
---|---|
State | Not Applicable |
Headers | show |
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: alpha-allyesconfig (attached as .config) compiler: alpha-linux-gnu-gcc (Debian 6.1.1-9) 6.1.1 20160705 reproduce: wget https://raw.githubusercontent.com/01org/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # save the attached .config to linux build tree make.cross ARCH=alpha 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:39:3: error: 'PIO_CPU_MMIO' undeclared here (not in a function) [PIO_CPU_MMIO ... PIO_INDIRECT - 1] = { ^~~~~~~~~~~~ >> lib/logic_pio.c:39:20: error: 'PIO_INDIRECT' undeclared here (not in a function) [PIO_CPU_MMIO ... PIO_INDIRECT - 1] = { ^~~~~~~~~~~~ >> lib/logic_pio.c:39:3: error: array index in initializer not of integer type [PIO_CPU_MMIO ... PIO_INDIRECT - 1] = { ^~~~~~~~~~~~ lib/logic_pio.c:39:3: note: (near initialization for 'logic_pio_root_list') >> lib/logic_pio.c:40: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:40:3: note: (near initialization for 'logic_pio_root_list') lib/logic_pio.c:41:3: error: field name not in record or union initializer .sec_min = PIO_SECT_MIN(PIO_CPU_MMIO), ^ lib/logic_pio.c:41:3: note: (near initialization for 'logic_pio_root_list') >> lib/logic_pio.c:41:14: error: implicit declaration of function 'PIO_SECT_MIN' [-Werror=implicit-function-declaration] .sec_min = PIO_SECT_MIN(PIO_CPU_MMIO), ^~~~~~~~~~~~ lib/logic_pio.c:42:3: error: field name not in record or union initializer .sec_max = PIO_SECT_MAX(PIO_INDIRECT - 1), ^ lib/logic_pio.c:42:3: note: (near initialization for 'logic_pio_root_list') >> lib/logic_pio.c:42:14: error: implicit declaration of function 'PIO_SECT_MAX' [-Werror=implicit-function-declaration] .sec_max = PIO_SECT_MAX(PIO_INDIRECT - 1), ^~~~~~~~~~~~ lib/logic_pio.c:46:3: error: array index in initializer not of integer type [PIO_INDIRECT] = { ^~~~~~~~~~~~ lib/logic_pio.c:46:3: note: (near initialization for 'logic_pio_root_list') lib/logic_pio.c:47:3: error: field name not in record or union initializer .sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_INDIRECT].sec_head), ^ lib/logic_pio.c:47:3: note: (near initialization for 'logic_pio_root_list') lib/logic_pio.c:48:3: error: field name not in record or union initializer .sec_min = PIO_SECT_MIN(PIO_INDIRECT), ^ lib/logic_pio.c:48:3: note: (near initialization for 'logic_pio_root_list') lib/logic_pio.c:49:3: error: field name not in record or union initializer .sec_max = PIO_SECT_MAX(PIO_INDIRECT), ^ lib/logic_pio.c:49:3: note: (near initialization for 'logic_pio_root_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: lib/logic_pio.c: In function 'logic_pio_find_range_byaddr': >> include/linux/rculist.h:351:49: error: dereferencing pointer to incomplete type 'struct logic_pio_hwaddr' 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: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types] 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/kernel.h:852:48: warning: initialization makes pointer from integer without a cast [-Wint-conversion] 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) { ^~~~~~~~~~~~~~~~~~~~~~~ lib/logic_pio.c: In function 'logic_pio_alloc_range': >> lib/logic_pio.c:109:19: error: dereferencing pointer to incomplete type 'struct logic_pio_root' idle_start = root->sec_min; ^~ 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 'struct logic_pio_sect' 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) { ^~~~~~~~~~~~~~~~~~~~~~~ >> include/linux/kernel.h:852:48: warning: initialization makes pointer from integer without a cast [-Wint-conversion] const typeof( ((type *)0)->member ) *__mptr = (ptr); \ ^ vim +/PIO_MAX_SECT +32 lib/logic_pio.c 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 > 18 #include <linux/of.h> 19 #include <linux/io.h> 20 #include <linux/mm.h> 21 #include <linux/rculist.h> 22 #include <linux/sizes.h> 23 #include <linux/slab.h> 24 25 /* The unique hardware address list. */ 26 static LIST_HEAD(io_range_list); 27 static DEFINE_MUTEX(io_range_mutex); 28 29 /* 30 * These are the lists for PIO. The highest PIO_SECT_BITS of PIO is the index. 31 */ > 32 static struct logic_pio_root logic_pio_root_list[PIO_MAX_SECT] = { 33 #ifdef CONFIG_INDIRECT_PIO 34 /* 35 * At this moment, assign all the other logic PIO space to MMIO. 36 * If more elements added, please adjust the ending index and .sec_max; 37 * Please keep MMIO element started from index ZERO. 38 */ > 39 [PIO_CPU_MMIO ... PIO_INDIRECT - 1] = { > 40 .sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_CPU_MMIO].sec_head), > 41 .sec_min = PIO_SECT_MIN(PIO_CPU_MMIO), > 42 .sec_max = PIO_SECT_MAX(PIO_INDIRECT - 1), 43 }, 44 45 /* The last element */ 46 [PIO_INDIRECT] = { 47 .sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_INDIRECT].sec_head), 48 .sec_min = PIO_SECT_MIN(PIO_INDIRECT), 49 .sec_max = PIO_SECT_MAX(PIO_INDIRECT), 50 }, 51 #else 52 [PIO_CPU_MMIO] = { 53 .sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_CPU_MMIO].sec_head), 54 .sec_min = PIO_SECT_MIN(PIO_CPU_MMIO), 55 .sec_max = PIO_SECT_MAX(PIO_CPU_MMIO), 56 }, 57 58 #endif 59 }; 60 61 /* 62 * Search a io_range registered which match the fwnode and addr. 63 * 64 * @fwnode: the host fwnode which must be valid; 65 * @start: the start hardware address of this search; 66 * @end: the end hardware address of this search. can be equal to @start; 67 * 68 * return NULL when there is no matched node; IS_ERR() means ERROR; 69 * valid virtual address represent a matched node was found. 70 */ 71 static struct logic_pio_hwaddr * 72 logic_pio_find_range_byaddr(struct fwnode_handle *fwnode, 73 resource_size_t start, resource_size_t end) 74 { 75 struct logic_pio_hwaddr *range; 76 > 77 list_for_each_entry_rcu(range, &io_range_list, list) { 78 if (!range->pio_peer) { 79 pr_warn("Invalid cpu addr node(%pa) in list!\n", 80 &range->hw_start); 81 continue; 82 } 83 if (range->fwnode != fwnode) 84 continue; 85 /* without any overlap with current range */ 86 if (start >= range->hw_start + range->size || 87 end < range->hw_start) 88 continue; 89 /* overlap is not supported now. */ 90 if (start < range->hw_start || 91 end >= range->hw_start + range->size) 92 return ERR_PTR(-EBUSY); 93 /* had been registered. */ 94 return range; 95 } 96 97 return NULL; 98 } 99 100 101 static int logic_pio_alloc_range(struct logic_pio_root *root, 102 resource_size_t size, unsigned long align, 103 struct list_head **prev, resource_size_t *pio_alloc) 104 { 105 struct logic_pio_sect *entry; 106 resource_size_t tmp_start; 107 resource_size_t idle_start, idle_end; 108 > 109 idle_start = root->sec_min; 110 *prev = &root->sec_head; 111 list_for_each_entry_rcu(entry, &root->sec_head, list) { 112 if (!entry->hwpeer || 113 idle_start > entry->io_start) { 114 WARN(1, "skip an invalid io range during traversal!\n"); 115 goto nextentry; 116 } 117 /* set the end edge. */ 118 if (idle_start == entry->io_start) { 119 struct logic_pio_sect *next; 120 121 idle_start = entry->io_start + entry->hwpeer->size; > 122 next = list_next_or_null_rcu(&root->sec_head, > 123 &entry->list, struct logic_pio_sect, list); 124 if (next) { 125 entry = next; 126 } else { 127 *prev = &entry->list; 128 break; 129 } 130 } 131 idle_end = entry->io_start - 1; 132 133 /* contiguous range... */ 134 if (idle_start > idle_end) 135 goto nextentry; 136 137 tmp_start = idle_start; 138 idle_start = ALIGN(idle_start, align); 139 if (idle_start >= tmp_start && 140 idle_start + size <= idle_end) { 141 *prev = &entry->list; 142 *pio_alloc = idle_start; 143 return 0; 144 } 145 146 nextentry: 147 idle_start = entry->io_start + entry->hwpeer->size; 148 *prev = &entry->list; 149 } 150 /* check the last free gap... */ 151 idle_end = root->sec_max; 152 153 tmp_start = idle_start; 154 idle_start = ALIGN(idle_start, align); 155 if (idle_start >= tmp_start && 156 idle_start + size <= idle_end) { 157 *pio_alloc = idle_start; 158 return 0; 159 } 160 161 return -EBUSY; 162 } 163 164 /* 165 * register a io range node in the io range list. 166 * 167 * @newrange: pointer to the io range to be registered. 168 * 169 * return 'newrange' when success, ERR_VALUE() is for failures. 170 * specially, return a valid pointer which is not equal to 'newrange' when 171 * the io range had been registered before. 172 */ 173 struct logic_pio_hwaddr 174 *logic_pio_register_range(struct logic_pio_hwaddr *newrange, 175 unsigned long align) 176 { 177 struct logic_pio_hwaddr *range; 178 struct logic_pio_sect *newsect; 179 resource_size_t pio_alloc; 180 struct list_head *prev, *hwprev; 181 unsigned long sect_id; 182 int err; 183 184 if (!newrange || !newrange->fwnode || !newrange->size) 185 return ERR_PTR(-EINVAL); 186 187 sect_id = newrange->flags; 188 if (sect_id >= PIO_MAX_SECT) 189 return ERR_PTR(-EINVAL); 190 191 mutex_lock(&io_range_mutex); 192 range = logic_pio_find_range_byaddr(newrange->fwnode, 193 newrange->hw_start, 194 newrange->hw_start + newrange->size - 1); 195 if (range) { 196 if (!IS_ERR(range)) 197 pr_info("the request IO range had been registered!\n"); 198 else 199 pr_err("registering IO[%pa - sz%pa) got failed!\n", 200 &newrange->hw_start, &newrange->size); 201 mutex_unlock(&io_range_mutex); 202 return range; 203 } 204 205 err = logic_pio_alloc_range(&logic_pio_root_list[sect_id], 206 newrange->size, align, &prev, &pio_alloc); 207 if (err) { 208 pr_err("can't find free %pa logical IO range!\n", 209 &newrange->size); 210 goto exitproc; 211 } 212 213 if (prev == &logic_pio_root_list[sect_id].sec_head) { 214 hwprev = &io_range_list; 215 } else { > 216 newsect = to_pio_sect(prev); > 217 hwprev = &newsect->hwpeer->list; 218 } 219 220 newsect = kzalloc(sizeof(*newsect), GFP_KERNEL); --- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation
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
Hi, Thanks for your report! I am sorry for that! This issue was caused by missing the '#include <linux/logic_pio.h>' in logic_pio.c for some architectures where the 'asm-generic/io.h' wasn't been included. Will be fixed in the next V9. Apologized for this! -Zhichang On 04/01/2017 01:58 PM, kbuild test robot wrote: > 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: alpha-allyesconfig (attached as .config) > compiler: alpha-linux-gnu-gcc (Debian 6.1.1-9) 6.1.1 20160705 > reproduce: > wget https://raw.githubusercontent.com/01org/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross > chmod +x ~/bin/make.cross > # save the attached .config to linux build tree > make.cross ARCH=alpha > > 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:39:3: error: 'PIO_CPU_MMIO' undeclared here (not in a function) > [PIO_CPU_MMIO ... PIO_INDIRECT - 1] = { > ^~~~~~~~~~~~ >>> lib/logic_pio.c:39:20: error: 'PIO_INDIRECT' undeclared here (not in a function) > [PIO_CPU_MMIO ... PIO_INDIRECT - 1] = { > ^~~~~~~~~~~~ >>> lib/logic_pio.c:39:3: error: array index in initializer not of integer type > [PIO_CPU_MMIO ... PIO_INDIRECT - 1] = { > ^~~~~~~~~~~~ > lib/logic_pio.c:39:3: note: (near initialization for 'logic_pio_root_list') >>> lib/logic_pio.c:40: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:40:3: note: (near initialization for 'logic_pio_root_list') > lib/logic_pio.c:41:3: error: field name not in record or union initializer > .sec_min = PIO_SECT_MIN(PIO_CPU_MMIO), > ^ > lib/logic_pio.c:41:3: note: (near initialization for 'logic_pio_root_list') >>> lib/logic_pio.c:41:14: error: implicit declaration of function 'PIO_SECT_MIN' [-Werror=implicit-function-declaration] > .sec_min = PIO_SECT_MIN(PIO_CPU_MMIO), > ^~~~~~~~~~~~ > lib/logic_pio.c:42:3: error: field name not in record or union initializer > .sec_max = PIO_SECT_MAX(PIO_INDIRECT - 1), > ^ > lib/logic_pio.c:42:3: note: (near initialization for 'logic_pio_root_list') >>> lib/logic_pio.c:42:14: error: implicit declaration of function 'PIO_SECT_MAX' [-Werror=implicit-function-declaration] > .sec_max = PIO_SECT_MAX(PIO_INDIRECT - 1), > ^~~~~~~~~~~~ > lib/logic_pio.c:46:3: error: array index in initializer not of integer type > [PIO_INDIRECT] = { > ^~~~~~~~~~~~ > lib/logic_pio.c:46:3: note: (near initialization for 'logic_pio_root_list') > lib/logic_pio.c:47:3: error: field name not in record or union initializer > .sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_INDIRECT].sec_head), > ^ > lib/logic_pio.c:47:3: note: (near initialization for 'logic_pio_root_list') > lib/logic_pio.c:48:3: error: field name not in record or union initializer > .sec_min = PIO_SECT_MIN(PIO_INDIRECT), > ^ > lib/logic_pio.c:48:3: note: (near initialization for 'logic_pio_root_list') > lib/logic_pio.c:49:3: error: field name not in record or union initializer > .sec_max = PIO_SECT_MAX(PIO_INDIRECT), > ^ > lib/logic_pio.c:49:3: note: (near initialization for 'logic_pio_root_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: > lib/logic_pio.c: In function 'logic_pio_find_range_byaddr': >>> include/linux/rculist.h:351:49: error: dereferencing pointer to incomplete type 'struct logic_pio_hwaddr' > 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: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types] > 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/kernel.h:852:48: warning: initialization makes pointer from integer without a cast [-Wint-conversion] > 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) { > ^~~~~~~~~~~~~~~~~~~~~~~ > lib/logic_pio.c: In function 'logic_pio_alloc_range': >>> lib/logic_pio.c:109:19: error: dereferencing pointer to incomplete type 'struct logic_pio_root' > idle_start = root->sec_min; > ^~ > 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 'struct logic_pio_sect' > 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) { > ^~~~~~~~~~~~~~~~~~~~~~~ >>> include/linux/kernel.h:852:48: warning: initialization makes pointer from integer without a cast [-Wint-conversion] > const typeof( ((type *)0)->member ) *__mptr = (ptr); \ > ^ > > vim +/PIO_MAX_SECT +32 lib/logic_pio.c > > 12 * GNU General Public License for more details. > 13 * > 14 * You should have received a copy of the GNU General Public License > 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. > 16 */ > 17 > > 18 #include <linux/of.h> > 19 #include <linux/io.h> > 20 #include <linux/mm.h> > 21 #include <linux/rculist.h> > 22 #include <linux/sizes.h> > 23 #include <linux/slab.h> > 24 > 25 /* The unique hardware address list. */ > 26 static LIST_HEAD(io_range_list); > 27 static DEFINE_MUTEX(io_range_mutex); > 28 > 29 /* > 30 * These are the lists for PIO. The highest PIO_SECT_BITS of PIO is the index. > 31 */ > > 32 static struct logic_pio_root logic_pio_root_list[PIO_MAX_SECT] = { > 33 #ifdef CONFIG_INDIRECT_PIO > 34 /* > 35 * At this moment, assign all the other logic PIO space to MMIO. > 36 * If more elements added, please adjust the ending index and .sec_max; > 37 * Please keep MMIO element started from index ZERO. > 38 */ > > 39 [PIO_CPU_MMIO ... PIO_INDIRECT - 1] = { > > 40 .sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_CPU_MMIO].sec_head), > > 41 .sec_min = PIO_SECT_MIN(PIO_CPU_MMIO), > > 42 .sec_max = PIO_SECT_MAX(PIO_INDIRECT - 1), > 43 }, > 44 > 45 /* The last element */ > 46 [PIO_INDIRECT] = { > 47 .sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_INDIRECT].sec_head), > 48 .sec_min = PIO_SECT_MIN(PIO_INDIRECT), > 49 .sec_max = PIO_SECT_MAX(PIO_INDIRECT), > 50 }, > 51 #else > 52 [PIO_CPU_MMIO] = { > 53 .sec_head = LIST_HEAD_INIT(logic_pio_root_list[PIO_CPU_MMIO].sec_head), > 54 .sec_min = PIO_SECT_MIN(PIO_CPU_MMIO), > 55 .sec_max = PIO_SECT_MAX(PIO_CPU_MMIO), > 56 }, > 57 > 58 #endif > 59 }; > 60 > 61 /* > 62 * Search a io_range registered which match the fwnode and addr. > 63 * > 64 * @fwnode: the host fwnode which must be valid; > 65 * @start: the start hardware address of this search; > 66 * @end: the end hardware address of this search. can be equal to @start; > 67 * > 68 * return NULL when there is no matched node; IS_ERR() means ERROR; > 69 * valid virtual address represent a matched node was found. > 70 */ > 71 static struct logic_pio_hwaddr * > 72 logic_pio_find_range_byaddr(struct fwnode_handle *fwnode, > 73 resource_size_t start, resource_size_t end) > 74 { > 75 struct logic_pio_hwaddr *range; > 76 > > 77 list_for_each_entry_rcu(range, &io_range_list, list) { > 78 if (!range->pio_peer) { > 79 pr_warn("Invalid cpu addr node(%pa) in list!\n", > 80 &range->hw_start); > 81 continue; > 82 } > 83 if (range->fwnode != fwnode) > 84 continue; > 85 /* without any overlap with current range */ > 86 if (start >= range->hw_start + range->size || > 87 end < range->hw_start) > 88 continue; > 89 /* overlap is not supported now. */ > 90 if (start < range->hw_start || > 91 end >= range->hw_start + range->size) > 92 return ERR_PTR(-EBUSY); > 93 /* had been registered. */ > 94 return range; > 95 } > 96 > 97 return NULL; > 98 } > 99 > 100 > 101 static int logic_pio_alloc_range(struct logic_pio_root *root, > 102 resource_size_t size, unsigned long align, > 103 struct list_head **prev, resource_size_t *pio_alloc) > 104 { > 105 struct logic_pio_sect *entry; > 106 resource_size_t tmp_start; > 107 resource_size_t idle_start, idle_end; > 108 > > 109 idle_start = root->sec_min; > 110 *prev = &root->sec_head; > 111 list_for_each_entry_rcu(entry, &root->sec_head, list) { > 112 if (!entry->hwpeer || > 113 idle_start > entry->io_start) { > 114 WARN(1, "skip an invalid io range during traversal!\n"); > 115 goto nextentry; > 116 } > 117 /* set the end edge. */ > 118 if (idle_start == entry->io_start) { > 119 struct logic_pio_sect *next; > 120 > 121 idle_start = entry->io_start + entry->hwpeer->size; > > 122 next = list_next_or_null_rcu(&root->sec_head, > > 123 &entry->list, struct logic_pio_sect, list); > 124 if (next) { > 125 entry = next; > 126 } else { > 127 *prev = &entry->list; > 128 break; > 129 } > 130 } > 131 idle_end = entry->io_start - 1; > 132 > 133 /* contiguous range... */ > 134 if (idle_start > idle_end) > 135 goto nextentry; > 136 > 137 tmp_start = idle_start; > 138 idle_start = ALIGN(idle_start, align); > 139 if (idle_start >= tmp_start && > 140 idle_start + size <= idle_end) { > 141 *prev = &entry->list; > 142 *pio_alloc = idle_start; > 143 return 0; > 144 } > 145 > 146 nextentry: > 147 idle_start = entry->io_start + entry->hwpeer->size; > 148 *prev = &entry->list; > 149 } > 150 /* check the last free gap... */ > 151 idle_end = root->sec_max; > 152 > 153 tmp_start = idle_start; > 154 idle_start = ALIGN(idle_start, align); > 155 if (idle_start >= tmp_start && > 156 idle_start + size <= idle_end) { > 157 *pio_alloc = idle_start; > 158 return 0; > 159 } > 160 > 161 return -EBUSY; > 162 } > 163 > 164 /* > 165 * register a io range node in the io range list. > 166 * > 167 * @newrange: pointer to the io range to be registered. > 168 * > 169 * return 'newrange' when success, ERR_VALUE() is for failures. > 170 * specially, return a valid pointer which is not equal to 'newrange' when > 171 * the io range had been registered before. > 172 */ > 173 struct logic_pio_hwaddr > 174 *logic_pio_register_range(struct logic_pio_hwaddr *newrange, > 175 unsigned long align) > 176 { > 177 struct logic_pio_hwaddr *range; > 178 struct logic_pio_sect *newsect; > 179 resource_size_t pio_alloc; > 180 struct list_head *prev, *hwprev; > 181 unsigned long sect_id; > 182 int err; > 183 > 184 if (!newrange || !newrange->fwnode || !newrange->size) > 185 return ERR_PTR(-EINVAL); > 186 > 187 sect_id = newrange->flags; > 188 if (sect_id >= PIO_MAX_SECT) > 189 return ERR_PTR(-EINVAL); > 190 > 191 mutex_lock(&io_range_mutex); > 192 range = logic_pio_find_range_byaddr(newrange->fwnode, > 193 newrange->hw_start, > 194 newrange->hw_start + newrange->size - 1); > 195 if (range) { > 196 if (!IS_ERR(range)) > 197 pr_info("the request IO range had been registered!\n"); > 198 else > 199 pr_err("registering IO[%pa - sz%pa) got failed!\n", > 200 &newrange->hw_start, &newrange->size); > 201 mutex_unlock(&io_range_mutex); > 202 return range; > 203 } > 204 > 205 err = logic_pio_alloc_range(&logic_pio_root_list[sect_id], > 206 newrange->size, align, &prev, &pio_alloc); > 207 if (err) { > 208 pr_err("can't find free %pa logical IO range!\n", > 209 &newrange->size); > 210 goto exitproc; > 211 } > 212 > 213 if (prev == &logic_pio_root_list[sect_id].sec_head) { > 214 hwprev = &io_range_list; > 215 } else { > > 216 newsect = to_pio_sect(prev); > > 217 hwprev = &newsect->hwpeer->list; > 218 } > 219 > 220 newsect = kzalloc(sizeof(*newsect), GFP_KERNEL); > > --- > 0-DAY kernel test infrastructure Open Source Technology Center > https://lists.01.org/pipermail/kbuild-all Intel Corporation >
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 */