Wednesday, 29 April 2015

WorkQueue mechanism in Linux

1.Work Queue

The Linux Workqueue mechanism is to simplify the creation of kernel threads. By calling workqueue interface you can create kernel threads. And it may be based on the current number of system CPU to create the number of threads so that the transaction can be parallelized thread. work queue is the kernel simple and effective mechanism, he apparently simplifies the creation of the kernel daemon facilitate the programming of the user.

Work Queue (work queue) is in the form of work after another push executed after the work queue can push the work, referred to a kernel thread to perform, that is, the lower half can be executed in the process context. The most important thing is the work queue is allowed to reschedule or even sleep.


2.Data Structure
We pushed back the implementation of the task called work , describing its data structure work_struct,

struct work_struct {
    atomic_long_t data;      / * Work handler func parameter * /
#define WORK_STRUCT_PENDING 0        /* T if work item pending execution */
#define WORK_STRUCT_STATIC 1        /* static initializer (debugobjects) */
#define WORK_STRUCT_FLAG_MASK (3UL)
#define WORK_STRUCT_WQ_DATA_MASK (~WORK_STRUCT_FLAG_MASK)
    struct list_head entry;        /*Connection work pointer*/
    work_func_t func;              /*work handler*/
#ifdef CONFIG_LOCKDEP
    struct lockdep_map lockdep_map;
#endif
};

The work queue structure to organize a work queue (workqueue), its data structure

struct workqueue_struct {
 struct cpu_workqueue_struct *cpu_wq;
 struct list_head list;
 const char *name;   /*workqueue name*/
 int singlethread;   / * Is not a single thread - threaded our preferred first CPU -0 indicates the default worker thread event*/
 int freezeable;  /* Freeze threads during suspend */
 int rt;
}; 

If it is multi-threaded, Linux CPU number of the current system to create its structure is based on cpu_workqueue_struct,
struct cpu_workqueue_struct {
 spinlock_t lock;
 struct list_head worklist;
 wait_queue_head_t more_work;
 struct work_struct *current_work; 
 struct workqueue_struct *wq;  
 struct task_struct *thread; 
} ____cacheline_aligned;



In the structure of the main maintains a job queue, and kernel threads need to sleep waiting queue, and also maintains a task context, the task_struct.
The relationship between the three is as follows:

Creating work
3.1 Creating job queue
a. create_singlethread_workqueue (name)
Implementation mechanism of the function shown below, the function returns a pointer to a variable of type struct workqueue_struct of the pointer variable points to the memory address inside the function call kzalloc dynamically generated. So the driver call void destroy_workqueue (struct workqueue_struct * wq) In the case of the work queue is no longer used to release the memory address here.


Cwq figure is a per-CPU type of address space. For create_singlethread_workqueue terms, even for multi-CPU system, the kernel is responsible for creating a worker_thread only kernel process. After the kernel process is created, it will first define a graph in wait node, and then check cwq worklist in a body of the loop, if the queue is empty, then the node will be added to the wait cwq the more_work then Sleep in the waiting queue.

Driver calls queue_work (struct workqueue_struct * wq, struct work_struct * work) was added to the wq work node. work will in turn increase the cwq-> worklist points list. queue_work to cwq-> worklist added a work node, while calls to awaken dormant wake_up on cwq-> more_work of worker_thread process. wake_up will first wait on the call autoremove_wake_function function node, then the node is removed from the wait cwq-> more_work in.

worker_thread again is scheduled to begin processing cwq-> worklist for all the nodes work ... when all work is completed node processing, worker_thread again will wait node to cwq-> more_work, then dormant in the waiting queue until Driver call queue_work again ...

b. create_workqueue



With respect create_singlethread_workqueue, create_workqueue wq will also be assigned a job queue, but differs in that for the purposes of multi-CPU system, for each CPU, cwq structure will be created for a per-CPU, which corresponds every cwq, will generate a new worker_thread process. However, when a node to submit work on cwq with queue_work, which CPU calling the function, then the CPU Bianxiang worklist cwq corresponding increase in work on the node.

c. Summary
When the user invokes workqueue initialization interfaces create_workqueue or create_singlethread_workqueue queue for workqueue initialized, the kernel starts the user is assigned a workqueue object and its chain to a global workqueue queue. Then Linux CPU based on the current situation, in order to workqueue object is assigned the same number of CPU cpu_workqueue_struct objects, each cpu_workqueue_struct objects will exist a task queue. Then, Linux cpu_workqueue_struct for each object is assigned a kernel thread, namely the kernel daemon to process each queue tasks. At this point, the user invokes the initialization interface workqueue initialization is complete, return workqueue pointer. After Workqueue initialization is complete, the task run context to build up, but not yet perform specific tasks, therefore, need to define specific work_struct object. Then work_struct added to the job queue, Linux daemon wakes up to handle the task.

 Workqueue kernel implementation of the principles described above can be described as follows:




3.2 Creating work
To use the job queue, the first thing to do is to create some post-needed push to complete the work. The structure can be built statically compiled by DECLARE_WORK:
DECLARE_WORK (name, void (* func) (void *), void * data);
This will create a file called statically name, pending function func, parameter data of work_struct structure.
Similarly, you can create a pointer at runtime by a work:
INIT_WORK (structwork_struct * work, woid (* func) (void *), void * data);


4. Scheduling
a. schedule_work

In most cases, you do not need to create their own job queue, but only defines the work, the work attached to the core structure predefined event scheduler work queue defines a static global amount in kernel / workqueue.c in Work Queue static struct workqueue_struct * keventd_wq; default worker thread is called events / n, where n is the number of processors, each processor corresponds to a thread. For example, single-processor systems only events / 0 of such a thread. The dual-processor system will be more of an events / 1 thread.
Scheduling work structure, work structure will add to the overall work of the event queue keventd_wq, called queue_work common module. Foreign shielded keventd_wq interface, users do not know this parameter is equivalent to using the default parameters. keventd_wq by the kernel to maintain their own, create, destroy. Such work will soon be scheduled once the worker thread in the processor on which it is awakened, it will be executed.

. b schedule_delayed_work (& work, delay);
Sometimes I do not want to work will be executed immediately, but want it to execute again after some delay. In this case, and you can also use the timer to delay the scheduling, after the expiration of a default timer callback registration work. After delay delay, by the timer wake up, will add to the work queue wq work in.

Work is not the priority queue, essentially as a FIFO manner.

Example

#include <linux/module.h>
#include <linux/init.h>
#include <linux/workqueue.h>
static struct workqueue_struct *queue=NULL;
static struct work_struct   work;
staticvoid work_handler(struct work_struct *data)
{
       printk(KERN_ALERT"work handler function.\n");
}
static int __init test_init(void)
{
      queue=create_singlethread_workqueue("hello world");
      if (!queue)
            goto err;
       INIT_WORK(&work,work_handler);
       schedule_work(&work);
      return0;
err:
      return-1;
}
static   void __exit test_exit(void)
{
       destroy_workqueue(queue);
}
MODULE_LICENSE("GPL");
module_init(test_init);
module_exit(test_exit);

The longstanding task queue interface was removed in 2.5.41; in its place is a new "workqueue" mechanism. Workqueues are very similar to task queues, but there are some important differences. Among other things, each workqueue has one or more dedicated worker threads (one per CPU, by default) associated with it. So all tasks running out of workqueues have a process context, and can thus sleep. Note that access to user space is not possible from code running out of a workqueue; there simply is no user space to access. Drivers can create their own work queues - with their own worker threads - but there is a default queue (for each processor) provided by the kernel that will work in most situations.
Workqueues are created with one of:

    struct workqueue_struct *create_workqueue(const char *name);
    struct workqueue_struct *create_singlethread_workqueue(const char *name);

A workqueue created with create_workqueue() will have one worker thread for each CPU on the system;create_singlethread_workqueue(), instead, creates a workqueue with a single worker process. The name of the queue is limited to ten characters; it is only used for generating the "command" for the kernel thread(s) (which can be seen in ps or top).
Tasks to be run out of a workqueue need to be packaged in a struct work_struct structure. This structure may be declared and initialized at compile time as follows:

    DECLARE_WORK(name, void (*function)(void *), void *data);

Here, name is the name of the resulting work_struct structure, function is the function to call to execute the work, and data is a pointer to pass to that function.
To set up a work_struct structure at run time, instead, use the following two macros:

    INIT_WORK(struct work_struct *work, 
              void (*function)(void *), void *data);
    PREPARE_WORK(struct work_struct *work, 
                 void (*function)(void *), void *data);

The difference between the two is that INIT_WORK initializes the linked list pointers within the work_struct structure, while PREPARE_WORKchanges only the function and data pointers. INIT_WORK must be used at least once before queueing the work_struct structure, but shouldnot be used if the work_struct might already be in a workqueue.
Actually queueing a job to be executed is simple:

    int queue_work(struct workqueue_struct *queue, 
                   struct work_struct *work);
    int queue_delayed_work(struct workqueue_struct *queue, 
                    struct work_struct *work,
                           unsigned long delay);

The second form of the call ensures that a minimum delay (in jiffies) passes before the work is actually executed. The return value from both functions is nonzero if the work_struct was actually added to queue (otherwise, it may have already been there and will not be added a second time).
Entries in workqueues are executed at some undefined time in the future, when the associated worker thread is scheduled to run (and after the delay period, if any, has passed). If it is necessary to cancel a delayed task, you can do so with:

    int cancel_delayed_work(struct work_struct *work);

Note that this workqueue entry could actually be executing when cancel_delayed_work() returns; all this function will do is keep it from starting after the call.
To ensure that none of your workqueue entries are running, call:

    void flush_workqueue(struct workqueue_struct *queue);

This would be a good thing to do, for example, in a device driver shutdown routine. Note that if the queue contains work with long delays this call could take a long time to complete. This function will not (as of 2.5.68) wait for any work entries submitted after the call was first made; you should ensure that, for example, any outstanding work queue entries will not resubmit themselves. You should also cancel any delayed entries (with cancel_delayed_work()) first if need be.
Work queues can be destroyed with:

    void destroy_workqueue(struct workqueue_struct *queue);

This operation will flush the queue, then delete it.
Finally, for tasks that do not justify their own workqueue, a "default" work queue (called "events") is defined. work_struct structures can be added to this queue with:

    int schedule_work(struct work_struct *work);
    int schedule_delayed_work(struct work_struct *work, unsigned long delay);

Most users of workqueues can probably use the predefined queue, but one should bear in mind that it is a shared resource. Long delays in the worker function will slow down other users of the queue, and should be avoided. There is a flush_scheduled_work() function which will wait for everything on this queue to be executed. If your module uses the default queue, it should almost certainly callflush_scheduled_work() before allowing itself to be unloaded.


With first call, the work is scheduled immediately and is run as soon as the events worker thread on the current processor wakes up.
While with second call, the work_struct represented by &work will not execute for at least delay timer ticks into the future.


One final note: schedule_work()schedule_delayed_work() and flush_scheduled_work() are exported to any modules which wish to use them. The other functions (for working with separate workqueues) are exported to GPL-licensed modules only.



Reference
https://lwn.net/Articles/23634/




Saturday, 18 April 2015

UART framwork in Linux


uart linux device driver architecture model of analysis

Introduction
In linux in, serial port terminal is often referred to in the shell, we see / dev / ttyS * is the corresponding serial terminal device nodes. Before analyzing the specific serial driver. It is necessary to analyze uart driven architecture . it is a serial device driver package layers.
Two: uart driver architecture overview
As shown below:




When uart_port receiving data from serial devices, the device will be placed in the corresponding cache line discipline area.
Such user at the time of writing the serial driver, only first to register a uart_driver. Its main role is to define the device node number. Then the operation of packaging equipment will be in uart_port. Drive engineers do not need to be concerned about the upper flow, just by hardware specification uart_port the interface functions can be completed.

Three: uart driver important data structures and their associated
We can consider under their own, based on the above framework code should first consider how to write the following:
1: a uart_driver registration period is usually the device number that corresponds to the user space will see uart_driver multiple device nodes, for example.:
/ dev / ttyS0 / dev / ttyS1 each device node corresponds to a specific hardware architecture point of view from above, each device file should correspond to a uart_port ie:. uart_device how relations with more than one uart_port how to go up? operation is to distinguish which device file?

one for each uart_port -circ_buf, so uart_port must have this relationship up cache

Memories tty driver architecture .tty_driver member points to a call of an array that tty-> ttys. Each device file corresponds to a set array while the array data structure of the code for tty_struct. Corresponding tty_struct will tty_driver and ldisc associate.
That in uart driver, whether it can be used in the same way to deal with it?

The uart drive common data structures expressed as follows:





Combined with the above questions raised can clearly understand the design of these structures.

uart_driver registration operation

Uart_driver registered corresponding function: uart_register_driver () code is as follows:

int uart_register_driver(struct uart_driver *drv)
{
struct
tty_driver *normal = NULL;
int
i, retval;

BUG_ON(drv->state);

/*
*
Maybe we should be using a slab cache for this, especially if
*
we have a large number of ports to handle.
*/
drv->state
= kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);
retval
= -ENOMEM;
if
(!drv→state)
goto
out;
normal = alloc_tty_driver(drv->nr);
if (!normal)
 
        goto out;

 
   drv->tty_driver = normal;

 
   normal->owner      = drv->owner;
 
   normal->driver_name    = drv->driver_name;
 
   normal->name       = drv->dev_name;
 
   normal->major      = drv->major;
 
   normal->minor_start    = drv->minor;
 
   normal->type       = TTY_DRIVER_TYPE_SERIAL;
 
   normal->subtype        = SERIAL_TYPE_NORMAL;
 
   normal->init_termios   = tty_std_termios;
 
   normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
 
   normal->init_termios.c_ispeed = normal->init_termios.c_ospeed = 9600;
 
   normal->flags      = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
 
   normal->driver_state    = drv;
 
   tty_set_operations(normal, &uart_ops);

 
   /*
 
    * Initialise the UART state(s).
 
    */
 
   for (i = 0; i nr; i++) {
 
       struct uart_state *state = drv->state + i;

 
       state->close_delay     = 500;    /* .5 seconds */
 
       state->closing_wait    = 30000;  /* 30 seconds */

 
       mutex_init(&state->mutex);
 
   }

 
   retval = tty_register_driver(normal);
out:
 
   if (retval
 
       put_tty_driver(normal);
 
       kfree(drv->state);
 
   }
 
   return retval;
}

uart_register_driver:

Register a uart driver with the core driver. We in turn register with the tty layer, and initialise the core driver per-port state.
We have a proc file in /proc/tty/driver which is named after the normal driver.
drv->port should be NULL, and the per-port structures should be registered using uart_add_one_port after this call has succeeded.



 int uart_register_driver(struct uart_driver *drv)
 {
         struct tty_driver *normal;
         int i, retval;
 
         BUG_ON(drv->state);
 
         /*
          * Maybe we should be using a slab cache for this, especially if
          * we have a large number of ports to handle.
          */
         drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);
         if (!drv->state)
                 goto out;
 
         normal = alloc_tty_driver(drv->nr);
         if (!normal)
                 goto out_kfree;
 
         drv->tty_driver = normal;
 
        normal->driver_name     = drv->driver_name;
       normal->name            = drv->dev_name;
         normal->major           = drv->major;
         normal->minor_start     = drv->minor;
         normal->type            = TTY_DRIVER_TYPE_SERIAL;
         normal->subtype         = SERIAL_TYPE_NORMAL;
         normal->init_termios    = tty_std_termios;
         normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
         normal->init_termios.c_ispeed = normal->init_termios.c_ospeed = 9600;
         normal->flags           = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
         normal->driver_state    = drv;
         tty_set_operations(normal, &uart_ops);
 
         /*
          * Initialise the UART state(s).
          */
         for (i = 0; i < drv->nr; i++) {
                 struct uart_state *state = drv->state + i;
                 struct tty_port *port = &state->port;
 
                 tty_port_init(port);
                 port->ops = &uart_port_ops;
         }
 
         retval = tty_register_driver(normal);
         if (retval >= 0)
                 return retval;
 
         for (i = 0; i < drv->nr; i++)
                 tty_port_destroy(&drv->state[i].port);
         put_tty_driver(normal);
 out_kfree:
         kfree(drv->state);
 out:
         return -ENOMEM;
 }
 /**
  *      uart_unregister_driver - remove a driver from the uart core layer
  *      @drv: low level driver structure
  *
  *      Remove all references to a driver from the core driver.  The low
  *      level driver must have removed all its ports via the
  *      uart_remove_one_port() if it registered them with uart_add_one_port().
  *      (ie, drv->port == NULL)
  */
 void uart_unregister_driver(struct uart_driver *drv)
 {
         struct tty_driver *p = drv->tty_driver;
         unsigned int i;
 
         tty_unregister_driver(p);
         put_tty_driver(p);
         for (i = 0; i < drv->nr; i++)
                 tty_port_destroy(&drv->state[i].port);
         kfree(drv->state);
         drv->state = NULL;
         drv->tty_driver = NULL;
442 }
    uart_add_one_port() operations

 /**
  *      uart_add_one_port - attach a driver-defined port structure
  *      @drv: pointer to the uart low level driver structure for this port
  *      @uport: uart port structure to use for this port.
  *
  *      This allows the driver to register its own uart_port structure
  *      with the core driver.  The main purpose is to allow the low
  *      level uart drivers to expand uart_port, rather than having yet
  *      more levels of structures.
  */
 int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
 {
         struct uart_state *state;
         struct tty_port *port;
         int ret = 0;
         struct device *tty_dev;
         int num_groups;
         BUG_ON(in_interrupt());
 
         if (uport->line >= drv->nr)
                 return -EINVAL;
 
         state = drv->state + uport->line;
         port = &state->port;
 
         mutex_lock(&port_mutex);
         mutex_lock(&port->mutex);
         if (state->uart_port) {
                 ret = -EINVAL;
                 goto out;
         }
 
         /* Link the port to the driver state table and vice versa */
         state->uart_port = uport;
         uport->state = state;
 
         state->pm_state = UART_PM_STATE_UNDEFINED;
         uport->cons = drv->cons;
 
         /*
          * If this port is a console, then the spinlock is already
          * initialised.
          */
         if (!(uart_console(uport) && (uport->cons->flags & CON_ENABLED))) {
                 spin_lock_init(&uport->lock);
                 lockdep_set_class(&uport->lock, &port_lock_key);
        }
         if (uport->cons && uport->dev)
                 of_console_check(uport->dev->of_node, uport->cons->name, uport->line);
 
         uart_configure_port(drv, state, uport);
 
         num_groups = 2;
         if (uport->attr_group)
                 num_groups++;
 
         uport->tty_groups = kcalloc(num_groups, sizeof(*uport->tty_groups),
                                     GFP_KERNEL);
         if (!uport->tty_groups) {
                 ret = -ENOMEM;
                 goto out;
         }
         uport->tty_groups[0] = &tty_dev_attr_group;
         if (uport->attr_group)
                 uport->tty_groups[1] = uport->attr_group;
 
         /*
          * Register the port whether it's detected or not.  This allows
          * setserial to be used to alter this port's parameters.
          */
         tty_dev = tty_port_register_device_attr(port, drv->tty_driver,
                         uport->line, uport->dev, port, uport->tty_groups);
         if (likely(!IS_ERR(tty_dev))) {
                 device_set_wakeup_capable(tty_dev, 1);
         } else {
                 dev_err(uport->dev, "Cannot register tty device on line %d\n",
                        uport->line);
         }
 
         /*
          * Ensure UPF_DEAD is not set.
          */
         uport->flags &= ~UPF_DEAD;
 
  out:
         mutex_unlock(&port->mutex);
         mutex_unlock(&port_mutex);
 
         return ret;
 }


/**
  *      uart_remove_one_port - detach a driver defined port structure
  *      @drv: pointer to the uart low level driver structure for this port
*      @uport: uart port structure for this port
  *
  *      This unhooks (and hangs up) the specified port structure from the
  *      core driver.  No further calls will be made to the low-level code
  *      for this port.
  */
 int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)
 {
         struct uart_state *state = drv->state + uport->line;
         struct tty_port *port = &state->port;
         struct tty_struct *tty;
         int ret = 0;
 
         BUG_ON(in_interrupt());
 
         if (state->uart_port != uport)
                 dev_alert(uport->dev, "Removing wrong port: %p != %p\n",
                         state->uart_port, uport);
 
         mutex_lock(&port_mutex);
 
         /*
          * Mark the port "dead" - this prevents any opens from
          * succeeding while we shut down the port.
          */
         mutex_lock(&port->mutex);
         if (!state->uart_port) {
                 mutex_unlock(&port->mutex);
                 ret = -EINVAL;
                 goto out;
         }
         uport->flags |= UPF_DEAD;
         mutex_unlock(&port->mutex);
 
         /*
          * Remove the devices from the tty layer
          */
         tty_unregister_device(drv->tty_driver, uport->line);
 
         tty = tty_port_tty_get(port);
         if (tty) {
                 tty_vhangup(port->tty);
                 tty_kref_put(tty);
         }
 
         /*
          * If the port is used as a console, unregister it
         */
         if (uart_console(uport))
                 unregister_console(uport->cons);
 
         /*
          * Free the port IO and memory resources, if any.
          */
         if (uport->type != PORT_UNKNOWN)
                 uport->ops->release_port(uport);
         kfree(uport->tty_groups);
 
         /*
          * Indicate that there isn't a port here anymore.
          */
         uport->type = PORT_UNKNOWN;
 
         state->uart_port = NULL;
 out:
         mutex_unlock(&port_mutex);
 
         return ret;
 }
First, this function can not be used. Uart_port-> line is to uart device file number in interrupt context. It is the corresponding uart_driver-> state array uart_port-> line items.
It is mainly the corresponding initialization uart_driver-> state items. Then call uart_configure_port () to automatically configure the port and then registered tty_device. If the user space to run the udev or has been configured hotplug. Will automatically generate device files in / dev up.
Operational flowchart is as follows:
 
 static const struct tty_operations uart_ops = {
         .open           = uart_open,
         .close          = uart_close,
         .write          = uart_write,
         .put_char       = uart_put_char,
         .flush_chars    = uart_flush_chars,
         .write_room     = uart_write_room,
         .chars_in_buffer= uart_chars_in_buffer,
         .flush_buffer   = uart_flush_buffer,
         .ioctl          = uart_ioctl,
         .throttle       = uart_throttle,
         .unthrottle     = uart_unthrottle,
         .send_xchar     = uart_send_xchar,
         .set_termios    = uart_set_termios,
         .set_ldisc      = uart_set_ldisc,
         .stop           = uart_stop,
         .start          = uart_start,
         .hangup         = uart_hangup,
         .break_ctl      = uart_break_ctl,
         .wait_until_sent= uart_wait_until_sent,
 #ifdef CONFIG_PROC_FS
         .proc_fops      = &uart_proc_fops,
 #endif
         .tiocmget       = uart_tiocmget,
         .tiocmset       = uart_tiocmset,
         .get_icount     = uart_get_icount,
 #ifdef CONFIG_CONSOLE_POLL
         .poll_init      = uart_poll_init,
         .poll_get_char  = uart_poll_get_char,
         .poll_put_char  = uart_poll_put_char,
 #endif
 };
 
open operating device node
When users open space to perform the operation, it will perform uart_ops-> open Uart_ops definition as follows:

 /*
  * Calls to uart_open are serialised by the tty_lock in
  *   drivers/tty/tty_io.c:tty_open()
  * Note that if this fails, then uart_close() _will_ be called.
  *
  * In time, we want to scrap the "opening nonpresent ports"
  * behaviour and implement an alternative way for setserial
  * to set base addresses/ports/types.  This will allow us to
  * get rid of a certain amount of extra tests.
  */
 static int uart_open(struct tty_struct *tty, struct file *filp)
 {
         struct uart_driver *drv = (struct uart_driver *)tty->driver->driver_tate;
         int retval, line = tty->index;
         struct uart_state *state = drv->state + line;
         struct tty_port *port = &state->port;
 
         pr_debug("uart_open(%d) called\n", line);
 
         spin_lock_irq(&port->lock);
         ++port->count;
         spin_unlock_irq(&port->lock);
 
         /*
          * We take the semaphore here to guarantee that we won't be re-entered
          * while allocating the state structure, or while we request any IRQ         * that the driver may need.  This also has the nice side-effect tha         * it delays the action of uart_hangup, so we can guarantee that
          * state->port.tty will always contain something reasonable.
          */
         if (mutex_lock_interruptible(&port->mutex)) {
                 retval = -ERESTARTSYS;
                 goto end;
         }
 
         if (!state->uart_port || state->uart_port->flags & UPF_DEAD) {
                 retval = -ENXIO;
                goto err_unlock;
         }
 
         tty->driver_data = state;
         state->uart_port->state = state;
         state->port.low_latency =
                 (state->uart_port->flags & UPF_LOW_LATENCY) ? 1 : 0;
         tty_port_tty_set(port, tty);
 
         /*
          * Start up the serial port.
          */
         retval = uart_startup(tty, state, 0);
 
         /*
          * If we succeeded, wait until the port is ready.
          */
         mutex_unlock(&port->mutex);
         if (retval == 0)
                 retval = tty_port_block_til_ready(port, tty, filp);
 
 end:
         return retval;
 err_unlock:
         mutex_unlock(&port->mutex);
         goto end;
 }

Here, Note To complete the ring buffer that info-> xmit initialization. Then call the port-> ops-> startup () will bring the port to a working state. Other is an adjustable parameter settings, do not explained in detail.

device node write operation
Write operation corresponds to the operation of the interface for uart_write () code is as follows:

 static int uart_write(struct tty_struct *tty,
                                         const unsigned char *buf, int count)
 {
         struct uart_state *state = tty->driver_data;
         struct uart_port *port;
         struct circ_buf *circ;
         unsigned long flags;
         int c, ret = 0;
 
         /*
          * This means you called this function _after_ the port was
          * closed.  No cookie for you.
          */
         if (!state) {
                 WARN_ON(1);
                 return -EL3HLT;
         }
 
         port = state->uart_port;
        circ = &state->xmit;
 
         if (!circ->buf)
                 return 0;
 
         spin_lock_irqsave(&port->lock, flags);
         while (1) {
                 c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE);
                 if (count < c)
                         c = count;
                 if (c <= 0)
                         break;
                 memcpy(circ->buf + circ->head, buf, c);
                 circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1);
                 buf += c;
                 count -= c;
                 ret += c;
         }
 
         __uart_start(tty);
         spin_unlock_irqrestore(&port->lock, flags);
 
         return ret;
 }
static void uart_start(struct tty_struct *tty)
{
 
   struct uart_state *state = tty->driver_data;
 
   struct uart_port *port = state->port;
 
   unsigned long flags;

 
   spin_lock_irqsave(&port->lock, flags);
 
   __uart_start(tty);
 
   spin_unlock_irqrestore(&port->lock, flags);
}

static void __uart_start(struct tty_struct *tty)
{
 
   struct uart_state *state = tty->driver_data;
 
   struct uart_port *port = state->port;

 
   if (!uart_circ_empty(&state->info->xmit) && state->info->xmit.buf &&
 
       !tty->stopped && !tty->hw_stopped)
 
       port->ops->start_tx(port);
}

Note:
As can be seen from the code here note if the operation is to initialize the state-> info. Note port-> info is state-> a copy of the info. That port directly through port-> info can be found in the cache it is to operate.
 /*
  * Startup the port.  This will be called once per open.  All calls
  * will be serialised by the per-port mutex.
  */
 static int uart_port_startup(struct tty_struct *tty, struct uart_state *state                 int init_hw)
 {
         struct uart_port *uport = state->uart_port;
         unsigned long page;
         int retval = 0;
 
         if (uport->type == PORT_UNKNOWN)
                 return 1;
 
         /*
          * Make sure the device is in D0 state.
          */
         uart_change_pm(state, UART_PM_STATE_ON);
 
         /*
          * Initialise and allocate the transmit and temporary
          * buffer.
          */
         if (!state->xmit.buf) {
                 /* This is protected by the per port mutex */
                 page = get_zeroed_page(GFP_KERNEL);
                 if (!page)
                         return -ENOMEM;
 
                 state->xmit.buf = (unsigned char *) page;
                 uart_circ_clear(&state->xmit);
         }
 
         retval = uport->ops->startup(uport);
         if (retval == 0) {
                 if (uart_console(uport) && uport->cons->cflag) {
                         tty->termios.c_cflag = uport->cons->cflag;
                         uport->cons->cflag = 0;
                 }
                 /*
                  * Initialise the hardware port settings.
                  */
                 uart_change_speed(tty, state, NULL);
 
                 if (init_hw) {
                         /*
                          * Setup the RTS and DTR signals once the
                          * port is open and ready to respond.
                          */
                         if (tty->termios.c_cflag & CBAUD)
                                 uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR);
                 }
 
                 spin_lock_irq(&uport->lock);
                 if (uart_cts_enabled(uport) &&
                     !(uport->ops->get_mctrl(uport) & TIOCM_CTS))
                         uport->hw_stopped = 1;
                 else
                         uport->hw_stopped = 0;
                 spin_unlock_irq(&uport->lock);
         }
 
         /*
          * This is to allow setserial on this port. People may want to set
          * port/irq/type and then reconfigure the port properly if it failed
          * now.
          */
         if (retval && capable(CAP_SYS_ADMIN))
                 return 1;
 
         return retval;
 }
 
 static int uart_startup(struct tty_struct *tty, struct uart_state *state,
                 int init_hw)
 {
         struct tty_port *port = &state->port;
         int retval;
 
         if (port->flags & ASYNC_INITIALIZED)
                 return 0;
 
         /*
          * Set the TTY IO error marker - we will only clear this
          * once we have successfully opened the port.
          */
         set_bit(TTY_IO_ERROR, &tty->flags);
 
         retval = uart_port_startup(tty, state, init_hw);
         if (!retval) {
                 set_bit(ASYNCB_INITIALIZED, &port->flags);
                 clear_bit(TTY_IO_ERROR, &tty->flags);
         } else if (retval > 0)
                 retval = 0;
 
        return retval;
 }
 
In this function, the continued operation of the device to complete the initialization file corresponding state. Now open the device the user space. That is to be operated on this file. It uart_port also began to work. That call uart_startup () make it into work state. of course, you need to initialize the corresponding ring buffer uart_port circ_buf. that state-> info-> xmit.

Pay particular attention to where the tty-> driver_data = state; this is because after only port-related operations, do not need to understand uart_driver information.
Tracking a look at two important subroutine which calls uart_get () and uart_startup () first analyze uart_get () code is as follows...:

static struct uart_state *uart_get (struct uart_driver *drv, int line)
{
 
   struct uart_state *state;
 
   int ret = 0;

 
   state = drv->state + line;
 
   if (mutex_lock_interruptible(&state->mutex)) {
 
       ret = -ERESTARTSYS;
 
       goto err;
 
   }

 
   state->count++;
 
   if (!state->port || state->port->flags & UPF_DEAD) {
 
       ret = -ENXIO;
 
       goto err_unlock;
 
   }

 
   if (!state->info) {
 
       state->info = kzalloc(sizeof(struct uart_info), GFP_KERNEL);
 
       if (state->info) {
 
            init_waitqueue_head(&state->info->open_wait);
 
            init_waitqueue_head(&state->info->delta_msr_wait);

 
            /*
 
             * Link the info into the other structures.
 
             */
 
            state->port->info = state->info;

 
            tasklet_init(&state->info->tlet, uart_tasklet_action,
 
                      (unsigned long)state);
 
       } else {
 
            ret = -ENOMEM;
 
            goto err_unlock;
 
       }
 
   }
 
   return state;

err_unlock:
 
   state->count--;
 
   mutex_unlock(&state->mutex);
err:
 
   return ERR_PTR(ret);

}

UART In BeagleBone Black:


                   RX TX           CTS   RTS                        Device      Remark
 UART0 J1_4 J1_5                               /dev/ttyO0      BeagleBone Black only
 UART1 P9_26 P9_24 P9_20 P9_19               /dev/ttyO1
 UART2 P9_22 P9_21 P8_37 P8_38               /dev/ttyO2
 UART3          P9_42 P8_36 P8_34               /dev/ttyO3      TX only
 UART4 P9_11 P9_13 P8_35 P8_33               /dev/ttyO4
 UART5 P8_38 P8_37 P8_31 P8_32               /dev/ttyO5


Device tree would be having different name for these so look into the base address and identify UARTs and then change them.  


Summary
After this section is to analyze the serial-driven basis in the understanding of the tty driver architecture, come to understand uart driver architecture should not be difficult. With our in-depth analysis in linux device driver, more deeply appreciate, linux device driver architecture many of which are interlinked. As long as a deep understanding of a driver architecture. replicability. it is easy to analyze the drivers of other architectures.

Reference
1)Essential Linux Device driver chapter 6
2)serial drivers PPT by free-electrons

For any query post a comment 

Thank You Enjoy !!!!