@@ -7,6 +7,7 @@
#include <linux/file.h>
#include <linux/kthread.h>
#include <linux/module.h>
+#include <linux/dma-mapping.h>
#include "usbip_common.h"
#include "stub.h"
@@ -34,6 +35,46 @@ static ssize_t usbip_status_show(struct device *dev,
}
static DEVICE_ATTR_RO(usbip_status);
+/*
+ * The real USB controllers may support larger than 32-bit address memory pointers actually.
+ * But vhci-hcd driver use the default platform device dma mask set(32-bit),
+ * and usbip device's max_sectors will be limited by dma max mapping size.
+ * usbip_dma_bits shows the real dma mask bit of the real usb controller
+ * which usbip device is bound to.
+ */
+static unsigned int mask_convert_to_bits(u64 dma_mask)
+{
+ unsigned int bits = 0;
+
+ while (dma_mask & 0x1) {
+ dma_mask >>= 1;
+ bits++;
+ }
+ return bits;
+}
+
+static ssize_t usbip_dma_bits_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct stub_device *sdev = dev_get_drvdata(dev);
+ struct device *sys_dev = sdev->udev->bus->sysdev;
+ u64 dma_mask = 0;
+ unsigned int dma_bits = 0;
+
+ if (!sdev || !sys_dev) {
+ dev_err(dev, "sdev or sys_dev is null\n");
+ return -ENODEV;
+ }
+
+ spin_lock_irq(&sdev->ud.lock);
+ dma_mask = dma_get_mask(sys_dev);
+ dma_bits = mask_convert_to_bits(dma_mask);
+ spin_unlock_irq(&sdev->ud.lock);
+
+ return sysfs_emit(buf, "%d\n", dma_bits);
+}
+static DEVICE_ATTR_RO(usbip_dma_bits);
+
/*
* usbip_sockfd gets a socket descriptor of an established TCP connection that
* is used to transfer usbip requests by kernel threads. -1 is a magic number
@@ -144,6 +185,7 @@ static DEVICE_ATTR_WO(usbip_sockfd);
static struct attribute *usbip_attrs[] = {
&dev_attr_usbip_status.attr,
+ &dev_attr_usbip_dma_bits.attr,
&dev_attr_usbip_sockfd.attr,
&dev_attr_usbip_debug.attr,
NULL,
@@ -12,6 +12,7 @@
/* Hardening for Spectre-v1 */
#include <linux/nospec.h>
+#include <linux/dma-mapping.h>
#include "usbip_common.h"
#include "vhci.h"
@@ -311,7 +312,7 @@ static ssize_t attach_store(struct device *dev, struct device_attribute *attr,
{
struct socket *socket;
int sockfd = 0;
- __u32 port = 0, pdev_nr = 0, rhport = 0, devid = 0, speed = 0;
+ __u32 port = 0, pdev_nr = 0, rhport = 0, devid = 0, speed = 0, dma_bits = 0;
struct usb_hcd *hcd;
struct vhci_hcd *vhci_hcd;
struct vhci_device *vdev;
@@ -327,15 +328,15 @@ static ssize_t attach_store(struct device *dev, struct device_attribute *attr,
* @devid: unique device identifier in a remote host
* @speed: usb device speed in a remote host
*/
- if (sscanf(buf, "%u %u %u %u", &port, &sockfd, &devid, &speed) != 4)
+ if (sscanf(buf, "%u %u %u %u %u", &port, &sockfd, &devid, &speed, &dma_bits) != 5)
return -EINVAL;
pdev_nr = port_to_pdev_nr(port);
rhport = port_to_rhport(port);
usbip_dbg_vhci_sysfs("port(%u) pdev(%d) rhport(%u)\n",
port, pdev_nr, rhport);
- usbip_dbg_vhci_sysfs("sockfd(%u) devid(%u) speed(%u)\n",
- sockfd, devid, speed);
+ usbip_dbg_vhci_sysfs("sockfd(%u) devid(%u) speed(%u) dma_bits(%u)\n",
+ sockfd, devid, speed, dma_bits);
/* check received parameters */
if (!valid_args(&pdev_nr, &rhport, speed))
@@ -346,6 +347,8 @@ static ssize_t attach_store(struct device *dev, struct device_attribute *attr,
dev_err(dev, "port %d is not ready\n", port);
return -EAGAIN;
}
+ /* Set the real USB controller's dma mask to vhci-hcd driver. */
+ dma_set_mask(dev, DMA_BIT_MASK(dma_bits));
vhci_hcd = hcd_to_vhci_hcd(hcd);
vhci = vhci_hcd->vhci;
@@ -115,6 +115,7 @@ struct usbip_usb_device {
uint32_t busnum;
uint32_t devnum;
uint32_t speed;
+ uint32_t dma_bits;
uint16_t idVendor;
uint16_t idProduct;
@@ -61,6 +61,38 @@ static int32_t read_attr_usbip_status(struct usbip_usb_device *udev)
return value;
}
+static int32_t read_attr_usbip_dma_bits(struct usbip_usb_device *udev)
+{
+ char dma_bits_attr_path[SYSFS_PATH_MAX];
+ int size;
+ int fd;
+ int length;
+ char dma_bits[3] = { 0 };
+
+ size = snprintf(dma_bits_attr_path, sizeof(dma_bits_attr_path),
+ "%s/usbip_dma_bits", udev->path);
+ if (size < 0 || (unsigned int)size >= sizeof(dma_bits_attr_path)) {
+ err("usbip_dma_bits path length %i >= %lu or < 0", size,
+ (unsigned long)sizeof(dma_bits_attr_path));
+ return -1;
+ }
+
+ fd = open(dma_bits_attr_path, O_RDONLY);
+ if (fd < 0) {
+ err("error opening attribute %s", dma_bits_attr_path);
+ return -1;
+ }
+ length = read(fd, dma_bits, 2);
+ if (length < 0) {
+ err("error reading attribute %s", dma_bits_attr_path);
+ close(fd);
+ return -1;
+ }
+ udev->dma_bits = atoi(dma_bits);
+ close(fd);
+ return 0;
+}
+
static
struct usbip_exported_device *usbip_exported_device_new(
struct usbip_host_driver *hdriver, const char *sdevpath)
@@ -82,6 +114,8 @@ struct usbip_exported_device *usbip_exported_device_new(
if (hdriver->ops.read_device(edev->sudev, &edev->udev) < 0)
goto err;
+ read_attr_usbip_dma_bits(&edev->udev);
+
edev->status = read_attr_usbip_status(&edev->udev);
if (edev->status < 0)
goto err;
@@ -355,15 +355,15 @@ int usbip_vhci_get_free_port(uint32_t speed)
}
int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid,
- uint32_t speed) {
+ uint32_t speed, uint32_t dma_bits) {
char buff[200]; /* what size should be ? */
char attach_attr_path[SYSFS_PATH_MAX];
char attr_attach[] = "attach";
const char *path;
int ret;
- snprintf(buff, sizeof(buff), "%u %d %u %u",
- port, sockfd, devid, speed);
+ snprintf(buff, sizeof(buff), "%u %d %u %u %u",
+ port, sockfd, devid, speed, dma_bits);
dbg("writing: %s", buff);
path = udev_device_get_syspath(vhci_driver->hc_device);
@@ -389,11 +389,11 @@ static unsigned long get_devid(uint8_t busnum, uint8_t devnum)
/* will be removed */
int usbip_vhci_attach_device(uint8_t port, int sockfd, uint8_t busnum,
- uint8_t devnum, uint32_t speed)
+ uint8_t devnum, uint32_t speed, uint32_t dma_bits)
{
int devid = get_devid(busnum, devnum);
- return usbip_vhci_attach_device2(port, sockfd, devid, speed);
+ return usbip_vhci_attach_device2(port, sockfd, devid, speed, dma_bits);
}
int usbip_vhci_detach_device(uint8_t port)
@@ -54,11 +54,11 @@ int usbip_vhci_refresh_device_list(void);
int usbip_vhci_get_free_port(uint32_t speed);
int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid,
- uint32_t speed);
+ uint32_t speed, uint32_t dma_bits);
/* will be removed */
int usbip_vhci_attach_device(uint8_t port, int sockfd, uint8_t busnum,
- uint8_t devnum, uint32_t speed);
+ uint8_t devnum, uint32_t speed, uint32_t dma_bits);
int usbip_vhci_detach_device(uint8_t port);
@@ -100,7 +100,7 @@ static int import_device(int sockfd, struct usbip_usb_device *udev)
dbg("got free port %d", port);
rc = usbip_vhci_attach_device(port, sockfd, udev->busnum,
- udev->devnum, udev->speed);
+ udev->devnum, udev->speed, udev->dma_bits);
if (rc < 0 && errno != EBUSY) {
err("import device");
goto err_driver_close;
@@ -79,6 +79,7 @@ void usbip_net_pack_usb_device(int pack, struct usbip_usb_device *udev)
udev->busnum = usbip_net_pack_uint32_t(pack, udev->busnum);
udev->devnum = usbip_net_pack_uint32_t(pack, udev->devnum);
udev->speed = usbip_net_pack_uint32_t(pack, udev->speed);
+ udev->dma_bits = usbip_net_pack_uint32_t(pack, udev->dma_bits);
udev->idVendor = usbip_net_pack_uint16_t(pack, udev->idVendor);
udev->idProduct = usbip_net_pack_uint16_t(pack, udev->idProduct);