diff options
author | Todd Poynor <toddpoynor@google.com> | 2018-07-31 13:24:34 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2018-08-01 20:07:02 +0200 |
commit | 80666096eb78f0eb54abb1991c23488a276fa1c6 (patch) | |
tree | 6be67d39618528a567badb99611f9a0fb033c8c5 /drivers/staging/gasket/gasket_core.c | |
parent | 5298ff58c93e0d7b7d67b8525e7c18a9478cbd8d (diff) |
staging: gasket: core: remove static function forward declarations
Remove forward declarations of static functions, move code to avoid
forward references, for kernel style.
Signed-off-by: Todd Poynor <toddpoynor@google.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/staging/gasket/gasket_core.c')
-rw-r--r-- | drivers/staging/gasket/gasket_core.c | 1802 |
1 files changed, 873 insertions, 929 deletions
diff --git a/drivers/staging/gasket/gasket_core.c b/drivers/staging/gasket/gasket_core.c index c00774059f9e..b5a7254fbfb3 100644 --- a/drivers/staging/gasket/gasket_core.c +++ b/drivers/staging/gasket/gasket_core.c @@ -67,61 +67,6 @@ enum do_map_region_status { DO_MAP_REGION_INVALID, }; -/* Function declarations; comments are with definitions. */ -static int __init gasket_init(void); -static void __exit gasket_exit(void); - -static int gasket_pci_probe( - struct pci_dev *pci_dev, const struct pci_device_id *id); -static void gasket_pci_remove(struct pci_dev *pci_dev); - -static int gasket_setup_pci(struct pci_dev *pci_dev, struct gasket_dev *dev); -static void gasket_cleanup_pci(struct gasket_dev *dev); - -static int gasket_map_pci_bar(struct gasket_dev *dev, int bar_num); -static void gasket_unmap_pci_bar(struct gasket_dev *dev, int bar_num); - -static int gasket_alloc_dev( - struct gasket_internal_desc *internal_desc, struct device *dev, - struct gasket_dev **pdev, const char *kobj_name); -static void gasket_free_dev(struct gasket_dev *dev); - -static int gasket_find_dev_slot( - struct gasket_internal_desc *internal_desc, const char *kobj_name); - -static int gasket_add_cdev( - struct gasket_cdev_info *dev_info, - const struct file_operations *file_ops, struct module *owner); - -static int gasket_enable_dev( - struct gasket_internal_desc *internal_desc, - struct gasket_dev *gasket_dev); -static void gasket_disable_dev(struct gasket_dev *gasket_dev); - -static struct gasket_internal_desc *lookup_internal_desc( - struct pci_dev *pci_dev); - -static ssize_t gasket_sysfs_data_show( - struct device *device, struct device_attribute *attr, char *buf); - -static int gasket_mmap(struct file *filp, struct vm_area_struct *vma); -static int gasket_open(struct inode *inode, struct file *file); -static int gasket_release(struct inode *inode, struct file *file); -static long gasket_ioctl(struct file *filp, uint cmd, ulong arg); - -static int gasket_mm_vma_bar_offset( - const struct gasket_dev *gasket_dev, const struct vm_area_struct *vma, - ulong *bar_offset); -static bool gasket_mm_get_mapping_addrs( - const struct gasket_mappable_region *region, ulong bar_offset, - ulong requested_length, struct gasket_mappable_region *mappable_region, - ulong *virt_offset); -static enum do_map_region_status do_map_region( - const struct gasket_dev *gasket_dev, struct vm_area_struct *vma, - struct gasket_mappable_region *map_region); - -static int gasket_get_hw_status(struct gasket_dev *gasket_dev); - /* Global data definitions. */ /* Mutex - only for framework-wide data. Other data should be protected by * finer-grained locks. @@ -157,48 +102,6 @@ enum gasket_sysfs_attribute_type { ATTR_USER_MEM_RANGES }; -/* File operations for all Gasket devices. */ -static const struct file_operations gasket_file_ops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .mmap = gasket_mmap, - .open = gasket_open, - .release = gasket_release, - .unlocked_ioctl = gasket_ioctl, -}; - -/* These attributes apply to all Gasket driver instances. */ -static const struct gasket_sysfs_attribute gasket_sysfs_generic_attrs[] = { - GASKET_SYSFS_RO(bar_offsets, gasket_sysfs_data_show, ATTR_BAR_OFFSETS), - GASKET_SYSFS_RO(bar_sizes, gasket_sysfs_data_show, ATTR_BAR_SIZES), - GASKET_SYSFS_RO(driver_version, gasket_sysfs_data_show, - ATTR_DRIVER_VERSION), - GASKET_SYSFS_RO(framework_version, gasket_sysfs_data_show, - ATTR_FRAMEWORK_VERSION), - GASKET_SYSFS_RO(device_type, gasket_sysfs_data_show, ATTR_DEVICE_TYPE), - GASKET_SYSFS_RO(revision, gasket_sysfs_data_show, - ATTR_HARDWARE_REVISION), - GASKET_SYSFS_RO(pci_address, gasket_sysfs_data_show, ATTR_PCI_ADDRESS), - GASKET_SYSFS_RO(status, gasket_sysfs_data_show, ATTR_STATUS), - GASKET_SYSFS_RO(is_device_owned, gasket_sysfs_data_show, - ATTR_IS_DEVICE_OWNED), - GASKET_SYSFS_RO(device_owner, gasket_sysfs_data_show, - ATTR_DEVICE_OWNER), - GASKET_SYSFS_RO(write_open_count, gasket_sysfs_data_show, - ATTR_WRITE_OPEN_COUNT), - GASKET_SYSFS_RO(reset_count, gasket_sysfs_data_show, ATTR_RESET_COUNT), - GASKET_SYSFS_RO(user_mem_ranges, gasket_sysfs_data_show, - ATTR_USER_MEM_RANGES), - GASKET_END_OF_ATTR_ARRAY -}; - -MODULE_DESCRIPTION("Google Gasket driver framework"); -MODULE_VERSION(GASKET_FRAMEWORK_VERSION); -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Rob Springer <rspringer@google.com>"); -module_init(gasket_init); -module_exit(gasket_exit); - /* Perform a standard Gasket callback. */ static inline int check_and_invoke_callback( struct gasket_dev *gasket_dev, int (*cb_function)(struct gasket_dev *)) @@ -239,165 +142,43 @@ static int gasket_owned_by_current_tgid(struct gasket_cdev_info *info) (info->ownership.owner == current->tgid)); } -static int __init gasket_init(void) +/* + * Find the next free gasket_internal_dev slot. + * + * Returns the located slot number on success or a negative number on failure. + */ +static int gasket_find_dev_slot( + struct gasket_internal_desc *internal_desc, const char *kobj_name) { int i; - pr_info("Performing one-time init of the Gasket framework.\n"); - /* Check for duplicates and find a free slot. */ - mutex_lock(&g_mutex); - for (i = 0; i < GASKET_FRAMEWORK_DESC_MAX; i++) { - g_descs[i].driver_desc = NULL; - mutex_init(&g_descs[i].mutex); - } - - gasket_sysfs_init(); - - mutex_unlock(&g_mutex); - return 0; -} - -static void __exit gasket_exit(void) -{ - /* No deinit/dealloc needed at present. */ - pr_info("Removing Gasket framework module.\n"); -} - -/* See gasket_core.h for description. */ -int gasket_register_device(const struct gasket_driver_desc *driver_desc) -{ - int i, ret; - int desc_idx = -1; - struct gasket_internal_desc *internal; - - pr_info("Initializing Gasket framework device\n"); - /* Check for duplicates and find a free slot. */ - mutex_lock(&g_mutex); + mutex_lock(&internal_desc->mutex); - for (i = 0; i < GASKET_FRAMEWORK_DESC_MAX; i++) { - if (g_descs[i].driver_desc == driver_desc) { - pr_err("%s driver already loaded/registered\n", - driver_desc->name); - mutex_unlock(&g_mutex); + /* Search for a previous instance of this device. */ + for (i = 0; i < GASKET_DEV_MAX; i++) { + if (internal_desc->devs[i] && + strcmp(internal_desc->devs[i]->kobj_name, kobj_name) == 0) { + pr_err("Duplicate device %s\n", kobj_name); + mutex_unlock(&internal_desc->mutex); return -EBUSY; } } - /* This and the above loop could be combined, but this reads easier. */ - for (i = 0; i < GASKET_FRAMEWORK_DESC_MAX; i++) { - if (!g_descs[i].driver_desc) { - g_descs[i].driver_desc = driver_desc; - desc_idx = i; + /* Find a free device slot. */ + for (i = 0; i < GASKET_DEV_MAX; i++) { + if (!internal_desc->devs[i]) break; - } } - mutex_unlock(&g_mutex); - - pr_info("Loaded %s driver, framework version %s\n", - driver_desc->name, GASKET_FRAMEWORK_VERSION); - if (desc_idx == -1) { - pr_err("Too many Gasket drivers loaded: %d\n", - GASKET_FRAMEWORK_DESC_MAX); + if (i == GASKET_DEV_MAX) { + pr_err("Too many registered devices; max %d\n", GASKET_DEV_MAX); + mutex_unlock(&internal_desc->mutex); return -EBUSY; } - /* Internal structure setup. */ - pr_debug("Performing initial internal structure setup.\n"); - internal = &g_descs[desc_idx]; - mutex_init(&internal->mutex); - memset(internal->devs, 0, sizeof(struct gasket_dev *) * GASKET_DEV_MAX); - memset(&internal->pci, 0, sizeof(internal->pci)); - internal->pci.name = driver_desc->name; - internal->pci.id_table = driver_desc->pci_id_table; - internal->pci.probe = gasket_pci_probe; - internal->pci.remove = gasket_pci_remove; - internal->class = - class_create(driver_desc->module, driver_desc->name); - - if (IS_ERR(internal->class)) { - pr_err("Cannot register %s class [ret=%ld]\n", - driver_desc->name, PTR_ERR(internal->class)); - ret = PTR_ERR(internal->class); - goto unregister_gasket_driver; - } - - /* - * Not using pci_register_driver() (without underscores), as it - * depends on KBUILD_MODNAME, and this is a shared file. - */ - pr_debug("Registering PCI driver.\n"); - ret = __pci_register_driver( - &internal->pci, driver_desc->module, driver_desc->name); - if (ret) { - pr_err("cannot register pci driver [ret=%d]\n", ret); - goto fail1; - } - - pr_debug("Registering char driver.\n"); - ret = register_chrdev_region( - MKDEV(driver_desc->major, driver_desc->minor), GASKET_DEV_MAX, - driver_desc->name); - if (ret) { - pr_err("cannot register char driver [ret=%d]\n", ret); - goto fail2; - } - - pr_info("Driver registered successfully.\n"); - return 0; - -fail2: - pci_unregister_driver(&internal->pci); - -fail1: - class_destroy(internal->class); - -unregister_gasket_driver: - mutex_lock(&g_mutex); - g_descs[desc_idx].driver_desc = NULL; - mutex_unlock(&g_mutex); - return ret; -} -EXPORT_SYMBOL(gasket_register_device); - -/* See gasket_core.h for description. */ -void gasket_unregister_device(const struct gasket_driver_desc *driver_desc) -{ - int i, desc_idx; - struct gasket_internal_desc *internal_desc = NULL; - - mutex_lock(&g_mutex); - for (i = 0; i < GASKET_FRAMEWORK_DESC_MAX; i++) { - if (g_descs[i].driver_desc == driver_desc) { - internal_desc = &g_descs[i]; - desc_idx = i; - break; - } - } - mutex_unlock(&g_mutex); - - if (!internal_desc) { - pr_err("request to unregister unknown desc: %s, %d:%d\n", - driver_desc->name, driver_desc->major, - driver_desc->minor); - return; - } - - unregister_chrdev_region( - MKDEV(driver_desc->major, driver_desc->minor), GASKET_DEV_MAX); - - pci_unregister_driver(&internal_desc->pci); - - class_destroy(internal_desc->class); - - /* Finally, effectively "remove" the driver. */ - mutex_lock(&g_mutex); - g_descs[desc_idx].driver_desc = NULL; - mutex_unlock(&g_mutex); - - pr_info("removed %s driver\n", driver_desc->name); + mutex_unlock(&internal_desc->mutex); + return i; } -EXPORT_SYMBOL(gasket_unregister_device); /* * Allocate and initialize a Gasket device structure, add the device to the @@ -474,250 +255,6 @@ static void gasket_free_dev(struct gasket_dev *gasket_dev) } /* - * Find the next free gasket_internal_dev slot. - * - * Returns the located slot number on success or a negative number on failure. - */ -static int gasket_find_dev_slot( - struct gasket_internal_desc *internal_desc, const char *kobj_name) -{ - int i; - - mutex_lock(&internal_desc->mutex); - - /* Search for a previous instance of this device. */ - for (i = 0; i < GASKET_DEV_MAX; i++) { - if (internal_desc->devs[i] && - strcmp(internal_desc->devs[i]->kobj_name, kobj_name) == 0) { - pr_err("Duplicate device %s\n", kobj_name); - mutex_unlock(&internal_desc->mutex); - return -EBUSY; - } - } - - /* Find a free device slot. */ - for (i = 0; i < GASKET_DEV_MAX; i++) { - if (!internal_desc->devs[i]) - break; - } - - if (i == GASKET_DEV_MAX) { - pr_err("Too many registered devices; max %d\n", GASKET_DEV_MAX); - mutex_unlock(&internal_desc->mutex); - return -EBUSY; - } - - mutex_unlock(&internal_desc->mutex); - return i; -} - -/* - * PCI subsystem probe function. - * - * Called when a Gasket device is found. Allocates device metadata, maps device - * memory, and calls gasket_enable_dev to prepare the device for active use. - * - * Returns 0 if successful and a negative value otherwise. - */ -static int gasket_pci_probe( - struct pci_dev *pci_dev, const struct pci_device_id *id) -{ - int ret; - const char *kobj_name = dev_name(&pci_dev->dev); - struct gasket_internal_desc *internal_desc; - struct gasket_dev *gasket_dev; - const struct gasket_driver_desc *driver_desc; - struct device *parent; - - pr_info("Add Gasket device %s\n", kobj_name); - - mutex_lock(&g_mutex); - internal_desc = lookup_internal_desc(pci_dev); - mutex_unlock(&g_mutex); - if (!internal_desc) { - pr_err("PCI probe called for unknown driver type\n"); - return -ENODEV; - } - - driver_desc = internal_desc->driver_desc; - - parent = &pci_dev->dev; - ret = gasket_alloc_dev(internal_desc, parent, &gasket_dev, kobj_name); - if (ret) - return ret; - gasket_dev->pci_dev = pci_dev_get(pci_dev); - if (IS_ERR_OR_NULL(gasket_dev->dev_info.device)) { - pr_err("Cannot create %s device %s [ret = %ld]\n", - driver_desc->name, gasket_dev->dev_info.name, - PTR_ERR(gasket_dev->dev_info.device)); - ret = -ENODEV; - goto fail1; - } - - ret = gasket_setup_pci(pci_dev, gasket_dev); - if (ret) - goto fail2; - - ret = check_and_invoke_callback(gasket_dev, driver_desc->add_dev_cb); - if (ret) { - dev_err(gasket_dev->dev, "Error in add device cb: %d\n", ret); - goto fail2; - } - - ret = gasket_sysfs_create_mapping( - gasket_dev->dev_info.device, gasket_dev); - if (ret) - goto fail3; - - /* - * Once we've created the mapping structures successfully, attempt to - * create a symlink to the pci directory of this object. - */ - ret = sysfs_create_link(&gasket_dev->dev_info.device->kobj, - &pci_dev->dev.kobj, dev_name(&pci_dev->dev)); - if (ret) { - dev_err(gasket_dev->dev, - "Cannot create sysfs pci link: %d\n", ret); - goto fail3; - } - ret = gasket_sysfs_create_entries( - gasket_dev->dev_info.device, gasket_sysfs_generic_attrs); - if (ret) - goto fail4; - - ret = check_and_invoke_callback( - gasket_dev, driver_desc->sysfs_setup_cb); - if (ret) { - dev_err(gasket_dev->dev, "Error in sysfs setup cb: %d\n", ret); - goto fail5; - } - - ret = gasket_enable_dev(internal_desc, gasket_dev); - if (ret) { - pr_err("cannot setup %s device\n", driver_desc->name); - gasket_disable_dev(gasket_dev); - goto fail5; - } - - return 0; - -fail5: - check_and_invoke_callback(gasket_dev, driver_desc->sysfs_cleanup_cb); -fail4: -fail3: - gasket_sysfs_remove_mapping(gasket_dev->dev_info.device); -fail2: - gasket_cleanup_pci(gasket_dev); - check_and_invoke_callback(gasket_dev, driver_desc->remove_dev_cb); - device_destroy(internal_desc->class, gasket_dev->dev_info.devt); -fail1: - gasket_free_dev(gasket_dev); - return ret; -} - -/* - * PCI subsystem remove function. - * - * Called to remove a Gasket device. Finds the device in the device list and - * cleans up metadata. - */ -static void gasket_pci_remove(struct pci_dev *pci_dev) -{ - int i; - struct gasket_internal_desc *internal_desc; - struct gasket_dev *gasket_dev = NULL; - const struct gasket_driver_desc *driver_desc; - /* Find the device desc. */ - mutex_lock(&g_mutex); - internal_desc = lookup_internal_desc(pci_dev); - if (!internal_desc) { - mutex_unlock(&g_mutex); - return; - } - mutex_unlock(&g_mutex); - - driver_desc = internal_desc->driver_desc; - - /* Now find the specific device */ - mutex_lock(&internal_desc->mutex); - for (i = 0; i < GASKET_DEV_MAX; i++) { - if (internal_desc->devs[i] && - internal_desc->devs[i]->pci_dev == pci_dev) { - gasket_dev = internal_desc->devs[i]; - break; - } - } - mutex_unlock(&internal_desc->mutex); - - if (!gasket_dev) - return; - - pr_info("remove %s device %s\n", internal_desc->driver_desc->name, - gasket_dev->kobj_name); - - gasket_disable_dev(gasket_dev); - gasket_cleanup_pci(gasket_dev); - - check_and_invoke_callback(gasket_dev, driver_desc->sysfs_cleanup_cb); - gasket_sysfs_remove_mapping(gasket_dev->dev_info.device); - - check_and_invoke_callback(gasket_dev, driver_desc->remove_dev_cb); - - device_destroy(internal_desc->class, gasket_dev->dev_info.devt); - gasket_free_dev(gasket_dev); -} - -/* - * Setup PCI & set up memory mapping for the specified device. - * - * Enables the PCI device, reads the BAR registers and sets up pointers to the - * device's memory mapped IO space. - * - * Returns 0 on success and a negative value otherwise. - */ -static int gasket_setup_pci( - struct pci_dev *pci_dev, struct gasket_dev *gasket_dev) -{ - int i, mapped_bars, ret; - - ret = pci_enable_device(pci_dev); - if (ret) { - dev_err(gasket_dev->dev, "cannot enable PCI device\n"); - return ret; - } - - pci_set_master(pci_dev); - - for (i = 0; i < GASKET_NUM_BARS; i++) { - ret = gasket_map_pci_bar(gasket_dev, i); - if (ret) { - mapped_bars = i; - goto fail; - } - } - - return 0; - -fail: - for (i = 0; i < mapped_bars; i++) - gasket_unmap_pci_bar(gasket_dev, i); - - pci_disable_device(pci_dev); - return -ENOMEM; -} - -/* Unmaps memory and cleans up PCI for the specified device. */ -static void gasket_cleanup_pci(struct gasket_dev *gasket_dev) -{ - int i; - - for (i = 0; i < GASKET_NUM_BARS; i++) - gasket_unmap_pci_bar(gasket_dev, i); - - pci_disable_device(gasket_dev->pci_dev); -} - -/* * Maps the specified bar into kernel space. * * Returns 0 on success, a negative error code otherwise. @@ -826,100 +363,280 @@ static void gasket_unmap_pci_bar(struct gasket_dev *dev, int bar_num) release_mem_region(base, bytes); } -/* Add a char device and related info. */ -static int gasket_add_cdev( - struct gasket_cdev_info *dev_info, - const struct file_operations *file_ops, struct module *owner) +/* + * Setup PCI & set up memory mapping for the specified device. + * + * Enables the PCI device, reads the BAR registers and sets up pointers to the + * device's memory mapped IO space. + * + * Returns 0 on success and a negative value otherwise. + */ +static int gasket_setup_pci( + struct pci_dev *pci_dev, struct gasket_dev *gasket_dev) { - int ret; + int i, mapped_bars, ret; - cdev_init(&dev_info->cdev, file_ops); - dev_info->cdev.owner = owner; - ret = cdev_add(&dev_info->cdev, dev_info->devt, 1); + ret = pci_enable_device(pci_dev); if (ret) { - dev_err(dev_info->gasket_dev_ptr->dev, - "cannot add char device [ret=%d]\n", ret); + dev_err(gasket_dev->dev, "cannot enable PCI device\n"); return ret; } - dev_info->cdev_added = 1; + + pci_set_master(pci_dev); + + for (i = 0; i < GASKET_NUM_BARS; i++) { + ret = gasket_map_pci_bar(gasket_dev, i); + if (ret) { + mapped_bars = i; + goto fail; + } + } return 0; + +fail: + for (i = 0; i < mapped_bars; i++) + gasket_unmap_pci_bar(gasket_dev, i); + + pci_disable_device(pci_dev); + return -ENOMEM; } -/* Perform final init and marks the device as active. */ -static int gasket_enable_dev( - struct gasket_internal_desc *internal_desc, - struct gasket_dev *gasket_dev) +/* Unmaps memory and cleans up PCI for the specified device. */ +static void gasket_cleanup_pci(struct gasket_dev *gasket_dev) { - int tbl_idx; - int ret; + int i; + + for (i = 0; i < GASKET_NUM_BARS; i++) + gasket_unmap_pci_bar(gasket_dev, i); + + pci_disable_device(gasket_dev->pci_dev); +} + +/* Determine the health of the Gasket device. */ +static int gasket_get_hw_status(struct gasket_dev *gasket_dev) +{ + int status; + int i; const struct gasket_driver_desc *driver_desc = - internal_desc->driver_desc; + gasket_dev->internal_desc->driver_desc; - ret = gasket_interrupt_init( - gasket_dev, driver_desc->name, - driver_desc->interrupt_type, driver_desc->interrupts, - driver_desc->num_interrupts, driver_desc->interrupt_pack_width, - driver_desc->interrupt_bar_index, - driver_desc->wire_interrupt_offsets); - if (ret) { - dev_err(gasket_dev->dev, - "Critical failure to allocate interrupts: %d\n", ret); - gasket_interrupt_cleanup(gasket_dev); - return ret; + status = gasket_check_and_invoke_callback_nolock( + gasket_dev, driver_desc->device_status_cb); + if (status != GASKET_STATUS_ALIVE) { + dev_dbg(gasket_dev->dev, "Hardware reported status %d.\n", + status); + return status; } - for (tbl_idx = 0; tbl_idx < driver_desc->num_page_tables; tbl_idx++) { - dev_dbg(gasket_dev->dev, "Initializing page table %d.\n", - tbl_idx); - ret = gasket_page_table_init( - &gasket_dev->page_table[tbl_idx], - &gasket_dev->bar_data[ - driver_desc->page_table_bar_index], - &driver_desc->page_table_configs[tbl_idx], - gasket_dev->dev, gasket_dev->pci_dev); - if (ret) { - dev_err(gasket_dev->dev, - "Couldn't init page table %d: %d\n", - tbl_idx, ret); - return ret; + status = gasket_interrupt_system_status(gasket_dev); + if (status != GASKET_STATUS_ALIVE) { + dev_dbg(gasket_dev->dev, + "Interrupt system reported status %d.\n", status); + return status; + } + + for (i = 0; i < driver_desc->num_page_tables; ++i) { + status = gasket_page_table_system_status( + gasket_dev->page_table[i]); + if (status != GASKET_STATUS_ALIVE) { + dev_dbg(gasket_dev->dev, + "Page table %d reported status %d.\n", + i, status); + return status; } - /* - * Make sure that the page table is clear and set to simple - * addresses. - */ - gasket_page_table_reset(gasket_dev->page_table[tbl_idx]); } - /* - * hardware_revision_cb returns a positive integer (the rev) if - * successful.) - */ - ret = check_and_invoke_callback( - gasket_dev, driver_desc->hardware_revision_cb); - if (ret < 0) { - dev_err(gasket_dev->dev, - "Error getting hardware revision: %d\n", ret); - return ret; + return GASKET_STATUS_ALIVE; +} + +static ssize_t gasket_write_mappable_regions( + char *buf, const struct gasket_driver_desc *driver_desc, int bar_index) +{ + int i; + ssize_t written; + ssize_t total_written = 0; + ulong min_addr, max_addr; + struct gasket_bar_desc bar_desc = + driver_desc->bar_descriptions[bar_index]; + + if (bar_desc.permissions == GASKET_NOMAP) + return 0; + for (i = 0; + i < bar_desc.num_mappable_regions && total_written < PAGE_SIZE; + i++) { + min_addr = bar_desc.mappable_regions[i].start - + driver_desc->legacy_mmap_address_offset; + max_addr = bar_desc.mappable_regions[i].start - + driver_desc->legacy_mmap_address_offset + + bar_desc.mappable_regions[i].length_bytes; + written = scnprintf(buf, PAGE_SIZE - total_written, + "0x%08lx-0x%08lx\n", min_addr, max_addr); + total_written += written; + buf += written; } - gasket_dev->hardware_revision = ret; + return total_written; +} - ret = check_and_invoke_callback(gasket_dev, driver_desc->enable_dev_cb); - if (ret) { - dev_err(gasket_dev->dev, "Error in enable device cb: %d\n", - ret); - return ret; +static ssize_t gasket_sysfs_data_show( + struct device *device, struct device_attribute *attr, char *buf) +{ + int i, ret = 0; + ssize_t current_written = 0; + const struct gasket_driver_desc *driver_desc; + struct gasket_dev *gasket_dev; + struct gasket_sysfs_attribute *gasket_attr; + const struct gasket_bar_desc *bar_desc; + enum gasket_sysfs_attribute_type sysfs_type; + + gasket_dev = gasket_sysfs_get_device_data(device); + if (!gasket_dev) { + dev_err(device, "No sysfs mapping found for device\n"); + return 0; } - /* device_status_cb returns a device status, not an error code. */ - gasket_dev->status = gasket_get_hw_status(gasket_dev); - if (gasket_dev->status == GASKET_STATUS_DEAD) - dev_err(gasket_dev->dev, "Device reported as unhealthy.\n"); + gasket_attr = gasket_sysfs_get_attr(device, attr); + if (!gasket_attr) { + dev_err(device, "No sysfs attr found for device\n"); + gasket_sysfs_put_device_data(device, gasket_dev); + return 0; + } - ret = gasket_add_cdev( - &gasket_dev->dev_info, &gasket_file_ops, driver_desc->module); - if (ret) + driver_desc = gasket_dev->internal_desc->driver_desc; + + sysfs_type = + (enum gasket_sysfs_attribute_type)gasket_attr->data.attr_type; + switch (sysfs_type) { + case ATTR_BAR_OFFSETS: + for (i = 0; i < GASKET_NUM_BARS; i++) { + bar_desc = &driver_desc->bar_descriptions[i]; + if (bar_desc->size == 0) + continue; + current_written = + snprintf(buf, PAGE_SIZE - ret, "%d: 0x%lx\n", i, + (ulong)bar_desc->base); + buf += current_written; + ret += current_written; + } + break; + case ATTR_BAR_SIZES: + for (i = 0; i < GASKET_NUM_BARS; i++) { + bar_desc = &driver_desc->bar_descriptions[i]; + if (bar_desc->size == 0) + continue; + current_written = + snprintf(buf, PAGE_SIZE - ret, "%d: 0x%lx\n", i, + (ulong)bar_desc->size); + buf += current_written; + ret += current_written; + } + break; + case ATTR_DRIVER_VERSION: + ret = snprintf( + buf, PAGE_SIZE, "%s\n", + gasket_dev->internal_desc->driver_desc->driver_version); + break; + case ATTR_FRAMEWORK_VERSION: + ret = snprintf( + buf, PAGE_SIZE, "%s\n", GASKET_FRAMEWORK_VERSION); + break; + case ATTR_DEVICE_TYPE: + ret = snprintf( + buf, PAGE_SIZE, "%s\n", + gasket_dev->internal_desc->driver_desc->name); + break; + case ATTR_HARDWARE_REVISION: + ret = snprintf( + buf, PAGE_SIZE, "%d\n", gasket_dev->hardware_revision); + break; + case ATTR_PCI_ADDRESS: + ret = snprintf(buf, PAGE_SIZE, "%s\n", gasket_dev->kobj_name); + break; + case ATTR_STATUS: + ret = snprintf( + buf, PAGE_SIZE, "%s\n", + gasket_num_name_lookup( + gasket_dev->status, gasket_status_name_table)); + break; + case ATTR_IS_DEVICE_OWNED: + ret = snprintf( + buf, PAGE_SIZE, "%d\n", + gasket_dev->dev_info.ownership.is_owned); + break; + case ATTR_DEVICE_OWNER: + ret = snprintf( + buf, PAGE_SIZE, "%d\n", + gasket_dev->dev_info.ownership.owner); + break; + case ATTR_WRITE_OPEN_COUNT: + ret = snprintf( + buf, PAGE_SIZE, "%d\n", + gasket_dev->dev_info.ownership.write_open_count); + break; + case ATTR_RESET_COUNT: + ret = snprintf(buf, PAGE_SIZE, "%d\n", gasket_dev->reset_count); + break; + case ATTR_USER_MEM_RANGES: + for (i = 0; i < GASKET_NUM_BARS; ++i) { + current_written = gasket_write_mappable_regions( + buf, driver_desc, i); + buf += current_written; + ret += current_written; + } + break; + default: + dev_dbg(gasket_dev->dev, "Unknown attribute: %s\n", + attr->attr.name); + ret = 0; + break; + } + + gasket_sysfs_put_attr(device, gasket_attr); + gasket_sysfs_put_device_data(device, gasket_dev); + return ret; +} + +/* These attributes apply to all Gasket driver instances. */ +static const struct gasket_sysfs_attribute gasket_sysfs_generic_attrs[] = { + GASKET_SYSFS_RO(bar_offsets, gasket_sysfs_data_show, ATTR_BAR_OFFSETS), + GASKET_SYSFS_RO(bar_sizes, gasket_sysfs_data_show, ATTR_BAR_SIZES), + GASKET_SYSFS_RO(driver_version, gasket_sysfs_data_show, + ATTR_DRIVER_VERSION), + GASKET_SYSFS_RO(framework_version, gasket_sysfs_data_show, + ATTR_FRAMEWORK_VERSION), + GASKET_SYSFS_RO(device_type, gasket_sysfs_data_show, ATTR_DEVICE_TYPE), + GASKET_SYSFS_RO(revision, gasket_sysfs_data_show, + ATTR_HARDWARE_REVISION), + GASKET_SYSFS_RO(pci_address, gasket_sysfs_data_show, ATTR_PCI_ADDRESS), + GASKET_SYSFS_RO(status, gasket_sysfs_data_show, ATTR_STATUS), + GASKET_SYSFS_RO(is_device_owned, gasket_sysfs_data_show, + ATTR_IS_DEVICE_OWNED), + GASKET_SYSFS_RO(device_owner, gasket_sysfs_data_show, + ATTR_DEVICE_OWNER), + GASKET_SYSFS_RO(write_open_count, gasket_sysfs_data_show, + ATTR_WRITE_OPEN_COUNT), + GASKET_SYSFS_RO(reset_count, gasket_sysfs_data_show, ATTR_RESET_COUNT), + GASKET_SYSFS_RO(user_mem_ranges, gasket_sysfs_data_show, + ATTR_USER_MEM_RANGES), + GASKET_END_OF_ATTR_ARRAY +}; + +/* Add a char device and related info. */ +static int gasket_add_cdev( + struct gasket_cdev_info *dev_info, + const struct file_operations *file_ops, struct module *owner) +{ + int ret; + + cdev_init(&dev_info->cdev, file_ops); + dev_info->cdev.owner = owner; + ret = cdev_add(&dev_info->cdev, dev_info->devt, 1); + if (ret) { + dev_err(dev_info->gasket_dev_ptr->dev, + "cannot add char device [ret=%d]\n", ret); return ret; + } + dev_info->cdev_added = 1; return 0; } @@ -971,177 +688,6 @@ static struct gasket_internal_desc *lookup_internal_desc( return NULL; } -/** - * Lookup a name by number in a num_name table. - * @num: Number to lookup. - * @table: Array of num_name structures, the table for the lookup. - * - * Description: Searches for num in the table. If found, the - * corresponding name is returned; otherwise NULL - * is returned. - * - * The table must have a NULL name pointer at the end. - */ -const char *gasket_num_name_lookup( - uint num, const struct gasket_num_name *table) -{ - uint i = 0; - - while (table[i].snn_name) { - if (num == table[i].snn_num) - break; - ++i; - } - - return table[i].snn_name; -} -EXPORT_SYMBOL(gasket_num_name_lookup); - -/* - * Open the char device file. - * - * If the open is for writing, and the device is not owned, this process becomes - * the owner. If the open is for writing and the device is already owned by - * some other process, it is an error. If this process is the owner, increment - * the open count. - * - * Returns 0 if successful, a negative error number otherwise. - */ -static int gasket_open(struct inode *inode, struct file *filp) -{ - int ret; - struct gasket_dev *gasket_dev; - const struct gasket_driver_desc *driver_desc; - struct gasket_ownership *ownership; - char task_name[TASK_COMM_LEN]; - struct gasket_cdev_info *dev_info = - container_of(inode->i_cdev, struct gasket_cdev_info, cdev); - struct pid_namespace *pid_ns = task_active_pid_ns(current); - int is_root = ns_capable(pid_ns->user_ns, CAP_SYS_ADMIN); - - gasket_dev = dev_info->gasket_dev_ptr; - driver_desc = gasket_dev->internal_desc->driver_desc; - ownership = &dev_info->ownership; - get_task_comm(task_name, current); - filp->private_data = gasket_dev; - inode->i_size = 0; - - dev_dbg(gasket_dev->dev, - "Attempting to open with tgid %u (%s) (f_mode: 0%03o, " - "fmode_write: %d is_root: %u)\n", - current->tgid, task_name, filp->f_mode, - (filp->f_mode & FMODE_WRITE), is_root); - - /* Always allow non-writing accesses. */ - if (!(filp->f_mode & FMODE_WRITE)) { - dev_dbg(gasket_dev->dev, "Allowing read-only opening.\n"); - return 0; - } - - mutex_lock(&gasket_dev->mutex); - - dev_dbg(gasket_dev->dev, - "Current owner open count (owning tgid %u): %d.\n", - ownership->owner, ownership->write_open_count); - - /* Opening a node owned by another TGID is an error (unless root) */ - if (ownership->is_owned && ownership->owner != current->tgid && - !is_root) { - dev_err(gasket_dev->dev, - "Process %u is opening a node held by %u.\n", - current->tgid, ownership->owner); - mutex_unlock(&gasket_dev->mutex); - return -EPERM; - } - - /* If the node is not owned, assign it to the current TGID. */ - if (!ownership->is_owned) { - ret = gasket_check_and_invoke_callback_nolock( - gasket_dev, driver_desc->device_open_cb); - if (ret) { - dev_err(gasket_dev->dev, - "Error in device open cb: %d\n", ret); - mutex_unlock(&gasket_dev->mutex); - return ret; - } - ownership->is_owned = 1; - ownership->owner = current->tgid; - dev_dbg(gasket_dev->dev, "Device owner is now tgid %u\n", - ownership->owner); - } - - ownership->write_open_count++; - - dev_dbg(gasket_dev->dev, "New open count (owning tgid %u): %d\n", - ownership->owner, ownership->write_open_count); - - mutex_unlock(&gasket_dev->mutex); - return 0; -} - -/* - * Called on a close of the device file. If this process is the owner, - * decrement the open count. On last close by the owner, free up buffers and - * eventfd contexts, and release ownership. - * - * Returns 0 if successful, a negative error number otherwise. - */ -static int gasket_release(struct inode *inode, struct file *file) -{ - int i; - struct gasket_dev *gasket_dev; - struct gasket_ownership *ownership; - const struct gasket_driver_desc *driver_desc; - char task_name[TASK_COMM_LEN]; - struct gasket_cdev_info *dev_info = - container_of(inode->i_cdev, struct gasket_cdev_info, cdev); - struct pid_namespace *pid_ns = task_active_pid_ns(current); - int is_root = ns_capable(pid_ns->user_ns, CAP_SYS_ADMIN); - - gasket_dev = dev_info->gasket_dev_ptr; - driver_desc = gasket_dev->internal_desc->driver_desc; - ownership = &dev_info->ownership; - get_task_comm(task_name, current); - mutex_lock(&gasket_dev->mutex); - - dev_dbg(gasket_dev->dev, - "Releasing device node. Call origin: tgid %u (%s) " - "(f_mode: 0%03o, fmode_write: %d, is_root: %u)\n", - current->tgid, task_name, file->f_mode, - (file->f_mode & FMODE_WRITE), is_root); - dev_dbg(gasket_dev->dev, "Current open count (owning tgid %u): %d\n", - ownership->owner, ownership->write_open_count); - - if (file->f_mode & FMODE_WRITE) { - ownership->write_open_count--; - if (ownership->write_open_count == 0) { - dev_dbg(gasket_dev->dev, "Device is now free\n"); - ownership->is_owned = 0; - ownership->owner = 0; - - /* Forces chip reset before we unmap the page tables. */ - driver_desc->device_reset_cb(gasket_dev, 0); - - for (i = 0; i < driver_desc->num_page_tables; ++i) { - gasket_page_table_unmap_all( - gasket_dev->page_table[i]); - gasket_page_table_garbage_collect( - gasket_dev->page_table[i]); - gasket_free_coherent_memory_all(gasket_dev, i); - } - - /* Closes device, enters power save. */ - gasket_check_and_invoke_callback_nolock( - gasket_dev, driver_desc->device_close_cb); - } - } - - dev_dbg(gasket_dev->dev, "New open count (owning tgid %u): %d\n", - ownership->owner, ownership->write_open_count); - mutex_unlock(&gasket_dev->mutex); - return 0; -} - /* * Verifies that the user has permissions to perform the requested mapping and * that the provided descriptor/range is of adequate size to hold the range to @@ -1301,6 +847,36 @@ static bool gasket_mm_get_mapping_addrs( return false; } +/* + * |