diff options
Diffstat (limited to 'driver/hdm-usb/hdm_usb.c')
-rw-r--r-- | driver/hdm-usb/hdm_usb.c | 122 |
1 files changed, 67 insertions, 55 deletions
diff --git a/driver/hdm-usb/hdm_usb.c b/driver/hdm-usb/hdm_usb.c index 3433646..5b0af88 100644 --- a/driver/hdm-usb/hdm_usb.c +++ b/driver/hdm-usb/hdm_usb.c @@ -30,7 +30,6 @@ #include <linux/etherdevice.h> #include <linux/uaccess.h> #include "mostcore.h" -#include "networking.h" #define USB_MTU 512 #define NO_ISOCHRONOUS_URB 0 @@ -126,6 +125,8 @@ struct most_dev { struct mutex io_mutex; struct timer_list link_stat_timer; struct work_struct poll_work_obj; + void (*on_netinfo)(struct most_interface *, unsigned char, + unsigned char *); }; #define to_mdev(d) container_of(d, struct most_dev, iface) @@ -145,7 +146,7 @@ static void wq_netinfo(struct work_struct *wq_obj); static inline int drci_rd_reg(struct usb_device *dev, u16 reg, u16 *buf) { int retval; - u16 *dma_buf = kzalloc(sizeof(u16), GFP_KERNEL); + __le16 *dma_buf = kzalloc(sizeof(*dma_buf), GFP_KERNEL); u8 req_type = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE; if (!dma_buf) @@ -154,7 +155,7 @@ static inline int drci_rd_reg(struct usb_device *dev, u16 reg, u16 *buf) retval = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), DRCI_READ_REQ, req_type, 0x0000, - reg, dma_buf, sizeof(u16), 5 * HZ); + reg, dma_buf, sizeof(*dma_buf), 5 * HZ); *buf = le16_to_cpu(*dma_buf); kfree(dma_buf); @@ -281,7 +282,6 @@ static int hdm_add_padding(struct most_dev *mdev, int channel, struct mbo *mbo) struct most_channel_config *conf = &mdev->conf[channel]; unsigned int frame_size = get_stream_frame_size(conf); unsigned int j, num_frames; - u16 rd_addr, wr_addr; if (!frame_size) return -EIO; @@ -293,13 +293,10 @@ static int hdm_add_padding(struct most_dev *mdev, int channel, struct mbo *mbo) return -EIO; } - for (j = 1; j < num_frames; j++) { - wr_addr = (num_frames - j) * USB_MTU; - rd_addr = (num_frames - j) * frame_size; - memmove(mbo->virt_address + wr_addr, - mbo->virt_address + rd_addr, + for (j = num_frames - 1; j > 0; j--) + memmove(mbo->virt_address + j * USB_MTU, + mbo->virt_address + j * frame_size, frame_size); - } mbo->buffer_length = num_frames * USB_MTU; return 0; } @@ -490,7 +487,7 @@ static void hdm_write_completion(struct urb *urb) * disconnect. In the interval before the hub driver starts disconnect * processing, devices may receive such fault reports for every request. * - * See <https://www.kernel.org/doc/Documentation/usb/error-codes.txt> + * See <https://www.kernel.org/doc/Documentation/driver-api/usb/error-codes.rst> */ static void hdm_read_completion(struct urb *urb) { @@ -629,19 +626,42 @@ _error: return retval; } +static void *hdm_dma_alloc(struct mbo *mbo, u32 size) +{ + struct most_dev *mdev = to_mdev(mbo->ifp); + + return usb_alloc_coherent(mdev->usb_device, size, GFP_KERNEL, + &mbo->bus_address); +} + +static void hdm_dma_free(struct mbo *mbo, u32 size) +{ + struct most_dev *mdev = to_mdev(mbo->ifp); + + usb_free_coherent(mdev->usb_device, size, mbo->virt_address, + mbo->bus_address); +} + /** * hdm_configure_channel - receive channel configuration from core * @iface: interface * @channel: channel ID * @conf: structure that holds the configuration information + * + * The attached network interface controller (NIC) supports a padding mode + * to avoid short packets on USB, hence increasing the performance due to a + * lower interrupt load. This mode is default for synchronous data and can + * be switched on for isochronous data. In case padding is active the + * driver needs to know the frame size of the payload in order to calculate + * the number of bytes it needs to pad when transmitting or to cut off when + * receiving data. + * */ static int hdm_configure_channel(struct most_interface *iface, int channel, struct most_channel_config *conf) { unsigned int num_frames; unsigned int frame_size; - unsigned int temp_size; - unsigned int tail_space; struct most_dev *mdev = to_mdev(iface); struct device *dev = &mdev->usb_device->dev; @@ -667,11 +687,15 @@ static int hdm_configure_channel(struct most_interface *iface, int channel, !(conf->data_type == MOST_CH_ISOC && conf->packets_per_xact != 0xFF)) { mdev->padding_active[channel] = false; + /* + * Since the NIC's padding mode is not going to be + * used, we can skip the frame size calculations and + * move directly on to exit. + */ goto exit; } mdev->padding_active[channel] = true; - temp_size = conf->buffer_size; frame_size = get_stream_frame_size(conf); if (frame_size == 0 || frame_size > USB_MTU) { @@ -679,25 +703,19 @@ static int hdm_configure_channel(struct most_interface *iface, int channel, return -EINVAL; } + num_frames = conf->buffer_size / frame_size; + if (conf->buffer_size % frame_size) { - u16 tmp_val; - - tmp_val = conf->buffer_size / frame_size; - conf->buffer_size = tmp_val * frame_size; - dev_notice(dev, - "Channel %d - rounding buffer size to %d bytes, channel config says %d bytes\n", - channel, - conf->buffer_size, - temp_size); - } + u16 old_size = conf->buffer_size; - num_frames = conf->buffer_size / frame_size; - tail_space = num_frames * (USB_MTU - frame_size); - temp_size += tail_space; + conf->buffer_size = num_frames * frame_size; + dev_warn(dev, "%s: fixed buffer size (%d -> %d)\n", + mdev->suffix[channel], old_size, conf->buffer_size); + } /* calculate extra length to comply w/ HW padding */ - conf->extra_len = (DIV_ROUND_UP(temp_size, USB_MTU) * USB_MTU) - - conf->buffer_size; + conf->extra_len = num_frames * (USB_MTU - frame_size); + exit: mdev->conf[channel] = *conf; if (conf->data_type == MOST_CH_ASYNC) { @@ -718,12 +736,19 @@ exit: * polls for the NI state of the INIC every 2 seconds. * */ -static void hdm_request_netinfo(struct most_interface *iface, int channel) +static void hdm_request_netinfo(struct most_interface *iface, int channel, + void (*on_netinfo)(struct most_interface *, + unsigned char, + unsigned char *)) { struct most_dev *mdev; BUG_ON(!iface); mdev = to_mdev(iface); + mdev->on_netinfo = on_netinfo; + if (!on_netinfo) + return; + mdev->link_stat_timer.expires = jiffies + HZ; mod_timer(&mdev->link_stat_timer, mdev->link_stat_timer.expires); } @@ -785,7 +810,8 @@ static void wq_netinfo(struct work_struct *wq_obj) hw_addr[4] = lo >> 8; hw_addr[5] = lo; - most_deliver_netinfo(&mdev->iface, link, hw_addr); + if (mdev->on_netinfo) + mdev->on_netinfo(&mdev->iface, link, hw_addr); } /** @@ -822,7 +848,7 @@ static const struct file_operations hdm_usb_fops = { /** * usb_device_id - ID table for HCD device probing */ -static struct usb_device_id usbid[] = { +static const struct usb_device_id usbid[] = { { USB_DEVICE(USB_VENDOR_ID_SMSC, USB_DEV_ID_BRDG), }, { USB_DEVICE(USB_VENDOR_ID_SMSC, USB_DEV_ID_OS81118), }, { USB_DEVICE(USB_VENDOR_ID_SMSC, USB_DEV_ID_OS81119), }, @@ -832,15 +858,15 @@ static struct usb_device_id usbid[] = { #define MOST_DCI_RO_ATTR(_name) \ struct most_dci_attribute most_dci_attr_##_name = \ - __ATTR(_name, S_IRUGO, show_value, NULL) + __ATTR(_name, 0444, show_value, NULL) #define MOST_DCI_ATTR(_name) \ struct most_dci_attribute most_dci_attr_##_name = \ - __ATTR(_name, S_IRUGO | S_IWUSR, show_value, store_value) + __ATTR(_name, 0644, show_value, store_value) #define MOST_DCI_WO_ATTR(_name) \ struct most_dci_attribute most_dci_attr_##_name = \ - __ATTR(_name, S_IWUSR, NULL, store_value) + __ATTR(_name, 0200, NULL, store_value) /** * struct most_dci_attribute - to access the attributes of a dci object @@ -1004,7 +1030,7 @@ static ssize_t store_value(struct most_dci_obj *dci_obj, err = drci_wr_reg(usb_dev, dci_obj->reg_addr, val); else if (!strcmp(name, "sync_ep")) err = start_sync_ep(usb_dev, val); - else if (!get_static_reg_addr(ro_regs, name, ®_addr)) + else if (!get_static_reg_addr(rw_regs, name, ®_addr)) err = drci_wr_reg(usb_dev, reg_addr, val); else return -EFAULT; @@ -1135,13 +1161,17 @@ hdm_probe(struct usb_interface *interface, const struct usb_device_id *id) mdev->link_stat_timer.expires = jiffies + (2 * HZ); mdev->iface.mod = hdm_usb_fops.owner; + mdev->iface.dev = &interface->dev; mdev->iface.interface = ITYPE_USB; mdev->iface.configure = hdm_configure_channel; mdev->iface.request_netinfo = hdm_request_netinfo; mdev->iface.enqueue = hdm_enqueue; mdev->iface.poison_channel = hdm_poison_channel; + mdev->iface.dma_alloc = hdm_dma_alloc; + mdev->iface.dma_free = hdm_dma_free; mdev->iface.description = mdev->description; mdev->iface.num_channels = num_endpoints; + mdev->iface.extra_attrs = XACT_ATTRS; snprintf(mdev->description, sizeof(mdev->description), "usb_device %d-%s:%d.%d", @@ -1291,25 +1321,7 @@ static struct usb_driver hdm_usb = { .disconnect = hdm_disconnect, }; -static int __init hdm_usb_init(void) -{ - pr_info("hdm_usb_init()\n"); - if (usb_register(&hdm_usb)) { - pr_err("could not register hdm_usb driver\n"); - return -EIO; - } - - return 0; -} - -static void __exit hdm_usb_exit(void) -{ - pr_info("hdm_usb_exit()\n"); - usb_deregister(&hdm_usb); -} - -module_init(hdm_usb_init); -module_exit(hdm_usb_exit); +module_usb_driver(hdm_usb); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Christian Gromm <christian.gromm@microchip.com>"); MODULE_DESCRIPTION("HDM_4_USB"); |