Message ID | 20210801203122.3515-1-himadrispandya@gmail.com |
---|---|
Headers | show |
Series | USB: serial: use wrappers for usb_control_msg() | expand |
On Mon, Aug 02, 2021 at 02:01:16AM +0530, Himadri Pandya wrote: > There are many usages of usb_control_msg() that can use the new wrapper > functions usb_contro_msg_send() & usb_control_msg_recv() for better > error checks on short reads and writes. As I said before, there no need to worry about short writes as that will always return an error. So this description (and some of the commit messages) needs a bit of work. > They can also be used to avoid > allocating redundant dma buffers that are generally required to use > usb_control_msg(). The DMA buffers are anything but redundant; they are required. But the wrappers can be used to not have to manage the dma buffers explicitly. > Hence use them whenever possible and avoid using > usb_control_msg() directly. > > Changes in v2: > - Drop unnecessary use of wrappers > - Drop unrelated style changes > > Additional Info: > - This is a super late follow-up on v1 that was submitted a while > ago(my sincere apologies). (All patches are rebased and > compile tested.) > - v1 patches: https://lkml.org/lkml/2020/11/4/40 > - Patches that introduced the wrapper functions: > https://lkml.org/lkml/2020/9/14/859 No worries, I'll go review the patches now. Johan
On Mon, Aug 02, 2021 at 02:01:17AM +0530, Himadri Pandya wrote: > usb_control_msg_send/recv are new wrapper functions for usb_control_msg() > that have proper error checks for short read/writes. There no need for any special handling of short writes. Testing against against negative errno is all that's needed. > These functions > can also accept data buffer on stack. Hence use these functions to have > more robust error checks, and to reduce kernel memory usage for usb > messages. I'd rephrase this along the lines of "to simplify error handling for short reads". Also, you're not reducing kernel memory usage, you're just moving the allocation to be handled by the wrapper instead. > Signed-off-by: Himadri Pandya <himadrispandya@gmail.com> > --- > Changes in v2: > - Fix callers of ch341_control_out() and ch341_control_in() > - Remove label "out" > - Remove an unnecessary assignment statement > --- > drivers/usb/serial/ch341.c | 97 ++++++++++++-------------------------- > 1 file changed, 29 insertions(+), 68 deletions(-) > > diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c > index 2db917eab799..c6f7ff9ca8ae 100644 > --- a/drivers/usb/serial/ch341.c > +++ b/drivers/usb/serial/ch341.c > @@ -113,10 +113,10 @@ static int ch341_control_out(struct usb_device *dev, u8 request, > dev_dbg(&dev->dev, "%s - (%02x,%04x,%04x)\n", __func__, > request, value, index); > > - r = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request, > - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, > - value, index, NULL, 0, DEFAULT_TIMEOUT); > - if (r < 0) > + r = usb_control_msg_send(dev, 0, request, > + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, > + value, index, NULL, 0, DEFAULT_TIMEOUT, GFP_KERNEL); > + if (r) > dev_err(&dev->dev, "failed to send control message: %d\n", r); > > return r; Since ch341_control_out() does not take a data buffer argument, there's no need to use the new helper which only adds an extra function call. Note that this function already return 0 on success or a negative errno on errors. > @@ -131,23 +131,13 @@ static int ch341_control_in(struct usb_device *dev, > dev_dbg(&dev->dev, "%s - (%02x,%04x,%04x,%u)\n", __func__, > request, value, index, bufsize); > > - r = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), request, > - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, > - value, index, buf, bufsize, DEFAULT_TIMEOUT); > - if (r < (int)bufsize) { > - if (r >= 0) { > - dev_err(&dev->dev, > - "short control message received (%d < %u)\n", > - r, bufsize); You're also removing this error message. It should at least be mentioned somewhere that short reads will now simply be reported as -EREMOTEIO with no indication of how short the transfer was. That's usually just fine, but I'm currently dealing with another driver where a short read can be used to differentiate between device types as an example. > - r = -EIO; > - } > - > - dev_err(&dev->dev, "failed to receive control message: %d\n", > - r); > - return r; > - } > + r = usb_control_msg_recv(dev, 0, request, > + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, > + value, index, buf, bufsize, DEFAULT_TIMEOUT, GFP_KERNEL); > + if (r) > + dev_err(&dev->dev, "failed to receive control message: %d\n", r); > > - return 0; > + return r; > } > > #define CH341_CLKRATE 48000000 > @@ -287,23 +277,19 @@ static int ch341_set_handshake(struct usb_device *dev, u8 control) > static int ch341_get_status(struct usb_device *dev, struct ch341_private *priv) > { > const unsigned int size = 2; > - char *buffer; > + u8 buffer[2]; > int r; > unsigned long flags; > > - buffer = kmalloc(size, GFP_KERNEL); > - if (!buffer) > - return -ENOMEM; > - > r = ch341_control_in(dev, CH341_REQ_READ_REG, 0x0706, 0, buffer, size); > - if (r < 0) > + if (r) > goto out; > > spin_lock_irqsave(&priv->lock, flags); > priv->msr = (~(*buffer)) & CH341_BITS_MODEM_STAT; > spin_unlock_irqrestore(&priv->lock, flags); > > -out: kfree(buffer); > +out: > return r; Just return r in the error path above and drop the label. > } > > @@ -312,21 +298,17 @@ out: kfree(buffer); > static int ch341_configure(struct usb_device *dev, struct ch341_private *priv) > { > const unsigned int size = 2; > - char *buffer; > + u8 buffer[2]; > int r; > > - buffer = kmalloc(size, GFP_KERNEL); > - if (!buffer) > - return -ENOMEM; > - > /* expect two bytes 0x27 0x00 */ > r = ch341_control_in(dev, CH341_REQ_READ_VERSION, 0, 0, buffer, size); > - if (r < 0) > + if (r) > goto out; > dev_dbg(&dev->dev, "Chip version: 0x%02x\n", buffer[0]); > > r = ch341_control_out(dev, CH341_REQ_SERIAL_INIT, 0, 0); > - if (r < 0) > + if (r) > goto out; > > r = ch341_set_baudrate_lcr(dev, priv, priv->baud_rate, priv->lcr); > @@ -335,7 +317,7 @@ static int ch341_configure(struct usb_device *dev, struct ch341_private *priv) > > r = ch341_set_handshake(dev, priv->mcr); > > -out: kfree(buffer); > +out: > return r; > } Same here (even if you need to touch the other error paths). > @@ -647,23 +613,19 @@ static void ch341_break_ctl(struct tty_struct *tty, int break_state) > struct ch341_private *priv = usb_get_serial_port_data(port); > int r; > uint16_t reg_contents; > - uint8_t *break_reg; > + uint8_t break_reg[2]; > > if (priv->quirks & CH341_QUIRK_SIMULATE_BREAK) { > ch341_simulate_break(tty, break_state); > return; > } > > - break_reg = kmalloc(2, GFP_KERNEL); > - if (!break_reg) > - return; > - > - r = ch341_control_in(port->serial->dev, CH341_REQ_READ_REG, > - ch341_break_reg, 0, break_reg, 2); > - if (r < 0) { > + r = ch341_control_in(port->serial->dev, CH341_REQ_READ_REG, ch341_break_reg, 0, > + break_reg, 2); Drop this unrelated style change (which creates a line > 80 chars too). > + if (r) { > dev_err(&port->dev, "%s - USB control read error (%d)\n", > __func__, r); > - goto out; > + return; > } > dev_dbg(&port->dev, "%s - initial ch341 break register contents - reg1: %x, reg2: %x\n", > __func__, break_reg[0], break_reg[1]); > @@ -681,11 +643,10 @@ static void ch341_break_ctl(struct tty_struct *tty, int break_state) > reg_contents = get_unaligned_le16(break_reg); > r = ch341_control_out(port->serial->dev, CH341_REQ_WRITE_REG, > ch341_break_reg, reg_contents); > - if (r < 0) > + if (r) > dev_err(&port->dev, "%s - USB control write error (%d)\n", > __func__, r); > -out: > - kfree(break_reg); > + return; No need for return at the end of a void function. > } > > static int ch341_tiocmset(struct tty_struct *tty, Johan
On Mon, Aug 02, 2021 at 02:01:19AM +0530, Himadri Pandya wrote: > New wrapper functions usb_control_msg_send/recv accept stack variables > for usb message buffer and eliminate the need of creating temporary dma > buffers. The wrappers also have proper error checks for short > read/writes. Hence use the wrappers instead of using usb_control_msg() > directly. > > Signed-off-by: Himadri Pandya <himadrispandya@gmail.com> I amended the commit message as follows when applying this one: USB: serial: f81232: use usb_control_msg_recv() and usb_control_msg_send() The new wrapper functions usb_control_msg_send/recv accept stack variables for USB message buffers and eliminate the need of manually allocating temporary DMA buffers. The read wrapper also treats short reads as errors. Hence use the wrappers instead of using usb_control_msg() directly. Note that the conversion of f81534a_ctrl_set_register() adds an extra an extra allocation and memcpy for every retry. Since this function is called rarely and retries are hopefully rare, the overhead should be acceptable. Also note that short reads are now logged as -EREMOTEIO instead of indicating the amount of data read. Johan
On Mon, Aug 02, 2021 at 02:01:21AM +0530, Himadri Pandya wrote: > Use the wrapper function usb_control_msg_recv() that accepts stack > variables and remove dma buffers from callers of usb_control_msg(). > > Signed-off-by: Himadri Pandya <himadrispandya@gmail.com> > --- > Changes in v2: > - Rebase the patch on top of recent changes > - Drop unrelated style changes > --- > drivers/usb/serial/keyspan_pda.c | 70 ++++++++++++++------------------ > 1 file changed, 31 insertions(+), 39 deletions(-) > > diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c > index 39b0f5f344c2..831dc5f42dea 100644 > --- a/drivers/usb/serial/keyspan_pda.c > +++ b/drivers/usb/serial/keyspan_pda.c > @@ -77,35 +77,28 @@ static int keyspan_pda_get_write_room(struct keyspan_pda_private *priv) > { > struct usb_serial_port *port = priv->port; > struct usb_serial *serial = port->serial; > - u8 *room; > + u8 room; > int rc; > > - room = kmalloc(1, GFP_KERNEL); > - if (!room) > - return -ENOMEM; > - > - rc = usb_control_msg(serial->dev, > - usb_rcvctrlpipe(serial->dev, 0), > - 6, /* write_room */ > - USB_TYPE_VENDOR | USB_RECIP_INTERFACE > - | USB_DIR_IN, > - 0, /* value: 0 means "remaining room" */ > - 0, /* index */ > - room, > - 1, > - 2000); > - if (rc != 1) { > - if (rc >= 0) > - rc = -EIO; > + rc = usb_control_msg_recv(serial->dev, > + 0, > + 6, /* write_room */ > + USB_TYPE_VENDOR | USB_RECIP_INTERFACE > + | USB_DIR_IN, > + 0, /* value: 0 means "remaining room" */ > + 0, /* index */ > + &room, > + 1, > + 2000, > + GFP_KERNEL); > + if (rc) { > dev_dbg(&port->dev, "roomquery failed: %d\n", rc); > - goto out_free; > + goto out; > } > > - dev_dbg(&port->dev, "roomquery says %d\n", *room); > - rc = *room; > -out_free: > - kfree(room); > - > + dev_dbg(&port->dev, "roomquery says %d\n", room); > + rc = room; > +out: I changed this to just return rc in the error path above directly instead. > return rc; > } Now applied, thanks. Johan