aboutsummaryrefslogtreecommitdiffstats
path: root/lib/logic_pio.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/logic_pio.c')
-rw-r--r--lib/logic_pio.c73
1 files changed, 54 insertions, 19 deletions
diff --git a/lib/logic_pio.c b/lib/logic_pio.c
index feea48fd1a0d..905027574e5d 100644
--- a/lib/logic_pio.c
+++ b/lib/logic_pio.c
@@ -35,7 +35,7 @@ int logic_pio_register_range(struct logic_pio_hwaddr *new_range)
35 struct logic_pio_hwaddr *range; 35 struct logic_pio_hwaddr *range;
36 resource_size_t start; 36 resource_size_t start;
37 resource_size_t end; 37 resource_size_t end;
38 resource_size_t mmio_sz = 0; 38 resource_size_t mmio_end = 0;
39 resource_size_t iio_sz = MMIO_UPPER_LIMIT; 39 resource_size_t iio_sz = MMIO_UPPER_LIMIT;
40 int ret = 0; 40 int ret = 0;
41 41
@@ -46,7 +46,7 @@ int logic_pio_register_range(struct logic_pio_hwaddr *new_range)
46 end = new_range->hw_start + new_range->size; 46 end = new_range->hw_start + new_range->size;
47 47
48 mutex_lock(&io_range_mutex); 48 mutex_lock(&io_range_mutex);
49 list_for_each_entry_rcu(range, &io_range_list, list) { 49 list_for_each_entry(range, &io_range_list, list) {
50 if (range->fwnode == new_range->fwnode) { 50 if (range->fwnode == new_range->fwnode) {
51 /* range already there */ 51 /* range already there */
52 goto end_register; 52 goto end_register;
@@ -56,7 +56,7 @@ int logic_pio_register_range(struct logic_pio_hwaddr *new_range)
56 /* for MMIO ranges we need to check for overlap */ 56 /* for MMIO ranges we need to check for overlap */
57 if (start >= range->hw_start + range->size || 57 if (start >= range->hw_start + range->size ||
58 end < range->hw_start) { 58 end < range->hw_start) {
59 mmio_sz += range->size; 59 mmio_end = range->io_start + range->size;
60 } else { 60 } else {
61 ret = -EFAULT; 61 ret = -EFAULT;
62 goto end_register; 62 goto end_register;
@@ -69,16 +69,16 @@ int logic_pio_register_range(struct logic_pio_hwaddr *new_range)
69 69
70 /* range not registered yet, check for available space */ 70 /* range not registered yet, check for available space */
71 if (new_range->flags == LOGIC_PIO_CPU_MMIO) { 71 if (new_range->flags == LOGIC_PIO_CPU_MMIO) {
72 if (mmio_sz + new_range->size - 1 > MMIO_UPPER_LIMIT) { 72 if (mmio_end + new_range->size - 1 > MMIO_UPPER_LIMIT) {
73 /* if it's too big check if 64K space can be reserved */ 73 /* if it's too big check if 64K space can be reserved */
74 if (mmio_sz + SZ_64K - 1 > MMIO_UPPER_LIMIT) { 74 if (mmio_end + SZ_64K - 1 > MMIO_UPPER_LIMIT) {
75 ret = -E2BIG; 75 ret = -E2BIG;
76 goto end_register; 76 goto end_register;
77 } 77 }
78 new_range->size = SZ_64K; 78 new_range->size = SZ_64K;
79 pr_warn("Requested IO range too big, new size set to 64K\n"); 79 pr_warn("Requested IO range too big, new size set to 64K\n");
80 } 80 }
81 new_range->io_start = mmio_sz; 81 new_range->io_start = mmio_end;
82 } else if (new_range->flags == LOGIC_PIO_INDIRECT) { 82 } else if (new_range->flags == LOGIC_PIO_INDIRECT) {
83 if (iio_sz + new_range->size - 1 > IO_SPACE_LIMIT) { 83 if (iio_sz + new_range->size - 1 > IO_SPACE_LIMIT) {
84 ret = -E2BIG; 84 ret = -E2BIG;
@@ -99,6 +99,20 @@ end_register:
99} 99}
100 100
101/** 101/**
102 * logic_pio_unregister_range - unregister a logical PIO range for a host
103 * @range: pointer to the IO range which has been already registered.
104 *
105 * Unregister a previously-registered IO range node.
106 */
107void logic_pio_unregister_range(struct logic_pio_hwaddr *range)
108{
109 mutex_lock(&io_range_mutex);
110 list_del_rcu(&range->list);
111 mutex_unlock(&io_range_mutex);
112 synchronize_rcu();
113}
114
115/**
102 * find_io_range_by_fwnode - find logical PIO range for given FW node 116 * find_io_range_by_fwnode - find logical PIO range for given FW node
103 * @fwnode: FW node handle associated with logical PIO range 117 * @fwnode: FW node handle associated with logical PIO range
104 * 118 *
@@ -108,26 +122,38 @@ end_register:
108 */ 122 */
109struct logic_pio_hwaddr *find_io_range_by_fwnode(struct fwnode_handle *fwnode) 123struct logic_pio_hwaddr *find_io_range_by_fwnode(struct fwnode_handle *fwnode)
110{ 124{
111 struct logic_pio_hwaddr *range; 125 struct logic_pio_hwaddr *range, *found_range = NULL;
112 126
127 rcu_read_lock();
113 list_for_each_entry_rcu(range, &io_range_list, list) { 128 list_for_each_entry_rcu(range, &io_range_list, list) {
114 if (range->fwnode == fwnode) 129 if (range->fwnode == fwnode) {
115 return range; 130 found_range = range;
131 break;
132 }
116 } 133 }
117 return NULL; 134 rcu_read_unlock();
135
136 return found_range;
118} 137}
119 138
120/* Return a registered range given an input PIO token */ 139/* Return a registered range given an input PIO token */
121static struct logic_pio_hwaddr *find_io_range(unsigned long pio) 140static struct logic_pio_hwaddr *find_io_range(unsigned long pio)
122{ 141{
123 struct logic_pio_hwaddr *range; 142 struct logic_pio_hwaddr *range, *found_range = NULL;
124 143
144 rcu_read_lock();
125 list_for_each_entry_rcu(range, &io_range_list, list) { 145 list_for_each_entry_rcu(range, &io_range_list, list) {
126 if (in_range(pio, range->io_start, range->size)) 146 if (in_range(pio, range->io_start, range->size)) {
127 return range; 147 found_range = range;
148 break;
149 }
128 } 150 }
129 pr_err("PIO entry token %lx invalid\n", pio); 151 rcu_read_unlock();
130 return NULL; 152
153 if (!found_range)
154 pr_err("PIO entry token 0x%lx invalid\n", pio);
155
156 return found_range;
131} 157}
132 158
133/** 159/**
@@ -180,14 +206,23 @@ unsigned long logic_pio_trans_cpuaddr(resource_size_t addr)
180{ 206{
181 struct logic_pio_hwaddr *range; 207 struct logic_pio_hwaddr *range;
182 208
209 rcu_read_lock();
183 list_for_each_entry_rcu(range, &io_range_list, list) { 210 list_for_each_entry_rcu(range, &io_range_list, list) {
184 if (range->flags != LOGIC_PIO_CPU_MMIO) 211 if (range->flags != LOGIC_PIO_CPU_MMIO)
185 continue; 212 continue;
186 if (in_range(addr, range->hw_start, range->size)) 213 if (in_range(addr, range->hw_start, range->size)) {
187 return addr - range->hw_start + range->io_start; 214 unsigned long cpuaddr;
215
216 cpuaddr = addr - range->hw_start + range->io_start;
217
218 rcu_read_unlock();
219 return cpuaddr;
220 }
188 } 221 }
189 pr_err("addr %llx not registered in io_range_list\n", 222 rcu_read_unlock();
190 (unsigned long long) addr); 223
224 pr_err("addr %pa not registered in io_range_list\n", &addr);
225
191 return ~0UL; 226 return ~0UL;
192} 227}
193 228