Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

char: xillybus: Move class-related functions to new xillybus_class.c

This patch is a preparation for adding another related driver, XillyUSB.
In order to share some code between the existing Xillybus driver and the
one to be added, some functions are moved to xillybus_class.c

XILLYBUS_CLASS is added to Kconfig and is common to all drivers in this
group. The relation with the existing XILLYBUS symbol is "select" rather
than "depends on" XILLYBUS_CLASS, or else "make olddefconfig" will silently
turn off XILLYBUS, which is currently enabled in several distributions.

XILLYBUS_CLASS doesn't depend on anything else, hence using it with
"select" poses no risk for a broken configuration.

After the future addition of the XillyUSB module, the tree of symbols
will be as follows:

XILLYBUS_CLASS --+-- XILLYBUS --+-- XILLYBUS_PCIE
| |
| +-- XILLYBUS_OF
|
+-- XILLYUSB

XILLYBUS is for drivers based upon memory registers + DMA-based interfaces,
and it's combined with XILLYBUS_PCIE and/or XILLYBUS_OF.

XILLYUSB is for the USB variant only.

Or a more detailed, bottom-up outline:

* CONFIG_XILLYBUS_PCIE -> xillybus_pcie.c: Functions related to PCIe.
* CONFIG_XILLYBUS_OF -> xillybus_of.c: Functions related to Xillybus as a
peripheral on an FPGA / Processor combo chip.
* CONFIG_XILLYBUS -> xillybus_core.c: Functions that are common to the two
above, mainly access to the peripheral with memory-mapped registers and
DMA.
* CONFIG_XILLYUSB -> xillyusb.c: The driver for the USB variant, accesses
the peripheral through the USB framework.
* CONFIG_XILLYBUS_CLASS -> xillybus_class.c: The new module, which contains
the class and API parts that would otherwise appear both in
xillybus_core.c and xillyusb.c. Contains utility functions for the two
latter.

And since I'm at it, comments on the module names are added in the
Kconfig's help part.

The functions are exported with the non-GPL EXPORT_SYMBOL (a matter of
taste).

Signed-off-by: Eli Billauer <eli.billauer@gmail.com>
Link: https://lore.kernel.org/r/20210526100311.56327-2-eli.billauer@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Eli Billauer and committed by
Greg Kroah-Hartman
8cb5d216 83aacfbc

+324 -169
+6 -2
drivers/char/xillybus/Kconfig
··· 3 3 # Xillybus devices 4 4 # 5 5 6 + config XILLYBUS_CLASS 7 + tristate 8 + 6 9 config XILLYBUS 7 10 tristate "Xillybus generic FPGA interface" 8 11 depends on PCI || OF 9 12 select CRC32 13 + select XILLYBUS_CLASS 10 14 help 11 15 Xillybus is a generic interface for peripherals designed on 12 16 programmable logic (FPGA). The driver probes the hardware for ··· 25 21 depends on PCI_MSI 26 22 help 27 23 Set to M if you want Xillybus to use PCI Express for communicating 28 - with the FPGA. 24 + with the FPGA. The module will be called xillybus_pcie. 29 25 30 26 config XILLYBUS_OF 31 27 tristate "Xillybus over Device Tree" ··· 33 29 help 34 30 Set to M if you want Xillybus to find its resources from the 35 31 Open Firmware Flattened Device Tree. If the target is an embedded 36 - system, say M. 32 + system, say M. The module will be called xillybus_of. 37 33 38 34 endif # if XILLYBUS
+1
drivers/char/xillybus/Makefile
··· 3 3 # Makefile for Xillybus driver 4 4 # 5 5 6 + obj-$(CONFIG_XILLYBUS_CLASS) += xillybus_class.o 6 7 obj-$(CONFIG_XILLYBUS) += xillybus_core.o 7 8 obj-$(CONFIG_XILLYBUS_PCIE) += xillybus_pcie.o 8 9 obj-$(CONFIG_XILLYBUS_OF) += xillybus_of.o
+2 -8
drivers/char/xillybus/xillybus.h
··· 30 30 31 31 struct xilly_idt_handle { 32 32 unsigned char *chandesc; 33 - unsigned char *idt; 33 + unsigned char *names; 34 + int names_len; 34 35 int entries; 35 36 }; 36 37 ··· 95 94 struct device *dev; 96 95 struct xilly_endpoint_hardware *ephw; 97 96 98 - struct list_head ep_list; 99 97 int dma_using_dac; /* =1 if 64-bit DMA is used, =0 otherwise. */ 100 98 __iomem void *registers; 101 99 int fatal_error; 102 100 103 101 struct mutex register_mutex; 104 102 wait_queue_head_t ep_wait; 105 - 106 - /* Channels and message handling */ 107 - struct cdev cdev; 108 - 109 - int major; 110 - int lowest_minor; /* Highest minor = lowest_minor + num_channels - 1 */ 111 103 112 104 int num_channels; /* EXCLUDING message buffer */ 113 105 struct xilly_channel **channels;
+263
drivers/char/xillybus/xillybus_class.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright 2021 Xillybus Ltd, http://xillybus.com 4 + * 5 + * Driver for the Xillybus class 6 + */ 7 + 8 + #include <linux/types.h> 9 + #include <linux/module.h> 10 + #include <linux/device.h> 11 + #include <linux/fs.h> 12 + #include <linux/cdev.h> 13 + #include <linux/slab.h> 14 + #include <linux/list.h> 15 + #include <linux/mutex.h> 16 + 17 + #include "xillybus_class.h" 18 + 19 + MODULE_DESCRIPTION("Driver for Xillybus class"); 20 + MODULE_AUTHOR("Eli Billauer, Xillybus Ltd."); 21 + MODULE_VERSION("1.0"); 22 + MODULE_ALIAS("xillybus_class"); 23 + MODULE_LICENSE("GPL v2"); 24 + 25 + static DEFINE_MUTEX(unit_mutex); 26 + static LIST_HEAD(unit_list); 27 + static struct class *xillybus_class; 28 + 29 + #define UNITNAMELEN 16 30 + 31 + struct xilly_unit { 32 + struct list_head list_entry; 33 + void *private_data; 34 + 35 + struct cdev *cdev; 36 + char name[UNITNAMELEN]; 37 + int major; 38 + int lowest_minor; 39 + int num_nodes; 40 + }; 41 + 42 + int xillybus_init_chrdev(struct device *dev, 43 + const struct file_operations *fops, 44 + struct module *owner, 45 + void *private_data, 46 + unsigned char *idt, unsigned int len, 47 + int num_nodes, 48 + const char *prefix, bool enumerate) 49 + { 50 + int rc; 51 + dev_t mdev; 52 + int i; 53 + char devname[48]; 54 + 55 + struct device *device; 56 + size_t namelen; 57 + struct xilly_unit *unit, *u; 58 + 59 + unit = kzalloc(sizeof(*unit), GFP_KERNEL); 60 + 61 + if (!unit) 62 + return -ENOMEM; 63 + 64 + mutex_lock(&unit_mutex); 65 + 66 + if (!enumerate) 67 + snprintf(unit->name, UNITNAMELEN, "%s", prefix); 68 + 69 + for (i = 0; enumerate; i++) { 70 + snprintf(unit->name, UNITNAMELEN, "%s_%02d", 71 + prefix, i); 72 + 73 + enumerate = false; 74 + list_for_each_entry(u, &unit_list, list_entry) 75 + if (!strcmp(unit->name, u->name)) { 76 + enumerate = true; 77 + break; 78 + } 79 + } 80 + 81 + rc = alloc_chrdev_region(&mdev, 0, num_nodes, unit->name); 82 + 83 + if (rc) { 84 + dev_warn(dev, "Failed to obtain major/minors"); 85 + goto fail_obtain; 86 + } 87 + 88 + unit->major = MAJOR(mdev); 89 + unit->lowest_minor = MINOR(mdev); 90 + unit->num_nodes = num_nodes; 91 + unit->private_data = private_data; 92 + 93 + unit->cdev = cdev_alloc(); 94 + if (!unit->cdev) { 95 + rc = -ENOMEM; 96 + goto unregister_chrdev; 97 + } 98 + unit->cdev->ops = fops; 99 + unit->cdev->owner = owner; 100 + 101 + rc = cdev_add(unit->cdev, MKDEV(unit->major, unit->lowest_minor), 102 + unit->num_nodes); 103 + if (rc) { 104 + dev_err(dev, "Failed to add cdev.\n"); 105 + /* kobject_put() is normally done by cdev_del() */ 106 + kobject_put(&unit->cdev->kobj); 107 + goto unregister_chrdev; 108 + } 109 + 110 + for (i = 0; i < num_nodes; i++) { 111 + namelen = strnlen(idt, len); 112 + 113 + if (namelen == len) { 114 + dev_err(dev, "IDT's list of names is too short. This is exceptionally weird, because its CRC is OK\n"); 115 + rc = -ENODEV; 116 + goto unroll_device_create; 117 + } 118 + 119 + snprintf(devname, sizeof(devname), "%s_%s", 120 + unit->name, idt); 121 + 122 + len -= namelen + 1; 123 + idt += namelen + 1; 124 + 125 + device = device_create(xillybus_class, 126 + NULL, 127 + MKDEV(unit->major, 128 + i + unit->lowest_minor), 129 + NULL, 130 + "%s", devname); 131 + 132 + if (IS_ERR(device)) { 133 + dev_err(dev, "Failed to create %s device. Aborting.\n", 134 + devname); 135 + rc = -ENODEV; 136 + goto unroll_device_create; 137 + } 138 + } 139 + 140 + if (len) { 141 + dev_err(dev, "IDT's list of names is too long. This is exceptionally weird, because its CRC is OK\n"); 142 + rc = -ENODEV; 143 + goto unroll_device_create; 144 + } 145 + 146 + list_add_tail(&unit->list_entry, &unit_list); 147 + 148 + dev_info(dev, "Created %d device files.\n", num_nodes); 149 + 150 + mutex_unlock(&unit_mutex); 151 + 152 + return 0; 153 + 154 + unroll_device_create: 155 + for (i--; i >= 0; i--) 156 + device_destroy(xillybus_class, MKDEV(unit->major, 157 + i + unit->lowest_minor)); 158 + 159 + cdev_del(unit->cdev); 160 + 161 + unregister_chrdev: 162 + unregister_chrdev_region(MKDEV(unit->major, unit->lowest_minor), 163 + unit->num_nodes); 164 + 165 + fail_obtain: 166 + mutex_unlock(&unit_mutex); 167 + 168 + kfree(unit); 169 + 170 + return rc; 171 + } 172 + EXPORT_SYMBOL(xillybus_init_chrdev); 173 + 174 + void xillybus_cleanup_chrdev(void *private_data, 175 + struct device *dev) 176 + { 177 + int minor; 178 + struct xilly_unit *unit; 179 + bool found = false; 180 + 181 + mutex_lock(&unit_mutex); 182 + 183 + list_for_each_entry(unit, &unit_list, list_entry) 184 + if (unit->private_data == private_data) { 185 + found = true; 186 + break; 187 + } 188 + 189 + if (!found) { 190 + dev_err(dev, "Weird bug: Failed to find unit\n"); 191 + mutex_unlock(&unit_mutex); 192 + return; 193 + } 194 + 195 + for (minor = unit->lowest_minor; 196 + minor < (unit->lowest_minor + unit->num_nodes); 197 + minor++) 198 + device_destroy(xillybus_class, MKDEV(unit->major, minor)); 199 + 200 + cdev_del(unit->cdev); 201 + 202 + unregister_chrdev_region(MKDEV(unit->major, unit->lowest_minor), 203 + unit->num_nodes); 204 + 205 + dev_info(dev, "Removed %d device files.\n", 206 + unit->num_nodes); 207 + 208 + list_del(&unit->list_entry); 209 + kfree(unit); 210 + 211 + mutex_unlock(&unit_mutex); 212 + } 213 + EXPORT_SYMBOL(xillybus_cleanup_chrdev); 214 + 215 + int xillybus_find_inode(struct inode *inode, 216 + void **private_data, int *index) 217 + { 218 + int minor = iminor(inode); 219 + int major = imajor(inode); 220 + struct xilly_unit *unit; 221 + bool found = false; 222 + 223 + mutex_lock(&unit_mutex); 224 + 225 + list_for_each_entry(unit, &unit_list, list_entry) 226 + if (unit->major == major && 227 + minor >= unit->lowest_minor && 228 + minor < (unit->lowest_minor + unit->num_nodes)) { 229 + found = true; 230 + break; 231 + } 232 + 233 + mutex_unlock(&unit_mutex); 234 + 235 + if (!found) 236 + return -ENODEV; 237 + 238 + *private_data = unit->private_data; 239 + *index = minor - unit->lowest_minor; 240 + 241 + return 0; 242 + } 243 + EXPORT_SYMBOL(xillybus_find_inode); 244 + 245 + static int __init xillybus_class_init(void) 246 + { 247 + xillybus_class = class_create(THIS_MODULE, "xillybus"); 248 + 249 + if (IS_ERR(xillybus_class)) { 250 + pr_warn("Failed to register xillybus class\n"); 251 + 252 + return PTR_ERR(xillybus_class); 253 + } 254 + return 0; 255 + } 256 + 257 + static void __exit xillybus_class_exit(void) 258 + { 259 + class_destroy(xillybus_class); 260 + } 261 + 262 + module_init(xillybus_class_init); 263 + module_exit(xillybus_class_exit);
+30
drivers/char/xillybus/xillybus_class.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * Copyright 2021 Xillybus Ltd, http://www.xillybus.com 4 + * 5 + * Header file for the Xillybus class 6 + */ 7 + 8 + #ifndef __XILLYBUS_CLASS_H 9 + #define __XILLYBUS_CLASS_H 10 + 11 + #include <linux/types.h> 12 + #include <linux/device.h> 13 + #include <linux/fs.h> 14 + #include <linux/module.h> 15 + 16 + int xillybus_init_chrdev(struct device *dev, 17 + const struct file_operations *fops, 18 + struct module *owner, 19 + void *private_data, 20 + unsigned char *idt, unsigned int len, 21 + int num_nodes, 22 + const char *prefix, bool enumerate); 23 + 24 + void xillybus_cleanup_chrdev(void *private_data, 25 + struct device *dev); 26 + 27 + int xillybus_find_inode(struct inode *inode, 28 + void **private_data, int *index); 29 + 30 + #endif /* __XILLYBUS_CLASS_H */
+22 -159
drivers/char/xillybus/xillybus_core.c
··· 21 21 #include <linux/interrupt.h> 22 22 #include <linux/sched.h> 23 23 #include <linux/fs.h> 24 - #include <linux/cdev.h> 25 24 #include <linux/spinlock.h> 26 25 #include <linux/mutex.h> 27 26 #include <linux/crc32.h> ··· 29 30 #include <linux/slab.h> 30 31 #include <linux/workqueue.h> 31 32 #include "xillybus.h" 33 + #include "xillybus_class.h" 32 34 33 35 MODULE_DESCRIPTION("Xillybus core functions"); 34 36 MODULE_AUTHOR("Eli Billauer, Xillybus Ltd."); 35 - MODULE_VERSION("1.07"); 37 + MODULE_VERSION("1.10"); 36 38 MODULE_ALIAS("xillybus_core"); 37 39 MODULE_LICENSE("GPL v2"); 38 40 ··· 58 58 59 59 static const char xillyname[] = "xillybus"; 60 60 61 - static struct class *xillybus_class; 62 - 63 - /* 64 - * ep_list_lock is the last lock to be taken; No other lock requests are 65 - * allowed while holding it. It merely protects list_of_endpoints, and not 66 - * the endpoints listed in it. 67 - */ 68 - 69 - static LIST_HEAD(list_of_endpoints); 70 - static struct mutex ep_list_lock; 71 61 static struct workqueue_struct *xillybus_wq; 72 62 73 63 /* ··· 560 570 unsigned char *scan; 561 571 int len; 562 572 563 - scan = idt; 564 - idt_handle->idt = idt; 565 - 566 - scan++; /* Skip version number */ 573 + scan = idt + 1; 574 + idt_handle->names = scan; 567 575 568 576 while ((scan <= end_of_idt) && *scan) { 569 577 while ((scan <= end_of_idt) && *scan++) 570 578 /* Do nothing, just scan thru string */; 571 579 count++; 572 580 } 581 + 582 + idt_handle->names_len = scan - idt_handle->names; 573 583 574 584 scan++; 575 585 ··· 1397 1407 1398 1408 static int xillybus_open(struct inode *inode, struct file *filp) 1399 1409 { 1400 - int rc = 0; 1410 + int rc; 1401 1411 unsigned long flags; 1402 - int minor = iminor(inode); 1403 - int major = imajor(inode); 1404 - struct xilly_endpoint *ep_iter, *endpoint = NULL; 1412 + struct xilly_endpoint *endpoint; 1405 1413 struct xilly_channel *channel; 1414 + int index; 1406 1415 1407 - mutex_lock(&ep_list_lock); 1408 - 1409 - list_for_each_entry(ep_iter, &list_of_endpoints, ep_list) { 1410 - if ((ep_iter->major == major) && 1411 - (minor >= ep_iter->lowest_minor) && 1412 - (minor < (ep_iter->lowest_minor + 1413 - ep_iter->num_channels))) { 1414 - endpoint = ep_iter; 1415 - break; 1416 - } 1417 - } 1418 - mutex_unlock(&ep_list_lock); 1419 - 1420 - if (!endpoint) { 1421 - pr_err("xillybus: open() failed to find a device for major=%d and minor=%d\n", 1422 - major, minor); 1423 - return -ENODEV; 1424 - } 1416 + rc = xillybus_find_inode(inode, (void **)&endpoint, &index); 1417 + if (rc) 1418 + return rc; 1425 1419 1426 1420 if (endpoint->fatal_error) 1427 1421 return -EIO; 1428 1422 1429 - channel = endpoint->channels[1 + minor - endpoint->lowest_minor]; 1423 + channel = endpoint->channels[1 + index]; 1430 1424 filp->private_data = channel; 1431 1425 1432 1426 /* ··· 1773 1799 .poll = xillybus_poll, 1774 1800 }; 1775 1801 1776 - static int xillybus_init_chrdev(struct xilly_endpoint *endpoint, 1777 - const unsigned char *idt) 1778 - { 1779 - int rc; 1780 - dev_t dev; 1781 - int devnum, i, minor, major; 1782 - char devname[48]; 1783 - struct device *device; 1784 - 1785 - rc = alloc_chrdev_region(&dev, 0, /* minor start */ 1786 - endpoint->num_channels, 1787 - xillyname); 1788 - if (rc) { 1789 - dev_warn(endpoint->dev, "Failed to obtain major/minors"); 1790 - return rc; 1791 - } 1792 - 1793 - endpoint->major = major = MAJOR(dev); 1794 - endpoint->lowest_minor = minor = MINOR(dev); 1795 - 1796 - cdev_init(&endpoint->cdev, &xillybus_fops); 1797 - endpoint->cdev.owner = endpoint->ephw->owner; 1798 - rc = cdev_add(&endpoint->cdev, MKDEV(major, minor), 1799 - endpoint->num_channels); 1800 - if (rc) { 1801 - dev_warn(endpoint->dev, "Failed to add cdev. Aborting.\n"); 1802 - goto unregister_chrdev; 1803 - } 1804 - 1805 - idt++; 1806 - 1807 - for (i = minor, devnum = 0; 1808 - devnum < endpoint->num_channels; 1809 - devnum++, i++) { 1810 - snprintf(devname, sizeof(devname)-1, "xillybus_%s", idt); 1811 - 1812 - devname[sizeof(devname)-1] = 0; /* Should never matter */ 1813 - 1814 - while (*idt++) 1815 - /* Skip to next */; 1816 - 1817 - device = device_create(xillybus_class, 1818 - NULL, 1819 - MKDEV(major, i), 1820 - NULL, 1821 - "%s", devname); 1822 - 1823 - if (IS_ERR(device)) { 1824 - dev_warn(endpoint->dev, 1825 - "Failed to create %s device. Aborting.\n", 1826 - devname); 1827 - rc = -ENODEV; 1828 - goto unroll_device_create; 1829 - } 1830 - } 1831 - 1832 - dev_info(endpoint->dev, "Created %d device files.\n", 1833 - endpoint->num_channels); 1834 - return 0; /* succeed */ 1835 - 1836 - unroll_device_create: 1837 - devnum--; i--; 1838 - for (; devnum >= 0; devnum--, i--) 1839 - device_destroy(xillybus_class, MKDEV(major, i)); 1840 - 1841 - cdev_del(&endpoint->cdev); 1842 - unregister_chrdev: 1843 - unregister_chrdev_region(MKDEV(major, minor), endpoint->num_channels); 1844 - 1845 - return rc; 1846 - } 1847 - 1848 - static void xillybus_cleanup_chrdev(struct xilly_endpoint *endpoint) 1849 - { 1850 - int minor; 1851 - 1852 - for (minor = endpoint->lowest_minor; 1853 - minor < (endpoint->lowest_minor + endpoint->num_channels); 1854 - minor++) 1855 - device_destroy(xillybus_class, MKDEV(endpoint->major, minor)); 1856 - cdev_del(&endpoint->cdev); 1857 - unregister_chrdev_region(MKDEV(endpoint->major, 1858 - endpoint->lowest_minor), 1859 - endpoint->num_channels); 1860 - 1861 - dev_info(endpoint->dev, "Removed %d device files.\n", 1862 - endpoint->num_channels); 1863 - } 1864 - 1865 1802 struct xilly_endpoint *xillybus_init_endpoint(struct pci_dev *pdev, 1866 1803 struct device *dev, 1867 1804 struct xilly_endpoint_hardware ··· 1912 2027 if (rc) 1913 2028 goto failed_idt; 1914 2029 1915 - /* 1916 - * endpoint is now completely configured. We put it on the list 1917 - * available to open() before registering the char device(s) 1918 - */ 2030 + rc = xillybus_init_chrdev(dev, &xillybus_fops, 2031 + endpoint->ephw->owner, endpoint, 2032 + idt_handle.names, 2033 + idt_handle.names_len, 2034 + endpoint->num_channels, 2035 + xillyname, false); 1919 2036 1920 - mutex_lock(&ep_list_lock); 1921 - list_add_tail(&endpoint->ep_list, &list_of_endpoints); 1922 - mutex_unlock(&ep_list_lock); 1923 - 1924 - rc = xillybus_init_chrdev(endpoint, idt_handle.idt); 1925 2037 if (rc) 1926 - goto failed_chrdevs; 2038 + goto failed_idt; 1927 2039 1928 2040 devres_release_group(dev, bootstrap_resources); 1929 2041 1930 2042 return 0; 1931 - 1932 - failed_chrdevs: 1933 - mutex_lock(&ep_list_lock); 1934 - list_del(&endpoint->ep_list); 1935 - mutex_unlock(&ep_list_lock); 1936 2043 1937 2044 failed_idt: 1938 2045 xilly_quiesce(endpoint); ··· 1936 2059 1937 2060 void xillybus_endpoint_remove(struct xilly_endpoint *endpoint) 1938 2061 { 1939 - xillybus_cleanup_chrdev(endpoint); 1940 - 1941 - mutex_lock(&ep_list_lock); 1942 - list_del(&endpoint->ep_list); 1943 - mutex_unlock(&ep_list_lock); 2062 + xillybus_cleanup_chrdev(endpoint, endpoint->dev); 1944 2063 1945 2064 xilly_quiesce(endpoint); 1946 2065 ··· 1950 2077 1951 2078 static int __init xillybus_init(void) 1952 2079 { 1953 - mutex_init(&ep_list_lock); 1954 - 1955 - xillybus_class = class_create(THIS_MODULE, xillyname); 1956 - if (IS_ERR(xillybus_class)) 1957 - return PTR_ERR(xillybus_class); 1958 - 1959 2080 xillybus_wq = alloc_workqueue(xillyname, 0, 0); 1960 - if (!xillybus_wq) { 1961 - class_destroy(xillybus_class); 2081 + if (!xillybus_wq) 1962 2082 return -ENOMEM; 1963 - } 1964 2083 1965 2084 return 0; 1966 2085 } ··· 1961 2096 { 1962 2097 /* flush_workqueue() was called for each endpoint released */ 1963 2098 destroy_workqueue(xillybus_wq); 1964 - 1965 - class_destroy(xillybus_class); 1966 2099 } 1967 2100 1968 2101 module_init(xillybus_init);