diff options
Diffstat (limited to 'lib/logic_pio.c')
-rw-r--r-- | lib/logic_pio.c | 73 |
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 | */ | ||
107 | void 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 | */ |
109 | struct logic_pio_hwaddr *find_io_range_by_fwnode(struct fwnode_handle *fwnode) | 123 | struct 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 */ |
121 | static struct logic_pio_hwaddr *find_io_range(unsigned long pio) | 140 | static 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 | ||