* 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
/* LDC receive data buffer for this ds_dev */
u8 *rcv_buf;
- int rcv_buf_len;
+ u64 rcv_buf_len;
u32 mtu;
/* service registration timer */
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);
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;
};
#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;
const struct ldc_mode_ops *mops;
unsigned long dummy1, dummy2, hv_err;
u8 mss, *mssbuf;
+ u32 num_entries;
int err;
err = -ENODEV;
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);
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.
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) {
/* 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
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.
#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 {