diff mbox series

[03/12] USB: serial: keyspan_pda: Consolidate room query

Message ID 20201014145727.338773481@linutronix.de
State New
Headers show
Series UBS: Cleanup in_interupt/in_irq/in_atomic() usage | expand

Commit Message

Thomas Gleixner Oct. 14, 2020, 2:52 p.m. UTC
From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>

Having two copies of the same code doesn't make the code more readable and
allocating a buffer of 1 byte for a synchronous operation is a pointless
exercise.

Add a byte buffer to struct keyspan_pda_private which can be used
instead. The buffer is only used in open() and tty->write(). Console writes
are not calling into the query. open() obviously happens before write() and
the writes are serialized by bit 0 of port->write_urbs_free which protects
also the transaction itself.

Move the actual query into a helper function and cleanup the usage sites in
keyspan_pda_write() and keyspan_pda_open().

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Johan Hovold <johan@kernel.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: linux-usb@vger.kernel.org
---
 drivers/usb/serial/keyspan_pda.c |  102 ++++++++++++++++-----------------------
 1 file changed, 43 insertions(+), 59 deletions(-)

Comments

Alan Stern Oct. 14, 2020, 4:14 p.m. UTC | #1
On Wed, Oct 14, 2020 at 04:52:18PM +0200, Thomas Gleixner wrote:
> From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> 
> Having two copies of the same code doesn't make the code more readable and
> allocating a buffer of 1 byte for a synchronous operation is a pointless
> exercise.

Not so.  In fact, it is required, because a portion of a structure 
cannot be mapped for DMA unless it is aligned at a cache line boundary.

> Add a byte buffer to struct keyspan_pda_private which can be used
> instead. The buffer is only used in open() and tty->write().

This won't work.

>  Console writes
> are not calling into the query. open() obviously happens before write() and
> the writes are serialized by bit 0 of port->write_urbs_free which protects
> also the transaction itself.
> 
> Move the actual query into a helper function and cleanup the usage sites in
> keyspan_pda_write() and keyspan_pda_open().
> 
> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> Cc: Johan Hovold <johan@kernel.org>
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Cc: linux-usb@vger.kernel.org
> ---
>  drivers/usb/serial/keyspan_pda.c |  102 ++++++++++++++++-----------------------
>  1 file changed, 43 insertions(+), 59 deletions(-)
> 
> --- a/drivers/usb/serial/keyspan_pda.c
> +++ b/drivers/usb/serial/keyspan_pda.c
> @@ -47,6 +47,7 @@ struct keyspan_pda_private {
>  	struct work_struct			unthrottle_work;
>  	struct usb_serial	*serial;
>  	struct usb_serial_port	*port;
> +	u8			query_buf;
>  };
>  
>  
> @@ -436,6 +437,31 @@ static int keyspan_pda_tiocmset(struct t
>  	return rc;
>  }
>  
> +/*
> + * Using priv->query_buf is safe here because this is only called for TTY
> + * operations open() and write(). write() comes post open() obviously and
> + * write() itself is serialized via bit 0 of port->write_urbs_free. Console
> + * writes are never calling into this.
> + */
> +static int keyspan_pda_query_room(struct usb_serial *serial,
> +				  struct keyspan_pda_private *priv)
> +{
> +	int res;
> +
> +	res = 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, /* index */
> +			      &priv->query_buf,
> +			      1,
> +			      2000);

Instead, consider using the new usb_control_msg_recv() API.  But it 
might be better to allocate the buffer once and for all.

Alan Stern
Sebastian Andrzej Siewior Oct. 14, 2020, 4:27 p.m. UTC | #2
On 2020-10-14 12:14:33 [-0400], Alan Stern wrote:
> Instead, consider using the new usb_control_msg_recv() API.  But it 

> might be better to allocate the buffer once and for all.


This will still allocate and free buffer on each invocation. What about
moving the query_buf to the begin of the struct / align it?

> Alan Stern


Sebastian
diff mbox series

Patch

--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -47,6 +47,7 @@  struct keyspan_pda_private {
 	struct work_struct			unthrottle_work;
 	struct usb_serial	*serial;
 	struct usb_serial_port	*port;
+	u8			query_buf;
 };
 
 
@@ -436,6 +437,31 @@  static int keyspan_pda_tiocmset(struct t
 	return rc;
 }
 
+/*
+ * Using priv->query_buf is safe here because this is only called for TTY
+ * operations open() and write(). write() comes post open() obviously and
+ * write() itself is serialized via bit 0 of port->write_urbs_free. Console
+ * writes are never calling into this.
+ */
+static int keyspan_pda_query_room(struct usb_serial *serial,
+				  struct keyspan_pda_private *priv)
+{
+	int res;
+
+	res = 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, /* index */
+			      &priv->query_buf,
+			      1,
+			      2000);
+	if (res != 1)
+		return res < 0 ? res : -EIO;
+
+	return (unsigned int)priv->query_buf;
+}
+
 static int keyspan_pda_write(struct tty_struct *tty,
 	struct usb_serial_port *port, const unsigned char *buf, int count)
 {
@@ -483,39 +509,16 @@  static int keyspan_pda_write(struct tty_
 	 * usage because the console write can't sleep.
 	 */
 	if (count > priv->tx_room && tty) {
-		u8 *room;
-
-		room = kmalloc(1, GFP_KERNEL);
-		if (!room) {
-			rc = -ENOMEM;
-			goto exit;
-		}
-
-		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 > 0) {
-			dev_dbg(&port->dev, "roomquery says %d\n", *room);
-			priv->tx_room = *room;
-		}
-		kfree(room);
+		rc = keyspan_pda_query_room(serial, priv);
 		if (rc < 0) {
-			dev_dbg(&port->dev, "roomquery failed\n");
-			goto exit;
-		}
-		if (rc == 0) {
-			dev_dbg(&port->dev, "roomquery returned 0 bytes\n");
-			rc = -EIO; /* device didn't return any data */
+			dev_dbg(&port->dev, "roomquery failed %d\n", rc);
 			goto exit;
 		}
+
+		dev_dbg(&port->dev, "roomquery says %d\n", rc);
+		priv->tx_room = rc;
 	}
+
 	if (count > priv->tx_room) {
 		/* we're about to completely fill the Tx buffer, so
 		   we'll be throttled afterwards. */
@@ -615,45 +618,26 @@  static int keyspan_pda_open(struct tty_s
 					struct usb_serial_port *port)
 {
 	struct usb_serial *serial = port->serial;
-	u8 *room;
-	int rc = 0;
 	struct keyspan_pda_private *priv;
+	int rc;
 
-	/* find out how much room is in the Tx ring */
-	room = kmalloc(1, GFP_KERNEL);
-	if (!room)
-		return -ENOMEM;
+	priv = usb_get_serial_port_data(port);
 
-	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, /* index */
-			     room,
-			     1,
-			     2000);
+	/* find out how much room is in the Tx ring */
+	rc = keyspan_pda_query_room(serial, priv);
 	if (rc < 0) {
-		dev_dbg(&port->dev, "%s - roomquery failed\n", __func__);
-		goto error;
-	}
-	if (rc == 0) {
-		dev_dbg(&port->dev, "%s - roomquery returned 0 bytes\n", __func__);
-		rc = -EIO;
-		goto error;
+		dev_dbg(&port->dev, "roomquery failed %d\n", rc);
+		return rc;
 	}
-	priv = usb_get_serial_port_data(port);
-	priv->tx_room = *room;
-	priv->tx_throttled = *room ? 0 : 1;
+
+	priv->tx_room = rc;
+	priv->tx_throttled = rc ? 0 : 1;
 
 	/*Start reading from the device*/
 	rc = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
-	if (rc) {
+	if (rc)
 		dev_dbg(&port->dev, "%s - usb_submit_urb(read int) failed\n", __func__);
-		goto error;
-	}
-error:
-	kfree(room);
+
 	return rc;
 }
 static void keyspan_pda_close(struct usb_serial_port *port)