diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-05 05:07:20 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-05 05:07:20 +0200 |
commit | 06dd3dfeea60e2a6457a6aedf97afc8e6d2ba497 (patch) | |
tree | 1d8b9efbd7cd3dbb5d7b7663d7fd2de61b26f453 /drivers/uio/uio_hv_generic.c | |
parent | Merge tag 'driver-core-4.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel... (diff) | |
parent | Merge tag 'stm-intel_th-for-greg-20180329' of git://git.kernel.org/pub/scm/li... (diff) | |
download | linux-06dd3dfeea60e2a6457a6aedf97afc8e6d2ba497.tar.xz linux-06dd3dfeea60e2a6457a6aedf97afc8e6d2ba497.zip |
Merge tag 'char-misc-4.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc
Pull char/misc updates from Greg KH:
"Here is the big set of char/misc driver patches for 4.17-rc1.
There are a lot of little things in here, nothing huge, but all
important to the different hardware types involved:
- thunderbolt driver updates
- parport updates (people still care...)
- nvmem driver updates
- mei updates (as always)
- hwtracing driver updates
- hyperv driver updates
- extcon driver updates
- ... and a handful of even smaller driver subsystem and individual
driver updates
All of these have been in linux-next with no reported issues"
* tag 'char-misc-4.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (149 commits)
hwtracing: Add HW tracing support menu
intel_th: Add ACPI glue layer
intel_th: Allow forcing host mode through drvdata
intel_th: Pick up irq number from resources
intel_th: Don't touch switch routing in host mode
intel_th: Use correct method of finding hub
intel_th: Add SPDX GPL-2.0 header to replace GPLv2 boilerplate
stm class: Make dummy's master/channel ranges configurable
stm class: Add SPDX GPL-2.0 header to replace GPLv2 boilerplate
MAINTAINERS: Bestow upon myself the care for drivers/hwtracing
hv: add SPDX license id to Kconfig
hv: add SPDX license to trace
Drivers: hv: vmbus: do not mark HV_PCIE as perf_device
Drivers: hv: vmbus: respect what we get from hv_get_synint_state()
/dev/mem: Avoid overwriting "err" in read_mem()
eeprom: at24: use SPDX identifier instead of GPL boiler-plate
eeprom: at24: simplify the i2c functionality checking
eeprom: at24: fix a line break
eeprom: at24: tweak newlines
eeprom: at24: refactor at24_probe()
...
Diffstat (limited to 'drivers/uio/uio_hv_generic.c')
-rw-r--r-- | drivers/uio/uio_hv_generic.c | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c index 8ca549032c27..f695a7e8c314 100644 --- a/drivers/uio/uio_hv_generic.c +++ b/drivers/uio/uio_hv_generic.c @@ -121,6 +121,94 @@ static void hv_uio_rescind(struct vmbus_channel *channel) uio_event_notify(&pdata->info); } +/* + * Handle fault when looking for sub channel ring buffer + * Subchannel ring buffer is same as resource 0 which is main ring buffer + * This is derived from uio_vma_fault + */ +static int hv_uio_vma_fault(struct vm_fault *vmf) +{ + struct vm_area_struct *vma = vmf->vma; + void *ring_buffer = vma->vm_private_data; + struct page *page; + void *addr; + + addr = ring_buffer + (vmf->pgoff << PAGE_SHIFT); + page = virt_to_page(addr); + get_page(page); + vmf->page = page; + return 0; +} + +static const struct vm_operations_struct hv_uio_vm_ops = { + .fault = hv_uio_vma_fault, +}; + +/* Sysfs API to allow mmap of the ring buffers */ +static int hv_uio_ring_mmap(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + struct vm_area_struct *vma) +{ + struct vmbus_channel *channel + = container_of(kobj, struct vmbus_channel, kobj); + unsigned long requested_pages, actual_pages; + + if (vma->vm_end < vma->vm_start) + return -EINVAL; + + /* only allow 0 for now */ + if (vma->vm_pgoff > 0) + return -EINVAL; + + requested_pages = vma_pages(vma); + actual_pages = 2 * HV_RING_SIZE; + if (requested_pages > actual_pages) + return -EINVAL; + + vma->vm_private_data = channel->ringbuffer_pages; + vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; + vma->vm_ops = &hv_uio_vm_ops; + return 0; +} + +static struct bin_attribute ring_buffer_bin_attr __ro_after_init = { + .attr = { + .name = "ring", + .mode = 0600, + /* size is set at init time */ + }, + .mmap = hv_uio_ring_mmap, +}; + +/* Callback from VMBUS subystem when new channel created. */ +static void +hv_uio_new_channel(struct vmbus_channel *new_sc) +{ + struct hv_device *hv_dev = new_sc->primary_channel->device_obj; + struct device *device = &hv_dev->device; + struct hv_uio_private_data *pdata = hv_get_drvdata(hv_dev); + const size_t ring_bytes = HV_RING_SIZE * PAGE_SIZE; + int ret; + + /* Create host communication ring */ + ret = vmbus_open(new_sc, ring_bytes, ring_bytes, NULL, 0, + hv_uio_channel_cb, pdata); + if (ret) { + dev_err(device, "vmbus_open subchannel failed: %d\n", ret); + return; + } + + /* Disable interrupts on sub channel */ + new_sc->inbound.ring_buffer->interrupt_mask = 1; + set_channel_read_mode(new_sc, HV_CALL_ISR); + + ret = sysfs_create_bin_file(&new_sc->kobj, &ring_buffer_bin_attr); + if (ret) { + dev_err(device, "sysfs create ring bin file failed; %d\n", ret); + vmbus_close(new_sc); + } +} + static void hv_uio_cleanup(struct hv_device *dev, struct hv_uio_private_data *pdata) { @@ -236,6 +324,7 @@ hv_uio_probe(struct hv_device *dev, } vmbus_set_chn_rescind_callback(dev->channel, hv_uio_rescind); + vmbus_set_sc_create_callback(dev->channel, hv_uio_new_channel); hv_set_drvdata(dev, pdata); |