Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * Copyright (C) 2017 HiSilicon Limited, All Rights Reserved.
0004  * Author: Gabriele Paoloni <gabriele.paoloni@huawei.com>
0005  * Author: Zhichang Yuan <yuanzhichang@hisilicon.com>
0006  * Author: John Garry <john.garry@huawei.com>
0007  */
0008 
0009 #define pr_fmt(fmt) "LOGIC PIO: " fmt
0010 
0011 #include <linux/of.h>
0012 #include <linux/io.h>
0013 #include <linux/logic_pio.h>
0014 #include <linux/mm.h>
0015 #include <linux/rculist.h>
0016 #include <linux/sizes.h>
0017 #include <linux/slab.h>
0018 
0019 /* The unique hardware address list */
0020 static LIST_HEAD(io_range_list);
0021 static DEFINE_MUTEX(io_range_mutex);
0022 
0023 /* Consider a kernel general helper for this */
0024 #define in_range(b, first, len)        ((b) >= (first) && (b) < (first) + (len))
0025 
0026 /**
0027  * logic_pio_register_range - register logical PIO range for a host
0028  * @new_range: pointer to the IO range to be registered.
0029  *
0030  * Returns 0 on success, the error code in case of failure.
0031  * If the range already exists, -EEXIST will be returned, which should be
0032  * considered a success.
0033  *
0034  * Register a new IO range node in the IO range list.
0035  */
0036 int logic_pio_register_range(struct logic_pio_hwaddr *new_range)
0037 {
0038     struct logic_pio_hwaddr *range;
0039     resource_size_t start;
0040     resource_size_t end;
0041     resource_size_t mmio_end = 0;
0042     resource_size_t iio_sz = MMIO_UPPER_LIMIT;
0043     int ret = 0;
0044 
0045     if (!new_range || !new_range->fwnode || !new_range->size ||
0046         (new_range->flags == LOGIC_PIO_INDIRECT && !new_range->ops))
0047         return -EINVAL;
0048 
0049     start = new_range->hw_start;
0050     end = new_range->hw_start + new_range->size;
0051 
0052     mutex_lock(&io_range_mutex);
0053     list_for_each_entry(range, &io_range_list, list) {
0054         if (range->fwnode == new_range->fwnode) {
0055             /* range already there */
0056             ret = -EEXIST;
0057             goto end_register;
0058         }
0059         if (range->flags == LOGIC_PIO_CPU_MMIO &&
0060             new_range->flags == LOGIC_PIO_CPU_MMIO) {
0061             /* for MMIO ranges we need to check for overlap */
0062             if (start >= range->hw_start + range->size ||
0063                 end < range->hw_start) {
0064                 mmio_end = range->io_start + range->size;
0065             } else {
0066                 ret = -EFAULT;
0067                 goto end_register;
0068             }
0069         } else if (range->flags == LOGIC_PIO_INDIRECT &&
0070                new_range->flags == LOGIC_PIO_INDIRECT) {
0071             iio_sz += range->size;
0072         }
0073     }
0074 
0075     /* range not registered yet, check for available space */
0076     if (new_range->flags == LOGIC_PIO_CPU_MMIO) {
0077         if (mmio_end + new_range->size - 1 > MMIO_UPPER_LIMIT) {
0078             /* if it's too big check if 64K space can be reserved */
0079             if (mmio_end + SZ_64K - 1 > MMIO_UPPER_LIMIT) {
0080                 ret = -E2BIG;
0081                 goto end_register;
0082             }
0083             new_range->size = SZ_64K;
0084             pr_warn("Requested IO range too big, new size set to 64K\n");
0085         }
0086         new_range->io_start = mmio_end;
0087     } else if (new_range->flags == LOGIC_PIO_INDIRECT) {
0088         if (iio_sz + new_range->size - 1 > IO_SPACE_LIMIT) {
0089             ret = -E2BIG;
0090             goto end_register;
0091         }
0092         new_range->io_start = iio_sz;
0093     } else {
0094         /* invalid flag */
0095         ret = -EINVAL;
0096         goto end_register;
0097     }
0098 
0099     list_add_tail_rcu(&new_range->list, &io_range_list);
0100 
0101 end_register:
0102     mutex_unlock(&io_range_mutex);
0103     return ret;
0104 }
0105 
0106 /**
0107  * logic_pio_unregister_range - unregister a logical PIO range for a host
0108  * @range: pointer to the IO range which has been already registered.
0109  *
0110  * Unregister a previously-registered IO range node.
0111  */
0112 void logic_pio_unregister_range(struct logic_pio_hwaddr *range)
0113 {
0114     mutex_lock(&io_range_mutex);
0115     list_del_rcu(&range->list);
0116     mutex_unlock(&io_range_mutex);
0117     synchronize_rcu();
0118 }
0119 
0120 /**
0121  * find_io_range_by_fwnode - find logical PIO range for given FW node
0122  * @fwnode: FW node handle associated with logical PIO range
0123  *
0124  * Returns pointer to node on success, NULL otherwise.
0125  *
0126  * Traverse the io_range_list to find the registered node for @fwnode.
0127  */
0128 struct logic_pio_hwaddr *find_io_range_by_fwnode(struct fwnode_handle *fwnode)
0129 {
0130     struct logic_pio_hwaddr *range, *found_range = NULL;
0131 
0132     rcu_read_lock();
0133     list_for_each_entry_rcu(range, &io_range_list, list) {
0134         if (range->fwnode == fwnode) {
0135             found_range = range;
0136             break;
0137         }
0138     }
0139     rcu_read_unlock();
0140 
0141     return found_range;
0142 }
0143 
0144 /* Return a registered range given an input PIO token */
0145 static struct logic_pio_hwaddr *find_io_range(unsigned long pio)
0146 {
0147     struct logic_pio_hwaddr *range, *found_range = NULL;
0148 
0149     rcu_read_lock();
0150     list_for_each_entry_rcu(range, &io_range_list, list) {
0151         if (in_range(pio, range->io_start, range->size)) {
0152             found_range = range;
0153             break;
0154         }
0155     }
0156     rcu_read_unlock();
0157 
0158     if (!found_range)
0159         pr_err("PIO entry token 0x%lx invalid\n", pio);
0160 
0161     return found_range;
0162 }
0163 
0164 /**
0165  * logic_pio_to_hwaddr - translate logical PIO to HW address
0166  * @pio: logical PIO value
0167  *
0168  * Returns HW address if valid, ~0 otherwise.
0169  *
0170  * Translate the input logical PIO to the corresponding hardware address.
0171  * The input PIO should be unique in the whole logical PIO space.
0172  */
0173 resource_size_t logic_pio_to_hwaddr(unsigned long pio)
0174 {
0175     struct logic_pio_hwaddr *range;
0176 
0177     range = find_io_range(pio);
0178     if (range)
0179         return range->hw_start + pio - range->io_start;
0180 
0181     return (resource_size_t)~0;
0182 }
0183 
0184 /**
0185  * logic_pio_trans_hwaddr - translate HW address to logical PIO
0186  * @fwnode: FW node reference for the host
0187  * @addr: Host-relative HW address
0188  * @size: size to translate
0189  *
0190  * Returns Logical PIO value if successful, ~0UL otherwise
0191  */
0192 unsigned long logic_pio_trans_hwaddr(struct fwnode_handle *fwnode,
0193                      resource_size_t addr, resource_size_t size)
0194 {
0195     struct logic_pio_hwaddr *range;
0196 
0197     range = find_io_range_by_fwnode(fwnode);
0198     if (!range || range->flags == LOGIC_PIO_CPU_MMIO) {
0199         pr_err("IO range not found or invalid\n");
0200         return ~0UL;
0201     }
0202     if (range->size < size) {
0203         pr_err("resource size %pa cannot fit in IO range size %pa\n",
0204                &size, &range->size);
0205         return ~0UL;
0206     }
0207     return addr - range->hw_start + range->io_start;
0208 }
0209 
0210 unsigned long logic_pio_trans_cpuaddr(resource_size_t addr)
0211 {
0212     struct logic_pio_hwaddr *range;
0213 
0214     rcu_read_lock();
0215     list_for_each_entry_rcu(range, &io_range_list, list) {
0216         if (range->flags != LOGIC_PIO_CPU_MMIO)
0217             continue;
0218         if (in_range(addr, range->hw_start, range->size)) {
0219             unsigned long cpuaddr;
0220 
0221             cpuaddr = addr - range->hw_start + range->io_start;
0222 
0223             rcu_read_unlock();
0224             return cpuaddr;
0225         }
0226     }
0227     rcu_read_unlock();
0228 
0229     pr_err("addr %pa not registered in io_range_list\n", &addr);
0230 
0231     return ~0UL;
0232 }
0233 
0234 #if defined(CONFIG_INDIRECT_PIO) && defined(PCI_IOBASE)
0235 #define BUILD_LOGIC_IO(bwl, type)                   \
0236 type logic_in##bwl(unsigned long addr)                  \
0237 {                                   \
0238     type ret = (type)~0;                        \
0239                                     \
0240     if (addr < MMIO_UPPER_LIMIT) {                  \
0241         ret = _in##bwl(addr);                   \
0242     } else if (addr >= MMIO_UPPER_LIMIT && addr < IO_SPACE_LIMIT) { \
0243         struct logic_pio_hwaddr *entry = find_io_range(addr);   \
0244                                     \
0245         if (entry)                      \
0246             ret = entry->ops->in(entry->hostdata,       \
0247                     addr, sizeof(type));        \
0248         else                            \
0249             WARN_ON_ONCE(1);                \
0250     }                               \
0251     return ret;                         \
0252 }                                   \
0253                                     \
0254 void logic_out##bwl(type value, unsigned long addr)         \
0255 {                                   \
0256     if (addr < MMIO_UPPER_LIMIT) {                  \
0257         _out##bwl(value, addr);             \
0258     } else if (addr >= MMIO_UPPER_LIMIT && addr < IO_SPACE_LIMIT) { \
0259         struct logic_pio_hwaddr *entry = find_io_range(addr);   \
0260                                     \
0261         if (entry)                      \
0262             entry->ops->out(entry->hostdata,        \
0263                     addr, value, sizeof(type)); \
0264         else                            \
0265             WARN_ON_ONCE(1);                \
0266     }                               \
0267 }                                   \
0268                                     \
0269 void logic_ins##bwl(unsigned long addr, void *buffer,           \
0270             unsigned int count)                 \
0271 {                                   \
0272     if (addr < MMIO_UPPER_LIMIT) {                  \
0273         reads##bwl(PCI_IOBASE + addr, buffer, count);       \
0274     } else if (addr >= MMIO_UPPER_LIMIT && addr < IO_SPACE_LIMIT) { \
0275         struct logic_pio_hwaddr *entry = find_io_range(addr);   \
0276                                     \
0277         if (entry)                      \
0278             entry->ops->ins(entry->hostdata,        \
0279                 addr, buffer, sizeof(type), count); \
0280         else                            \
0281             WARN_ON_ONCE(1);                \
0282     }                               \
0283                                     \
0284 }                                   \
0285                                     \
0286 void logic_outs##bwl(unsigned long addr, const void *buffer,        \
0287              unsigned int count)                \
0288 {                                   \
0289     if (addr < MMIO_UPPER_LIMIT) {                  \
0290         writes##bwl(PCI_IOBASE + addr, buffer, count);      \
0291     } else if (addr >= MMIO_UPPER_LIMIT && addr < IO_SPACE_LIMIT) { \
0292         struct logic_pio_hwaddr *entry = find_io_range(addr);   \
0293                                     \
0294         if (entry)                      \
0295             entry->ops->outs(entry->hostdata,       \
0296                 addr, buffer, sizeof(type), count); \
0297         else                            \
0298             WARN_ON_ONCE(1);                \
0299     }                               \
0300 }
0301 
0302 BUILD_LOGIC_IO(b, u8)
0303 EXPORT_SYMBOL(logic_inb);
0304 EXPORT_SYMBOL(logic_insb);
0305 EXPORT_SYMBOL(logic_outb);
0306 EXPORT_SYMBOL(logic_outsb);
0307 
0308 BUILD_LOGIC_IO(w, u16)
0309 EXPORT_SYMBOL(logic_inw);
0310 EXPORT_SYMBOL(logic_insw);
0311 EXPORT_SYMBOL(logic_outw);
0312 EXPORT_SYMBOL(logic_outsw);
0313 
0314 BUILD_LOGIC_IO(l, u32)
0315 EXPORT_SYMBOL(logic_inl);
0316 EXPORT_SYMBOL(logic_insl);
0317 EXPORT_SYMBOL(logic_outl);
0318 EXPORT_SYMBOL(logic_outsl);
0319 
0320 #endif /* CONFIG_INDIRECT_PIO && PCI_IOBASE */