VisionFive2 Linux kernel

StarFive Tech Linux Kernel for VisionFive (JH7110) boards (mirror)

More than 9999 Commits   32 Branches   54 Tags
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800   1) // SPDX-License-Identifier: GPL-2.0+
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800   2) /*
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800   3)  * Copyright (C) 2017 HiSilicon Limited, All Rights Reserved.
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800   4)  * Author: Gabriele Paoloni <gabriele.paoloni@huawei.com>
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800   5)  * Author: Zhichang Yuan <yuanzhichang@hisilicon.com>
0376fa72a4553 (John Garry         2019-11-05 01:22:15 +0800   6)  * Author: John Garry <john.garry@huawei.com>
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800   7)  */
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800   8) 
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800   9) #define pr_fmt(fmt)	"LOGIC PIO: " fmt
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  10) 
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  11) #include <linux/of.h>
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  12) #include <linux/io.h>
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  13) #include <linux/logic_pio.h>
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  14) #include <linux/mm.h>
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  15) #include <linux/rculist.h>
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  16) #include <linux/sizes.h>
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  17) #include <linux/slab.h>
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  18) 
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  19) /* The unique hardware address list */
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  20) static LIST_HEAD(io_range_list);
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  21) static DEFINE_MUTEX(io_range_mutex);
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  22) 
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  23) /* Consider a kernel general helper for this */
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  24) #define in_range(b, first, len)        ((b) >= (first) && (b) < (first) + (len))
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  25) 
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  26) /**
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  27)  * logic_pio_register_range - register logical PIO range for a host
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  28)  * @new_range: pointer to the IO range to be registered.
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  29)  *
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  30)  * Returns 0 on success, the error code in case of failure.
f6bda644fa3a7 (Geert Uytterhoeven 2021-02-02 11:03:32 +0100  31)  * If the range already exists, -EEXIST will be returned, which should be
f6bda644fa3a7 (Geert Uytterhoeven 2021-02-02 11:03:32 +0100  32)  * considered a success.
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  33)  *
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  34)  * Register a new IO range node in the IO range list.
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  35)  */
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  36) int logic_pio_register_range(struct logic_pio_hwaddr *new_range)
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  37) {
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  38) 	struct logic_pio_hwaddr *range;
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  39) 	resource_size_t start;
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  40) 	resource_size_t end;
0a27142bd1ee2 (John Garry         2019-07-30 21:29:53 +0800  41) 	resource_size_t mmio_end = 0;
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  42) 	resource_size_t iio_sz = MMIO_UPPER_LIMIT;
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  43) 	int ret = 0;
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  44) 
0376fa72a4553 (John Garry         2019-11-05 01:22:15 +0800  45) 	if (!new_range || !new_range->fwnode || !new_range->size ||
0376fa72a4553 (John Garry         2019-11-05 01:22:15 +0800  46) 	    (new_range->flags == LOGIC_PIO_INDIRECT && !new_range->ops))
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  47) 		return -EINVAL;
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  48) 
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  49) 	start = new_range->hw_start;
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  50) 	end = new_range->hw_start + new_range->size;
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  51) 
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  52) 	mutex_lock(&io_range_mutex);
06709e81c668f (John Garry         2019-07-30 21:29:52 +0800  53) 	list_for_each_entry(range, &io_range_list, list) {
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  54) 		if (range->fwnode == new_range->fwnode) {
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  55) 			/* range already there */
f6bda644fa3a7 (Geert Uytterhoeven 2021-02-02 11:03:32 +0100  56) 			ret = -EEXIST;
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  57) 			goto end_register;
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  58) 		}
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  59) 		if (range->flags == LOGIC_PIO_CPU_MMIO &&
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  60) 		    new_range->flags == LOGIC_PIO_CPU_MMIO) {
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  61) 			/* for MMIO ranges we need to check for overlap */
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  62) 			if (start >= range->hw_start + range->size ||
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  63) 			    end < range->hw_start) {
0a27142bd1ee2 (John Garry         2019-07-30 21:29:53 +0800  64) 				mmio_end = range->io_start + range->size;
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  65) 			} else {
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  66) 				ret = -EFAULT;
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  67) 				goto end_register;
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  68) 			}
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  69) 		} else if (range->flags == LOGIC_PIO_INDIRECT &&
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  70) 			   new_range->flags == LOGIC_PIO_INDIRECT) {
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  71) 			iio_sz += range->size;
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  72) 		}
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  73) 	}
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  74) 
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  75) 	/* range not registered yet, check for available space */
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  76) 	if (new_range->flags == LOGIC_PIO_CPU_MMIO) {
0a27142bd1ee2 (John Garry         2019-07-30 21:29:53 +0800  77) 		if (mmio_end + new_range->size - 1 > MMIO_UPPER_LIMIT) {
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  78) 			/* if it's too big check if 64K space can be reserved */
0a27142bd1ee2 (John Garry         2019-07-30 21:29:53 +0800  79) 			if (mmio_end + SZ_64K - 1 > MMIO_UPPER_LIMIT) {
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  80) 				ret = -E2BIG;
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  81) 				goto end_register;
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  82) 			}
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  83) 			new_range->size = SZ_64K;
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  84) 			pr_warn("Requested IO range too big, new size set to 64K\n");
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  85) 		}
0a27142bd1ee2 (John Garry         2019-07-30 21:29:53 +0800  86) 		new_range->io_start = mmio_end;
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  87) 	} else if (new_range->flags == LOGIC_PIO_INDIRECT) {
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  88) 		if (iio_sz + new_range->size - 1 > IO_SPACE_LIMIT) {
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  89) 			ret = -E2BIG;
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  90) 			goto end_register;
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  91) 		}
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  92) 		new_range->io_start = iio_sz;
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  93) 	} else {
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  94) 		/* invalid flag */
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  95) 		ret = -EINVAL;
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  96) 		goto end_register;
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  97) 	}
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  98) 
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800  99) 	list_add_tail_rcu(&new_range->list, &io_range_list);
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 100) 
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 101) end_register:
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 102) 	mutex_unlock(&io_range_mutex);
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 103) 	return ret;
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 104) }
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 105) 
b884e2de2afc6 (John Garry         2019-07-30 21:29:54 +0800 106) /**
b884e2de2afc6 (John Garry         2019-07-30 21:29:54 +0800 107)  * logic_pio_unregister_range - unregister a logical PIO range for a host
b884e2de2afc6 (John Garry         2019-07-30 21:29:54 +0800 108)  * @range: pointer to the IO range which has been already registered.
b884e2de2afc6 (John Garry         2019-07-30 21:29:54 +0800 109)  *
b884e2de2afc6 (John Garry         2019-07-30 21:29:54 +0800 110)  * Unregister a previously-registered IO range node.
b884e2de2afc6 (John Garry         2019-07-30 21:29:54 +0800 111)  */
b884e2de2afc6 (John Garry         2019-07-30 21:29:54 +0800 112) void logic_pio_unregister_range(struct logic_pio_hwaddr *range)
b884e2de2afc6 (John Garry         2019-07-30 21:29:54 +0800 113) {
b884e2de2afc6 (John Garry         2019-07-30 21:29:54 +0800 114) 	mutex_lock(&io_range_mutex);
b884e2de2afc6 (John Garry         2019-07-30 21:29:54 +0800 115) 	list_del_rcu(&range->list);
b884e2de2afc6 (John Garry         2019-07-30 21:29:54 +0800 116) 	mutex_unlock(&io_range_mutex);
b884e2de2afc6 (John Garry         2019-07-30 21:29:54 +0800 117) 	synchronize_rcu();
b884e2de2afc6 (John Garry         2019-07-30 21:29:54 +0800 118) }
b884e2de2afc6 (John Garry         2019-07-30 21:29:54 +0800 119) 
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 120) /**
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 121)  * find_io_range_by_fwnode - find logical PIO range for given FW node
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 122)  * @fwnode: FW node handle associated with logical PIO range
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 123)  *
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 124)  * Returns pointer to node on success, NULL otherwise.
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 125)  *
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 126)  * Traverse the io_range_list to find the registered node for @fwnode.
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 127)  */
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 128) struct logic_pio_hwaddr *find_io_range_by_fwnode(struct fwnode_handle *fwnode)
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 129) {
06709e81c668f (John Garry         2019-07-30 21:29:52 +0800 130) 	struct logic_pio_hwaddr *range, *found_range = NULL;
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 131) 
06709e81c668f (John Garry         2019-07-30 21:29:52 +0800 132) 	rcu_read_lock();
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 133) 	list_for_each_entry_rcu(range, &io_range_list, list) {
06709e81c668f (John Garry         2019-07-30 21:29:52 +0800 134) 		if (range->fwnode == fwnode) {
06709e81c668f (John Garry         2019-07-30 21:29:52 +0800 135) 			found_range = range;
06709e81c668f (John Garry         2019-07-30 21:29:52 +0800 136) 			break;
06709e81c668f (John Garry         2019-07-30 21:29:52 +0800 137) 		}
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 138) 	}
06709e81c668f (John Garry         2019-07-30 21:29:52 +0800 139) 	rcu_read_unlock();
06709e81c668f (John Garry         2019-07-30 21:29:52 +0800 140) 
06709e81c668f (John Garry         2019-07-30 21:29:52 +0800 141) 	return found_range;
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 142) }
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 143) 
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 144) /* Return a registered range given an input PIO token */
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 145) static struct logic_pio_hwaddr *find_io_range(unsigned long pio)
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 146) {
06709e81c668f (John Garry         2019-07-30 21:29:52 +0800 147) 	struct logic_pio_hwaddr *range, *found_range = NULL;
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 148) 
06709e81c668f (John Garry         2019-07-30 21:29:52 +0800 149) 	rcu_read_lock();
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 150) 	list_for_each_entry_rcu(range, &io_range_list, list) {
06709e81c668f (John Garry         2019-07-30 21:29:52 +0800 151) 		if (in_range(pio, range->io_start, range->size)) {
06709e81c668f (John Garry         2019-07-30 21:29:52 +0800 152) 			found_range = range;
06709e81c668f (John Garry         2019-07-30 21:29:52 +0800 153) 			break;
06709e81c668f (John Garry         2019-07-30 21:29:52 +0800 154) 		}
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 155) 	}
06709e81c668f (John Garry         2019-07-30 21:29:52 +0800 156) 	rcu_read_unlock();
06709e81c668f (John Garry         2019-07-30 21:29:52 +0800 157) 
06709e81c668f (John Garry         2019-07-30 21:29:52 +0800 158) 	if (!found_range)
06709e81c668f (John Garry         2019-07-30 21:29:52 +0800 159) 		pr_err("PIO entry token 0x%lx invalid\n", pio);
06709e81c668f (John Garry         2019-07-30 21:29:52 +0800 160) 
06709e81c668f (John Garry         2019-07-30 21:29:52 +0800 161) 	return found_range;
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 162) }
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 163) 
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 164) /**
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 165)  * logic_pio_to_hwaddr - translate logical PIO to HW address
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 166)  * @pio: logical PIO value
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 167)  *
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 168)  * Returns HW address if valid, ~0 otherwise.
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 169)  *
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 170)  * Translate the input logical PIO to the corresponding hardware address.
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 171)  * The input PIO should be unique in the whole logical PIO space.
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 172)  */
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 173) resource_size_t logic_pio_to_hwaddr(unsigned long pio)
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 174) {
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 175) 	struct logic_pio_hwaddr *range;
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 176) 
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 177) 	range = find_io_range(pio);
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 178) 	if (range)
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 179) 		return range->hw_start + pio - range->io_start;
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 180) 
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 181) 	return (resource_size_t)~0;
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 182) }
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 183) 
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 184) /**
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 185)  * logic_pio_trans_hwaddr - translate HW address to logical PIO
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 186)  * @fwnode: FW node reference for the host
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 187)  * @addr: Host-relative HW address
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 188)  * @size: size to translate
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 189)  *
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 190)  * Returns Logical PIO value if successful, ~0UL otherwise
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 191)  */
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 192) unsigned long logic_pio_trans_hwaddr(struct fwnode_handle *fwnode,
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 193) 				     resource_size_t addr, resource_size_t size)
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 194) {
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 195) 	struct logic_pio_hwaddr *range;
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 196) 
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 197) 	range = find_io_range_by_fwnode(fwnode);
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 198) 	if (!range || range->flags == LOGIC_PIO_CPU_MMIO) {
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 199) 		pr_err("IO range not found or invalid\n");
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 200) 		return ~0UL;
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 201) 	}
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 202) 	if (range->size < size) {
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 203) 		pr_err("resource size %pa cannot fit in IO range size %pa\n",
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 204) 		       &size, &range->size);
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 205) 		return ~0UL;
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 206) 	}
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 207) 	return addr - range->hw_start + range->io_start;
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 208) }
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 209) 
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 210) unsigned long logic_pio_trans_cpuaddr(resource_size_t addr)
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 211) {
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 212) 	struct logic_pio_hwaddr *range;
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 213) 
06709e81c668f (John Garry         2019-07-30 21:29:52 +0800 214) 	rcu_read_lock();
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 215) 	list_for_each_entry_rcu(range, &io_range_list, list) {
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 216) 		if (range->flags != LOGIC_PIO_CPU_MMIO)
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 217) 			continue;
06709e81c668f (John Garry         2019-07-30 21:29:52 +0800 218) 		if (in_range(addr, range->hw_start, range->size)) {
06709e81c668f (John Garry         2019-07-30 21:29:52 +0800 219) 			unsigned long cpuaddr;
06709e81c668f (John Garry         2019-07-30 21:29:52 +0800 220) 
06709e81c668f (John Garry         2019-07-30 21:29:52 +0800 221) 			cpuaddr = addr - range->hw_start + range->io_start;
06709e81c668f (John Garry         2019-07-30 21:29:52 +0800 222) 
06709e81c668f (John Garry         2019-07-30 21:29:52 +0800 223) 			rcu_read_unlock();
06709e81c668f (John Garry         2019-07-30 21:29:52 +0800 224) 			return cpuaddr;
06709e81c668f (John Garry         2019-07-30 21:29:52 +0800 225) 		}
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 226) 	}
06709e81c668f (John Garry         2019-07-30 21:29:52 +0800 227) 	rcu_read_unlock();
06709e81c668f (John Garry         2019-07-30 21:29:52 +0800 228) 
06709e81c668f (John Garry         2019-07-30 21:29:52 +0800 229) 	pr_err("addr %pa not registered in io_range_list\n", &addr);
06709e81c668f (John Garry         2019-07-30 21:29:52 +0800 230) 
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 231) 	return ~0UL;
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 232) }
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 233) 
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 234) #if defined(CONFIG_INDIRECT_PIO) && defined(PCI_IOBASE)
26c4c6ce808cd (John Garry         2020-03-28 00:06:13 +0800 235) #define BUILD_LOGIC_IO(bwl, type)					\
26c4c6ce808cd (John Garry         2020-03-28 00:06:13 +0800 236) type logic_in##bwl(unsigned long addr)					\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 237) {									\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 238) 	type ret = (type)~0;						\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 239) 									\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 240) 	if (addr < MMIO_UPPER_LIMIT) {					\
4acaa93ef6437 (John Garry         2020-03-28 00:06:14 +0800 241) 		ret = _in##bwl(addr);					\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 242) 	} else if (addr >= MMIO_UPPER_LIMIT && addr < IO_SPACE_LIMIT) { \
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 243) 		struct logic_pio_hwaddr *entry = find_io_range(addr);	\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 244) 									\
0376fa72a4553 (John Garry         2019-11-05 01:22:15 +0800 245) 		if (entry)						\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 246) 			ret = entry->ops->in(entry->hostdata,		\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 247) 					addr, sizeof(type));		\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 248) 		else							\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 249) 			WARN_ON_ONCE(1);				\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 250) 	}								\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 251) 	return ret;							\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 252) }									\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 253) 									\
26c4c6ce808cd (John Garry         2020-03-28 00:06:13 +0800 254) void logic_out##bwl(type value, unsigned long addr)			\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 255) {									\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 256) 	if (addr < MMIO_UPPER_LIMIT) {					\
4acaa93ef6437 (John Garry         2020-03-28 00:06:14 +0800 257) 		_out##bwl(value, addr);				\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 258) 	} else if (addr >= MMIO_UPPER_LIMIT && addr < IO_SPACE_LIMIT) {	\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 259) 		struct logic_pio_hwaddr *entry = find_io_range(addr);	\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 260) 									\
0376fa72a4553 (John Garry         2019-11-05 01:22:15 +0800 261) 		if (entry)						\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 262) 			entry->ops->out(entry->hostdata,		\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 263) 					addr, value, sizeof(type));	\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 264) 		else							\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 265) 			WARN_ON_ONCE(1);				\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 266) 	}								\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 267) }									\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 268) 									\
26c4c6ce808cd (John Garry         2020-03-28 00:06:13 +0800 269) void logic_ins##bwl(unsigned long addr, void *buffer,			\
26c4c6ce808cd (John Garry         2020-03-28 00:06:13 +0800 270) 		    unsigned int count)					\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 271) {									\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 272) 	if (addr < MMIO_UPPER_LIMIT) {					\
26c4c6ce808cd (John Garry         2020-03-28 00:06:13 +0800 273) 		reads##bwl(PCI_IOBASE + addr, buffer, count);		\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 274) 	} else if (addr >= MMIO_UPPER_LIMIT && addr < IO_SPACE_LIMIT) {	\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 275) 		struct logic_pio_hwaddr *entry = find_io_range(addr);	\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 276) 									\
0376fa72a4553 (John Garry         2019-11-05 01:22:15 +0800 277) 		if (entry)						\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 278) 			entry->ops->ins(entry->hostdata,		\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 279) 				addr, buffer, sizeof(type), count);	\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 280) 		else							\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 281) 			WARN_ON_ONCE(1);				\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 282) 	}								\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 283) 									\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 284) }									\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 285) 									\
26c4c6ce808cd (John Garry         2020-03-28 00:06:13 +0800 286) void logic_outs##bwl(unsigned long addr, const void *buffer,		\
26c4c6ce808cd (John Garry         2020-03-28 00:06:13 +0800 287) 		     unsigned int count)				\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 288) {									\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 289) 	if (addr < MMIO_UPPER_LIMIT) {					\
26c4c6ce808cd (John Garry         2020-03-28 00:06:13 +0800 290) 		writes##bwl(PCI_IOBASE + addr, buffer, count);		\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 291) 	} else if (addr >= MMIO_UPPER_LIMIT && addr < IO_SPACE_LIMIT) {	\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 292) 		struct logic_pio_hwaddr *entry = find_io_range(addr);	\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 293) 									\
0376fa72a4553 (John Garry         2019-11-05 01:22:15 +0800 294) 		if (entry)						\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 295) 			entry->ops->outs(entry->hostdata,		\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 296) 				addr, buffer, sizeof(type), count);	\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 297) 		else							\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 298) 			WARN_ON_ONCE(1);				\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 299) 	}								\
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 300) }
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 301) 
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 302) BUILD_LOGIC_IO(b, u8)
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 303) EXPORT_SYMBOL(logic_inb);
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 304) EXPORT_SYMBOL(logic_insb);
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 305) EXPORT_SYMBOL(logic_outb);
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 306) EXPORT_SYMBOL(logic_outsb);
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 307) 
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 308) BUILD_LOGIC_IO(w, u16)
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 309) EXPORT_SYMBOL(logic_inw);
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 310) EXPORT_SYMBOL(logic_insw);
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 311) EXPORT_SYMBOL(logic_outw);
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 312) EXPORT_SYMBOL(logic_outsw);
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 313) 
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 314) BUILD_LOGIC_IO(l, u32)
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 315) EXPORT_SYMBOL(logic_inl);
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 316) EXPORT_SYMBOL(logic_insl);
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 317) EXPORT_SYMBOL(logic_outl);
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 318) EXPORT_SYMBOL(logic_outsl);
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 319) 
031e3601869c8 (Zhichang Yuan      2018-03-15 02:15:50 +0800 320) #endif /* CONFIG_INDIRECT_PIO && PCI_IOBASE */