Re: driver migration

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Greg KH <greg@...> writes:

Dear Greg

> > I moved the initialization and clean up code from the init_callback/release
> > callback to the port_init/port_remove callback.

I am referring to your last posting on Feb 25th:
gkh> Release your port data in the port_remove callback, not the release
gkh> callback.  The release callback is for when your whole device is
gkh> removed, not the individual ports.

In addition, I initialized a spinlock  as part of setting up the data
structures in the port_init callback routine. Since then, the driver is no
longer crashing, and also the load no longer slowly builds up causing the
machine to eventually freeze.

One problem solved.

Next problem: 
When issuing a write command to the driver via echo "text" > /dev/ttyUSB0,
there is a delay of about 30 seconds until echo completes (echo is blocking
for 30 seconds). The timestamp in the syslog also show this: usbrsa_close is
started only around 30 secs (see below below @ 7346.332061) after completion
of the write completion handlers. 
The routine usbrsa_status_callback that was started first by usbrsa_open,
and is then being continuously called by itself, does not block.
(For the source code of the involved routines, please see below)


With the ancient kernel version 3.17, this was working fine.
I would not think that the 30 seconds blockng are not random but are related
to a timeout of any kind. 

1) I wonder what the kernel is doing between usbrsa_write and usbrsa_close.
it seems not to be executing code within the driver. What can cause the 30
seconds of blocking/what is the kernel waiting for?

2) I have seen other drivers calling usb_serial_port_softint from various
places. What exaclty does usb_serial_port_softint/schedule_word that is
called by usb_serial_port_softint?



Many thanks

Tilman

Syslog:
=======
...
[ 7315.882626] usbrsa_open - port=0
[ 7315.882666] usbrsa ttyUSB0: usbrsa_write_room(): Pool=640;usbrsa.tx=4084
[ 7315.882673] usbrsa ttyUSB0: usbrsa_write - port 0 START
[ 7315.882676] usbrsa_write; private struct =ffff8803ff468c00
[ 7315.882682] usbrsa ttyUSB0: usbrsa_write - port 0; bytes=10 := count=10 :
nofTxBytesFree=4084
[ 7315.882688] usbrsa ttyUSB0: usbrsa_write - poolsize  10, urb_index 0
[ 7315.882694] usbrsa ttyUSB0: usbrsa_write - port 0;URB allocated=0
[ 7315.882699] usbrsa ttyUSB0: usbrsa_write - port 0;bytes in urb=10
[ 7315.882705] usbrsa ttyUSB0: usbrsa_write - length = 10, data = 31 32 33
34 35 36 37 38 39 30
[ 7315.882711] usbrsa ttyUSB0: usbrsa_write - port 0;sent=10;count=0;
nof_bytes_to_be_sent=0;bytes=10
[ 7315.882714] usbrsa ttyUSB0: usbrsa_write() End - sent=10
[ 7315.882722] usbrsa ttyUSB0: usbrsa_write_room(): Pool=576;usbrsa.tx=4084
[ 7315.882726] usbrsa ttyUSB0: usbrsa_write - port 0 START
[ 7315.882729] usbrsa_write; private struct =ffff8803ff468c00
[ 7315.882734] usbrsa ttyUSB0: usbrsa_write - port 0; bytes=2 := count=2 :
nofTxBytesFree=4084
[ 7315.882738] usbrsa ttyUSB0: usbrsa_write - poolsize  10, urb_index 1
[ 7315.882742] usbrsa ttyUSB0: usbrsa_write - port 0;URB allocated=1
[ 7315.882745] usbrsa ttyUSB0: usbrsa_write - port 0;bytes in urb=2
[ 7315.882748] usbrsa ttyUSB0: usbrsa_write - length = 2, data = 0d 0a
[ 7315.882753] usbrsa ttyUSB0: usbrsa_write - port 0;sent=2;count=0;
nof_bytes_to_be_sent=0;bytes=2
[ 7315.882756] usbrsa ttyUSB0: usbrsa_write() End - sent=2
[ 7315.882769] usbrsa ttyUSB0: usbrsa_write_callback() - port = 0, ep
=0xc0018380
[ 7315.882776] usbrsa ttyUSB0: usbrsa_write_callback - length = 10, data =
31 32 33 34 35 36 37 38 39 30
[ 7315.882781] usbrsa ttyUSB0: usbrsa_write_callback(): Returned URB 0
[ 7315.882918] usbrsa ttyUSB0: usbrsa_write_callback() - port = 0, ep
=0xc0018380
[ 7315.882927] usbrsa ttyUSB0: usbrsa_write_callback - length = 2, data = 0d 0a
[ 7315.882932] usbrsa ttyUSB0: usbrsa_write_callback(): Returned URB 1
[ 7315.882938] usbrsa_status_callback: nofTxBytesFree=4074,nofRxBytesReceived=0 
[ 7315.883002] usbrsa_status_callback: nofTxBytesFree=4072,nofRxBytesReceived=0 
[ 7346.332061] usbrsa_close - start
[ 7346.332070] usbrsa ttyUSB0: usbrsa_close - port 0 start
[ 7346.332076] usbrsa ttyUSB0: send_baudrate_lcr_register() CFLAG=3261 
[ 7346.332080] usbrsa ttyUSB0: send_baudrate_lcr_register()
ST16C550.DLL=50;ST16C550.DLM=0;ST16C550.LCR=3
[ 7346.332130] usbrsa ttyUSB0: usbrsa_baudrate_lcr_callback() - port = 0,
ep=0xc0028300
[ 7346.332142] usbrsa ttyUSB0: send_baudrate_lcr_register() leaving
[ 7346.332146] usbrsa ttyUSB0: usbrsa_close - #retries=3
[ 7346.332148] usbrsa_close - end
[ 7346.332151] usbrsa ttyUSB0: usbrsa_close - end 
[ 7346.332163] usbrsa ttyUSB0: usbrsa_status_callback(): wake_up


Source code Excerpt:
=====================

static struct usb_serial_driver usbrsa_enumerated_device = 
{
        .driver = {
                .owner =        THIS_MODULE,
                .name =         "usbrsa",
        }, 
        .description =          "IO-DATA - USB-RSA",
        .id_table =             id_table_std,
        .num_ports =            1,
        .attach =               usbrsa_attach,
        .release =				usbrsa_release,
		.port_probe =		    usbrsa_probe,
		.port_remove =	 		usbrsa_remove,
        .open =					usbrsa_open,
        .close = 				usbrsa_close,
        .write =				usbrsa_write,
        .write_bulk_callback =  usbrsa_write_callback,
        .read_bulk_callback =	usbrsa_read_callback,
        .set_termios =          usbrsa_set_termios,
        .tiocmset = 			usbrsa_tiocmset,
        .tiocmget = 			usbrsa_tiocmget,
        .init_termios =			usbrsa_init_termios,
        .ioctl =				usbrsa_ioctl,
        .write_room = 			usbrsa_write_room,
        .chars_in_buffer = 		usbrsa_chars_in_buffer,
        .throttle =				usbrsa_throttle,
        .unthrottle =			usbrsa_unthrottle
};


static int  usbrsa_open(struct tty_struct *tty,
                        struct usb_serial_port *port)
{
	struct ktermios 			tmp_termios;
	int 						retval = 0;
	struct usbrsa_port_private*	priv = usb_get_serial_port_data(port);
	unsigned long				flags;
	
	printk("%s; priv=%p\n",__func__,priv);
	dev_dbg(&port->dev,"%s - port %d", __func__,port->port_number);

	
	// flush buffer of USB-RSA by sending reset 
	//retval = send_reset(port);

	if (retval != 0)
	{
		dev_err(&port->dev, "%s(): usb_submit_urb() failed"
				" with error %d\n", __func__, retval);
		return ENODEV;
	}

	
	 if (tty)
	 {
		 // usbrsa_set_termios will sent to endpoint 2 of the USB-RSA thereby 
		 // turning on the RX interrupt 
		 usbrsa_set_termios(tty, port, &tmp_termios);
	 }
	 

	 // start reading from USB-RSA
	 spin_lock_irqsave(&priv->lock, flags);
	 if (!(test_bit(LOCK_STATUS,&priv->urb_lock)))
	 {
		 set_bit(LOCK_STATUS,&priv->urb_lock);
		 // enable continuous reading
		 priv->read_running = USBRSA_READ_RUNNING;
		 spin_unlock_irqrestore(&priv->lock, flags);
		 retval = usb_submit_urb(priv->status_urb,GFP_KERNEL);
	 }
	 else
	 {
		 spin_unlock_irqrestore(&priv->lock, flags);
	 }

	 dev_dbg(&port->dev,"%s - port %d: leaving", __func__, port->port_number);
	 printk("%s - port=%d",__func__,port->port_number);
	 return 0;
}


tatic void usbrsa_close(struct usb_serial_port *port)
{
	struct usbrsa_port_private*	priv = usb_get_serial_port_data(port);
	int 						retries = 3;
	unsigned long 				flags;
	int							retval;


	printk("%s - start",__func__);
	dev_dbg(&port->dev,"%s - port %d start", __func__, port->port_number);

	// turn off  RX interrupt of USB-RSA by sending to EP5)
	while(retries > 0)
	{
		// turn off RX interrupt of USB-RSA by sending to EP5.
		 retval = send_baudrate_lcr_register(priv->c_flag, priv->baudrate,
					 EP5OUT, port);
		 
		 if (retval != 0)
		 {
			 dev_err(&port->dev, "%s(): usb_submit_urb() failed"
					 " with error %d\n", __func__, retval);
			
		 }
		 else 
		 {
			 dev_dbg(&port->dev,"%s - #retries=%d", __func__,retries);
			 break;
		 }
		 retries--;
	}
	
	// disable continuous reading
	spin_lock_irqsave(&priv->lock, flags);
	priv->read_running = USBRSA_READ_STOP;
	spin_unlock_irqrestore(&priv->lock, flags);
	
	printk("%s - end",__func__);
	dev_dbg(&port->dev,"%s - end ", __func__);

	return;
}




static int  usbrsa_write(struct tty_struct *tty,
                        struct usb_serial_port *port,
                        const unsigned char *buf, int count)
{
	struct usb_serial*			serial = port->serial;
	struct usbrsa_port_private*	priv = usb_get_serial_port_data(port);
	unsigned long				flags;
	int 						retval;
	int							nof_bytes_to_be_sent;
	int 						bytes;   
	int							urb_index;
	int							sent = 0;
	struct urb*					urb;
	
	dev_dbg(&port->dev,"%s - port %d START", __func__,port->port_number);
	printk("%s; private struct =%p\n",__func__,priv);
	

	while (count > 0)
	{
		// transfer only as many bytes as USB-RSA can take
		nof_bytes_to_be_sent = (count > priv->nofTxBytesFree) ? 
				priv->nofTxBytesFree : count;
		dev_dbg(&port->dev,"%s - port %d; bytes=%d := count=%d : nofTxBytesFree=%d",
				__func__, port->port_number,
				nof_bytes_to_be_sent,count,
				priv->nofTxBytesFree);
		
		while (nof_bytes_to_be_sent > 0)
		{
			// check for empty urb in write pool
			spin_lock_irqsave(&priv->lock, flags);
			urb_index = 
					find_first_zero_bit(&priv->write_urb_pool_lock,
							priv->urb_pool_size);

			dev_dbg(&port->dev,"%s - poolsize  %d, urb_index %d\n",__func__,
priv->urb_pool_size,urb_index);
			if (urb_index >= priv->urb_pool_size)
			{
				// no more urbs available
				spin_unlock_irqrestore(&priv->lock, flags);
				goto out_write_no_urbs;
			}

			dev_dbg(&port->dev,"%s - port %d;URB allocated=%d",__func__,
port->port_number,urb_index);
			// reserve urb
			set_bit(urb_index, &priv->write_urb_pool_lock);
			urb = priv->write_urb_pool[urb_index];

			spin_unlock_irqrestore(&priv->lock, flags);

			// copy data from userspace into urb transfer buffer
			bytes = (nof_bytes_to_be_sent > port->bulk_out_size) ?
					port->bulk_out_size : nof_bytes_to_be_sent;
			memcpy(urb->transfer_buffer, buf + sent, bytes);

			dev_dbg(&port->dev,"%s - port %d;bytes in urb=%d",__func__,
port->port_number, bytes);
			usb_serial_debug_data( &port->dev,
					__func__, bytes, urb->transfer_buffer);
			urb->dev = serial->dev;
			urb->transfer_buffer_length = bytes;

			// sent urb to USB-RSA
			retval = usb_submit_urb(urb, GFP_ATOMIC);

			if (retval) 
			{
				// return urb to pool
				spin_lock_irqsave(&priv->lock, flags);
				clear_bit(urb_index, &priv->write_urb_pool_lock);
				spin_unlock_irqrestore(&priv->lock, flags);
				dev_err(&port->dev,
						"%s - failed submitting write urb, error %d\n",
						__func__, retval);
				sent = retval;

				// bail out
				goto out_write_submit_failed;
			} 
			else 
			{
				sent += bytes;
				count -= bytes;
				nof_bytes_to_be_sent -= bytes;
				dev_dbg(&port->dev,"%s - port %d;sent=%d;count=%d;
nof_bytes_to_be_sent=%d;bytes=%d",
						__func__, port->port_number, sent,count, nof_bytes_to_be_sent,
						bytes);
			} 
		}
	}
	out_write_no_urbs:
	out_write_submit_failed:
	dev_dbg(&port->dev,"%s() End - sent=%d\n",__func__,sent);
	usb_serial_port_softint(port);
	return sent;
}



static void  usbrsa_write_callback(struct urb *urb)
{
	struct usb_serial_port* 	port 	= urb->context;
	struct usbrsa_port_private*	priv 	= usb_get_serial_port_data(port);
	int 						status	= urb->status;
	unsigned long				flags;
	int							urb_index;
	
	dev_dbg(&port->dev,"%s() - port = %d, ep =0x%x", __func__, port->port_number,
				priv->status_urb->pipe);
	
	usb_serial_debug_data( &port->dev, __func__,
				urb->actual_length, urb->transfer_buffer);
	// find urb in write pool
	for (urb_index=0; urb_index < priv->urb_pool_size;urb_index++)
	{
		if (urb == priv->write_urb_pool[urb_index])
		{
			// urb found; return urb to pool
			spin_lock_irqsave(&priv->lock, flags);
			clear_bit(urb_index, &priv->write_urb_pool_lock);
			spin_unlock_irqrestore(&priv->lock, flags);
			break;
		}
	}
	
	if (urb != priv->write_urb_pool[urb_index])
	{
		// urb not found -- this points to a bug
		dev_err(&port->dev, "%s(): urb not in pool",
				__func__);
	}
	dev_dbg(&port->dev,"%s(): Returned URB %d",__func__, urb_index);
	if (status)
	{
		dev_dbg(&port->dev,"%s(): nonzero urb status: 0x%d", __func__, status);
	}
	usb_serial_port_softint(port);
}



static void  usbrsa_status_callback(struct urb *urb)
{
	struct usb_serial_port* 	port 	= urb->context;
	struct usbrsa_port_private*	priv 	= usb_get_serial_port_data(port);
	int 						status	= urb->status;
	__u8*						ep3in   = urb->transfer_buffer;
	unsigned long				flags;
	int							retval;
	int 						read_urbs_needed = 0;
	int							urb_index;
	unsigned int				i;

//	dev_dbg(&port->dev,"%s() - port = %d, ep =0x%x", __func__, port->port_number,
//			priv->status_urb->pipe);

	
	spin_lock_irqsave(&priv->lock, flags);
	// read payload data of urb, i.e. bytes received and bytes 
	// available in tx queue of USB-RSA
	priv->nofTxBytesFree	= ep3in[0] + (256 * ep3in[1]);
	priv->nofRxBytesReceived= ep3in[2] + (256 * ep3in[3]);
	// unlock urb
	clear_bit(LOCK_STATUS,&priv->urb_lock);
	spin_unlock_irqrestore(&priv->lock, flags);
	if ((priv->DebugNofTxBytesFree != priv->nofTxBytesFree) ||
			(priv->DebugRxBytesReceived != 	priv->nofRxBytesReceived))
	{
		printk("%s: nofTxBytesFree=%d,nofRxBytesReceived=%d \n", 
				__func__, priv->nofTxBytesFree, priv->nofRxBytesReceived);
	}
	priv->DebugNofTxBytesFree =  priv->nofTxBytesFree;
	priv->DebugRxBytesReceived = priv->nofRxBytesReceived;

	// if coutinuous read enabled, either
	// -- issue next status request (USBRSA did not receive 
	//    anything)
	// -- issue a read urb (if rx queue is filled)
	if (priv->read_running == USBRSA_READ_RUNNING)
	{
		if(priv->nofRxBytesReceived != 0)
		{
			// USB-RSA received data 	

			// compute urbs needed
			read_urbs_needed  = priv->nofRxBytesReceived/port->bulk_in_size;
			if (priv->nofRxBytesReceived%port->bulk_in_size)
				read_urbs_needed++;
			dev_dbg(&port->dev,"%s(): EP1IN: rx=%d, urbs_needed=%d,size_of_urb=%d",
					__func__,
					priv->nofRxBytesReceived,
					read_urbs_needed,
					port->bulk_in_size);


			// issue read urbs
			// todo: issue more than one read urb. Will this work ?
			if (read_urbs_needed > priv->urb_pool_size)
				read_urbs_needed = priv->urb_pool_size;
			for(i=0; i < read_urbs_needed;i++ )
			{
				spin_lock_irqsave(&priv->lock, flags);
				urb_index = find_first_zero_bit(&priv->read_urb_pool_lock,
						priv->urb_pool_size);
				if (urb_index < priv->urb_pool_size)
				{
					set_bit(urb_index,&priv->read_urb_pool_lock);
					spin_unlock_irqrestore(&priv->lock, flags);

					// submit read
					dev_dbg(&port->dev,"%s(): submit read urb[%d]", __func__,urb_index );
					retval = usb_submit_urb(
							priv->read_urb_pool[urb_index],GFP_KERNEL);
					if (retval)
					{
						// return urb to read pool
						spin_lock_irqsave(&priv->lock, flags);
						clear_bit(urb_index,&priv->read_urb_pool_lock);
						spin_unlock_irqrestore(&priv->lock, flags);
						dev_dbg(&port->dev,"%s(): nonzero urb status: 0x%d", __func__, status);
						return;
					}
				}
				else
				{
					spin_unlock_irqrestore(&priv->lock, flags);
					i = read_urbs_needed;
				}
			}
		}
		spin_lock_irqsave(&priv->lock, flags);
		set_bit(LOCK_STATUS,&priv->urb_lock);
		spin_unlock_irqrestore(&priv->lock, flags);
		retval = usb_submit_urb(priv->status_urb,GFP_KERNEL);
		if (retval != 0)
		{
			dev_err(&port->dev, "%s(): usb_submit_urb() failed"
					" with error %d\n", __func__, retval);
			spin_lock_irqsave(&priv->lock, flags);
			clear_bit(LOCK_STATUS,&priv->urb_lock);
			spin_unlock_irqrestore(&priv->lock, flags);
		}
	}
	else
	{
		// reading from device ceased -- do nothing
		//dev_dbg(&port->dev,"%s(): reading stopped: tx_free=%d;rx_recv=%d",
		//		__func__, priv->nofTxBytesFree,priv->nofRxBytesReceived);
	}
	if (status)
	{
		dev_dbg(&port->dev,"%s(): nonzero urb status: 0x%d", __func__, status);
		
	}
	if (priv->read_running == USBRSA_READ_RUNNING)
	{
		//dev_dbg(&port->dev,"%s(): usb_serial_port_softint", __func__);
		usb_serial_port_softint(port);
	}
	else
	{
		dev_dbg(&port->dev,"%s(): wake_up", __func__);
		wake_up(&priv->wait_flag);	
	}
	return;
}







--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux