From 2db21ac5a4e01ed19ee2d897d75398fff0429514 Mon Sep 17 00:00:00 2001 From: Aaron Young Date: Thu, 10 Dec 2015 06:39:54 -0800 Subject: [PATCH] SPARC64: UEK4 LDOMS DOMAIN SERVICES UPDATE 2 This update provides fixes for LDom domain services on UEK4. Including: 1. Add control vlds device for non-device specific operations. 2. Allocate larger LDC rx/tx queues based on MTU - same algorithm as Solaris. 3. Fix default MTU for all ds devices to 4096 bytes. Signed-off-by: Aaron Young Orabug: 22347667 (cherry picked from commit f2cf5889f22fd3d1062a7fe985a6ab574eebdbf5) --- arch/sparc/kernel/ds.c | 10 +++------- arch/sparc/kernel/ldc.c | 29 +++++++++++++++++++++++------ drivers/char/vlds.c | 38 ++++++++++++++++++++++++++++++++++++++ include/uapi/linux/vlds.h | 2 ++ 4 files changed, 66 insertions(+), 13 deletions(-) diff --git a/arch/sparc/kernel/ds.c b/arch/sparc/kernel/ds.c index 28ce1ecd226b..9ed18a51dac2 100644 --- a/arch/sparc/kernel/ds.c +++ b/arch/sparc/kernel/ds.c @@ -114,7 +114,6 @@ MODULE_VERSION(DRV_MODULE_VERSION); * The largest contiguous buffer the kernel seems to allow is 8MB. */ #define DS_DEFAULT_SP_BUF_SIZE (8*1024*1024) -#define DS_DEFAULT_SP_MTU (8*1024*1024) #define DS_PRIMARY_ID 0 @@ -198,7 +197,7 @@ struct ds_dev { /* LDC receive data buffer for this ds_dev */ u8 *rcv_buf; - int rcv_buf_len; + u64 rcv_buf_len; u32 mtu; /* service registration timer */ @@ -4321,9 +4320,6 @@ static int ds_probe(struct vio_dev *vdev, const struct vio_device_id *id) goto out_free_ds; ds->rcv_buf_len = DS_DEFAULT_SP_BUF_SIZE; - - ds_cfg.mtu = DS_DEFAULT_SP_MTU; - } else { ds->rcv_buf = kzalloc(DS_DEFAULT_BUF_SIZE, GFP_KERNEL); @@ -4331,11 +4327,11 @@ static int ds_probe(struct vio_dev *vdev, const struct vio_device_id *id) goto out_free_ds; ds->rcv_buf_len = DS_DEFAULT_BUF_SIZE; - - ds_cfg.mtu = DS_DEFAULT_MTU; } + ds_cfg.mtu = DS_DEFAULT_MTU; ds->mtu = ds_cfg.mtu; + ds->hs_state = DS_HS_LDC_DOWN; ds_cfg.debug = 0; ds_cfg.tx_irq = vdev->tx_irq; diff --git a/arch/sparc/kernel/ldc.c b/arch/sparc/kernel/ldc.c index d6ac8969d315..0f5aad4da8d4 100644 --- a/arch/sparc/kernel/ldc.c +++ b/arch/sparc/kernel/ldc.c @@ -86,7 +86,8 @@ static struct ldc_version ver_arr[] = { }; #define LDC_DEFAULT_MTU (4 * LDC_PACKET_SIZE) -#define LDC_DEFAULT_NUM_ENTRIES (PAGE_SIZE / LDC_PACKET_SIZE) +#define LDC_MTU_MSGS (4) +#define LDC_MIN_NUM_ENTRIES (512) struct ldc_channel; @@ -1157,6 +1158,7 @@ struct ldc_channel *ldc_alloc(unsigned long id, const struct ldc_mode_ops *mops; unsigned long dummy1, dummy2, hv_err; u8 mss, *mssbuf; + u32 num_entries; int err; err = -ENODEV; @@ -1234,11 +1236,26 @@ struct ldc_channel *ldc_alloc(unsigned long id, lp->event_arg = event_arg; - /* XXX allow setting via ldc_channel_config to override defaults - * XXX or use some formula based upon mtu - */ - lp->tx_num_entries = LDC_DEFAULT_NUM_ENTRIES; - lp->rx_num_entries = LDC_DEFAULT_NUM_ENTRIES; + /* calculate the number of rx/tx queue entries */ + num_entries = (lp->cfg.mtu * LDC_MTU_MSGS) / mss; + + /* round num_entries up to nearest power of 2 - per spec */ + if ((num_entries & (num_entries - 1)) != 0) { + + uint64_t tmp = 1; + + while (num_entries) { + num_entries >>= 1; tmp <<= 1; + } + num_entries = tmp; + } + + /* guarantee a minimum number of queue entries */ + if (num_entries < LDC_MIN_NUM_ENTRIES) + num_entries = LDC_MIN_NUM_ENTRIES; + + lp->tx_num_entries = num_entries; + lp->rx_num_entries = num_entries; err = alloc_queue("TX", lp->tx_num_entries, &lp->tx_base, &lp->tx_ra); diff --git a/drivers/char/vlds.c b/drivers/char/vlds.c index be6946db9c25..8d5498058187 100644 --- a/drivers/char/vlds.c +++ b/drivers/char/vlds.c @@ -87,6 +87,10 @@ struct vlds_dev { struct vlds_dev *sp_vlds; #define IS_SP_VLDS(vlds_dev) ((vlds_dev) == sp_vlds) +/* Control device to provide non-device specific operations */ +struct vlds_dev *ctrl_vlds; +#define IS_CTRL_VLDS(vlds_dev) ((vlds_dev) == ctrl_vlds) + /* * Service info to describe a service and process(es) using the service. * Services can be regsitered as shared (the default) or exclusive. @@ -2064,6 +2068,19 @@ static long vlds_fops_ioctl(struct file *filp, unsigned int cmd, return -ENXIO; } + if (IS_CTRL_VLDS(vlds)) { + /* + * For the control device, + * we only allow the following operations. + */ + if (cmd != VLDS_IOCTL_SET_EVENT_FD && + cmd != VLDS_IOCTL_UNSET_EVENT_FD && + cmd != VLDS_IOCTL_GET_NEXT_EVENT) { + mutex_unlock(&vlds->vlds_mutex); + return -EINVAL; + } + } + mutex_unlock(&vlds->vlds_mutex); switch (cmd) { @@ -2506,6 +2523,12 @@ static int __init vlds_init(void) /* set callback to create devices under /dev/vlds directory */ vlds_data.chrdev_class->devnode = vlds_devnode; + /* Create the control device */ + rv = vlds_alloc_vlds_dev(VLDS_CTRL_DEV_NAME, VLDS_CTRL_DEV_NAME, + NULL, VLDS_INVALID_HANDLE, &ctrl_vlds); + if (rv != 0) + dprintk("Failed to create control vlds device (%d)\n", rv); + /* * If there is a SP DS present on the system (in the MD), * add a device for the SP directly since there is no @@ -2558,6 +2581,21 @@ static void __exit vlds_exit(void) mutex_unlock(&vlds_data_mutex); } + if (ctrl_vlds) { + + mutex_lock(&vlds_data_mutex); + mutex_lock(&ctrl_vlds->vlds_mutex); + + /* Cleanup the associated cdev, /sys and /dev entry */ + device_destroy(vlds_data.chrdev_class, ctrl_vlds->devt); + cdev_del(&ctrl_vlds->cdev); + + vlds_free_vlds_dev(ctrl_vlds); + ctrl_vlds = NULL; + + mutex_unlock(&vlds_data_mutex); + } + /* * Note - vio_unregister_driver() will invoke a call to * vlds_remove() for every successfully probed device. diff --git a/include/uapi/linux/vlds.h b/include/uapi/linux/vlds.h index 99f26c561bbc..bd064ef35122 100644 --- a/include/uapi/linux/vlds.h +++ b/include/uapi/linux/vlds.h @@ -10,7 +10,9 @@ #define VLDS_DEV_DIR "/dev/vlds" #define VLDS_SP_DEV_NAME "sp" /* SP DS device name */ +#define VLDS_CTRL_DEV_NAME "ctrl" /* Control DS device name */ #define VLDS_DEV_DOMAIN_FILENAME_TAG "host:" +#define VLDS_INVALID_HANDLE 0xFFFFFFFFFFFFFFFFUL /* String arguments to ioctl */ typedef struct vlds_string_arg { -- 2.50.1