I have taken the Software-based serial port module code from [here] (https://github.com/adrianomarto/soft_uart/) and implemented it for my application for the iMX-6 processor.
Although my driver is working fine to send/receive data between MCU (STM32L476) and MPU (iMX-6) via this driver module. I am getting crash for "hrtimer state" after running this module for hours. crash dump is attached below.
Below is the details for the setup:
- This module is used to receive incoming usart data from STM32 MCU usart set @ 4800 baud, 8N1.
- MPU two gpio pins are configured to mimic usart through bit-bang method.
- MPU software usart module has baud set to 4800, 8N1 with no flow control.
I am suspecting that somewhere in the soft-uart module "hrtimer_start" is called so much frequently or it is being handled incorrectly such that hrtimer is getting enqueued from "__run_hrtimer" as soon as the software is expecting it to be in callback state and that is the cause of the crash. Can anyone have a similar issue? or have information about this behavior please guide me. what could cause this kind of behavior?
Below is the code for software-based UART module
#include <linux/gpio.h>
#include <linux/hrtimer.h>
#include <linux/interrupt.h>
#include <linux/ktime.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/tty_driver.h>
#define SOFT_UART_MAJOR 0
#define N_PORTS 1
#define NONE 0
#define TX_BUFFER_FLUSH_TIMEOUT 4000 // milliseconds
#define DEV_BAUDRATE 4800
MODULE_LICENSE("GPL");
MODULE_AUTHOR("General");
MODULE_DESCRIPTION("Software-UART");
MODULE_VERSION("0.2");
//***********************************************************************************************//
int imx_soft_uart_init(const int gpio_tx, const int gpio_rx);
int imx_soft_uart_finalize(void);
int imx_soft_uart_open(struct tty_struct* tty);
int imx_soft_uart_close(void);
int imx_soft_uart_set_rx_callback(void (*callback)(unsigned char));
int imx_soft_uart_set_baudrate(const int baudrate);
int imx_soft_uart_send_string(const unsigned char* string, int string_size);
int imx_soft_uart_get_tx_queue_room(void);
int imx_soft_uart_get_tx_queue_size(void);
//***********************************************************************************************//
static irq_handler_t handle_rx_start(unsigned int irq, void* device, struct pt_regs* registers);
static irq_handler_t handle_rx_bytes(unsigned int irq, void* device, struct pt_regs* registers);
static enum hrtimer_restart handle_tx(struct hrtimer* timer);
static enum hrtimer_restart handle_rx(struct hrtimer* timer);
static void receive_character(unsigned char character);
static struct queue queue_tx;
static struct tty_struct* current_tty = NULL;
static DEFINE_MUTEX(current_tty_mutex);
static struct hrtimer timer_tx;
static struct hrtimer timer_rx;
static ktime_t period;
static ktime_t half_period;
unsigned long long t_half_period;
static int rx_bit_index = -1;
static void (*rx_callback)(unsigned char) = NULL;
//***********************************************************************************************//
#define QUEUE_MAX_SIZE 256
struct queue
{
int front;
int rear;
int size;
unsigned char data[QUEUE_MAX_SIZE];
};
void initialize_queue(struct queue* queue);
int enqueue_character(struct queue* queue, const unsigned char character);
int dequeue_character(struct queue* queue, unsigned char* character);
int enqueue_string(struct queue* queue, const unsigned char* string, int string_size);
int get_queue_room(struct queue* queue);
int get_queue_size(struct queue* queue);
//***********************************************************************************************//
/**
* Initializes a given queue.
* @param queue given queue
*/
void initialize_queue(struct queue* queue)
{
queue->size = 0;
queue->front = 0;
queue->rear = 0;
}
/**
* Adds a given character into a given queue.
* @param queue given queue
* @param character given character
* @return 1 if the character is added to the queue. 0 if the queue is full.
*/
int enqueue_character(struct queue* queue, const unsigned char character)
{
int success = 0;
if (queue->size < QUEUE_MAX_SIZE)
{
if (queue->size != 0)
{
queue->rear++;
if (queue->rear >= QUEUE_MAX_SIZE)
{
queue->rear = 0;
}
}
else
{
queue->rear = 0;
queue->front = 0;
}
queue->data[queue->rear] = character;
queue->size++;
success = 1;
}
return success;
}
/**
* Gets a character from a fiven queue.
* @param queue given queue
* @param character a character
* @return 1 if a character is fetched from the queue. 0 if the queue is empy.
*/
int dequeue_character(struct queue* queue, unsigned char* character)
{
int success = 0;
if (queue->size > 0)
{
*character = queue->data[queue->front];
queue->front++;
if (queue->front >= QUEUE_MAX_SIZE)
{
queue->front = 0;
}
queue->size--;
success = 1;
}
return success;
}
/**
* Adds a given string to a given queue.
* @param queue given queue
* @param string given string
* @param string_size size of the given string
* @return The amount of characters successfully added to the queue.
*/
int enqueue_string(struct queue* queue, const unsigned char* string, int string_size)
{
int n = 0;
while (n < string_size && enqueue_character(queue, string[n]))
{
n++;
}
return n;
}
/**
* Gets the number of characters that can be added to a given queue.
* @return number of characters.
*/
int get_queue_room(struct queue* queue)
{
return QUEUE_MAX_SIZE - queue->size;
}
/**
* Gets the number of characters contained in a given queue.
* @return number of characters.
*/
int get_queue_size(struct queue* queue)
{
return queue->size;
}
//****************************************************************************//
static int gpio_tx = 147;
module_param(gpio_tx, int, 0);
static int gpio_rx = 146;
module_param(gpio_rx, int, 0);
// Module prototypes.
static int soft_uart_open(struct tty_struct*, struct file*);
static void soft_uart_close(struct tty_struct*, struct file*);
static int soft_uart_write(struct tty_struct*, const unsigned char*, int);
static int soft_uart_write_room(struct tty_struct*);
static void soft_uart_flush_buffer(struct tty_struct*);
static int soft_uart_chars_in_buffer(struct tty_struct*);
static void soft_uart_set_termios(struct tty_struct*, struct ktermios*);
static void soft_uart_stop(struct tty_struct*);
static void soft_uart_start(struct tty_struct*);
static void soft_uart_hangup(struct tty_struct*);
static int soft_uart_tiocmget(struct tty_struct*);
static int soft_uart_tiocmset(struct tty_struct*, unsigned int, unsigned int);
static int soft_uart_ioctl(struct tty_struct*, unsigned int, unsigned int long);
static void soft_uart_throttle(struct tty_struct*);
static void soft_uart_unthrottle(struct tty_struct*);
// Module operations.
static const struct tty_operations soft_uart_operations = {
.open = soft_uart_open,
.close = soft_uart_close,
.write = soft_uart_write,
.write_room = soft_uart_write_room,
.flush_buffer = soft_uart_flush_buffer,
.chars_in_buffer = soft_uart_chars_in_buffer,
.ioctl = soft_uart_ioctl,
.set_termios = soft_uart_set_termios,
.stop = soft_uart_stop,
.start = soft_uart_start,
.hangup = soft_uart_hangup,
.tiocmget = soft_uart_tiocmget,
.tiocmset = soft_uart_tiocmset,
.throttle = soft_uart_throttle,
.unthrottle = soft_uart_unthrottle
};
// Driver instance.
static struct tty_driver* soft_uart_driver = NULL;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
static struct tty_port port;
#endif
/**
* Module initialization.
*/
static int __init soft_uart_init(void)
{
imx_soft_uart_set_baudrate(DEV_BAUDRATE);
printk(KERN_INFO "soft_uart: Initializing module...#2\n");
if (!imx_soft_uart_init(gpio_tx, gpio_rx))
{
printk(KERN_ALERT "soft_uart: Failed initialize GPIO.\n");
return -ENOMEM;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
printk(KERN_INFO "soft_uart: LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0).\n");
// Initializes the port.
tty_port_init(&port);
port.low_latency = 0;
// Allocates the driver.
soft_uart_driver = tty_alloc_driver(N_PORTS, TTY_DRIVER_REAL_RAW);
// Returns if the allocation fails.
if (IS_ERR(soft_uart_driver))
{
printk(KERN_ALERT "soft_uart: Failed to allocate the driver.\n");
return -ENOMEM;
}
#else
printk(KERN_INFO "soft_uart: LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0).\n");
// Allocates the driver.
soft_uart_driver = alloc_tty_driver(N_PORTS);
// Returns if the allocation fails.
if (!soft_uart_driver)
{
printk(KERN_ALERT "soft_uart: Failed to allocate the driver.\n");
return -ENOMEM;
}
#endif
// Initializes the driver.
soft_uart_driver->owner = THIS_MODULE;
soft_uart_driver->driver_name = "soft_uart";
soft_uart_driver->name = "ttySOFT";
soft_uart_driver->major = SOFT_UART_MAJOR;
soft_uart_driver->minor_start = 0;
soft_uart_driver->flags = TTY_DRIVER_REAL_RAW;
soft_uart_driver->type = TTY_DRIVER_TYPE_SERIAL;
soft_uart_driver->subtype = SERIAL_TYPE_NORMAL;
soft_uart_driver->init_termios = tty_std_termios;
soft_uart_driver->init_termios.c_ispeed = 4800;
soft_uart_driver->init_termios.c_ospeed = 4800;
soft_uart_driver->init_termios.c_cflag = B4800 | CREAD | CS8 | CLOCAL;
// Sets the callbacks for the driver.
tty_set_operations(soft_uart_driver, &soft_uart_operations);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
// Link the port with the driver.
tty_port_link_device(&port, soft_uart_driver, 0);
#endif
// Registers the TTY driver.
if (tty_register_driver(soft_uart_driver))
{
printk(KERN_ALERT "soft_uart: Failed to register the driver.\n");
put_tty_driver(soft_uart_driver);
return -1; // return if registration fails
}
printk(KERN_INFO "soft_uart: baudrate : %d\n", DEV_BAUDRATE);
printk(KERN_INFO "soft_uart: Module initialized.\n");
return 0;
}
/**
* Cleanup function that gets called when the module is unloaded.
*/
static void __exit soft_uart_exit(void)
{
printk(KERN_INFO "soft_uart: Finalizing the module...\n");
// Finalizes the soft UART.
if (!imx_soft_uart_finalize())
{
printk(KERN_ALERT "soft_uart: Something went wrong whilst finalizing the soft UART.\n");
}
// Unregisters the driver.
if (tty_unregister_driver(soft_uart_driver))
{
printk(KERN_ALERT "soft_uart: Failed to unregister the driver.\n");
}
put_tty_driver(soft_uart_driver);
printk(KERN_INFO "soft_uart: Module finalized.\n");
}
/**
* Opens a given TTY device.
* @param tty given TTY device
* @param file
* @return error code.
*/
static int soft_uart_open(struct tty_struct* tty, struct file* file)
{
int error = NONE;
if (imx_soft_uart_open(tty))
{
printk(KERN_INFO "soft_uart: Device opened.\n");
}
else
{
printk(KERN_ALERT "soft_uart: Device busy.\n");
error = -ENODEV;
}
return error;
}
/**
* Closes a given TTY device.
* @param tty
* @param file
*/
static void soft_uart_close(struct tty_struct* tty, struct file* file)
{
// Waits for the TX buffer to be empty before closing the UART.
int wait_time = 0;
while ((imx_soft_uart_get_tx_queue_size() > 0)
&& (wait_time < TX_BUFFER_FLUSH_TIMEOUT))
{
msleep(100);
wait_time += 100;
}
if (imx_soft_uart_close())
{
printk(KERN_INFO "soft_uart: Device closed.\n");
}
else
{
printk(KERN_ALERT "soft_uart: Could not close the device.\n");
}
}
/**
* Writes the contents of a given buffer into a given TTY device.
* @param tty given TTY device
* @param buffer given buffer
* @param buffer_size number of bytes contained in the given buffer
* @return number of bytes successfuly written into the TTY device
*/
static int soft_uart_write(struct tty_struct* tty, const unsigned char* buffer, int buffer_size)
{
return imx_soft_uart_send_string(buffer, buffer_size);
}
/**
* Tells the kernel the number of bytes that can be written to a given TTY.
* @param tty given TTY
* @return number of bytes
*/
static int soft_uart_write_room(struct tty_struct* tty)
{
return imx_soft_uart_get_tx_queue_room();
}
/**
* Does nothing.
* @param tty
*/
static void soft_uart_flush_buffer(struct tty_struct* tty)
{
}
/**
* Tells the kernel the number of bytes contained in the buffer of a given TTY.
* @param tty given TTY
* @return number of bytes
*/
static int soft_uart_chars_in_buffer(struct tty_struct* tty)
{
return imx_soft_uart_get_tx_queue_size();
}
/**
* Sets the UART parameters for a given TTY (only the baudrate is taken into account).
* @param tty given TTY
* @param termios parameters
*/
static void soft_uart_set_termios(struct tty_struct* tty, struct ktermios* termios)
{
int cflag = 0;
speed_t baudrate = tty_get_baud_rate(tty);
printk(KERN_INFO "soft_uart: soft_uart_set_termios: baudrate = %d.\n", baudrate);
// Gets the cflag.
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
cflag = tty->termios.c_cflag;
#else
cflag = tty->termios->c_cflag;
#endif
// Verifies the number of data bits (it must be 8).
if ((cflag & CSIZE) != CS8)
{
printk(KERN_ALERT "soft_uart: Invalid number of data bits.\n");
}
// Verifies the number of stop bits (it must be 1).
if (cflag & CSTOPB)
{
printk(KERN_ALERT "soft_uart: Invalid number of stop bits.\n");
}
// Verifies the parity (it must be none).
if (cflag & PARENB)
{
printk(KERN_ALERT "soft_uart: Invalid parity.\n");
}
// Configure the baudrate.
if (!imx_soft_uart_set_baudrate(baudrate))
{
printk(KERN_ALERT "soft_uart: Invalid baudrate.\n");
}
}
/**
* Does nothing.
* @param tty
*/
static void soft_uart_stop(struct tty_struct* tty)
{
printk(KERN_DEBUG "soft_uart: soft_uart_stop.\n");
}
/**
* Does nothing.
* @param tty
*/
static void soft_uart_start(struct tty_struct* tty)
{
printk(KERN_DEBUG "soft_uart: soft_uart_start.\n");
}
/**
* Does nothing.
* @param tty
*/
static void soft_uart_hangup(struct tty_struct* tty)
{
printk(KERN_DEBUG "soft_uart: soft_uart_hangup.\n");
}
/**
* Does nothing.
* @param tty
*/
static int soft_uart_tiocmget(struct tty_struct* tty)
{
return 0;
}
/**
* Does nothing.
* @param tty
* @param set
* @param clear
*/
static int soft_uart_tiocmset(struct tty_struct* tty, unsigned int set, unsigned int clear)
{
return 0;
}
/**
* Does nothing.
* @param tty
* @param command
* @param parameter
*/
static int soft_uart_ioctl(struct tty_struct* tty, unsigned int command, unsigned int long parameter)
{
int error = NONE;
switch (command)
{
case TIOCMSET:
error = NONE;
break;
case TIOCMGET:
error = NONE;
break;
default:
error = -ENOIOCTLCMD;
break;
}
return error;
}
/**
* Does nothing.
* @param tty
*/
static void soft_uart_throttle(struct tty_struct* tty)
{
printk(KERN_DEBUG "soft_uart: soft_uart_throttle.\n");
}
/**
* Does nothing.
* @param tty
*/
static void soft_uart_unthrottle(struct tty_struct* tty)
{
printk(KERN_DEBUG "soft_uart: soft_uart_unthrottle.\n");
}
// Module entry points.
module_init(soft_uart_init);
module_exit(soft_uart_exit);
//**************************************************************************************************//
/**
* Initializes the Soft UART infrastructure.
* This must be called during the module initialization.
* The GPIO pin used as TX is configured as output.
* The GPIO pin used as RX is configured as input.
* @param gpio_tx GPIO pin used as TX
* @param gpio_rx GPIO pin used as RX
* @return 1 if the initialization is successful. 0 otherwise.
*/
int imx_soft_uart_init(const int _gpio_tx, const int _gpio_rx)
{
bool success = true;
mutex_init(¤t_tty_mutex);
// Initializes the TX timer.
hrtimer_init(&timer_tx, CLOCK_MONOTONIC_RAW, HRTIMER_MODE_REL);
timer_tx.function = &handle_tx;
// Initializes the RX timer.
hrtimer_init(&timer_rx, CLOCK_MONOTONIC_RAW, HRTIMER_MODE_REL);
timer_rx.function = &handle_rx;
// Initializes the GPIO pins.
gpio_tx = _gpio_tx;
gpio_rx = _gpio_rx;
success &= gpio_request(gpio_tx, "soft_uart_tx") == 0;
success &= gpio_direction_output(gpio_tx, 1) == 0;
success &= gpio_request(gpio_rx, "soft_uart_rx") == 0;
success &= gpio_direction_input(gpio_rx) == 0;
// Initializes the interruption.
// success &= request_threaded_irq(
// gpio_to_irq(gpio_rx), (irq_handler_t) handle_rx_bytes,
// (irq_handler_t) handle_rx_start,
// IRQF_TRIGGER_FALLING,
// "soft_uart_irq_handler",
// NULL) == 0;
// Initializes the interruption.
success &= request_irq(
gpio_to_irq(gpio_rx),
(irq_handler_t) handle_rx_start,
IRQF_TRIGGER_FALLING,
"soft_uart_irq_handler",
NULL) == 0;
disable_irq(gpio_to_irq(gpio_rx));
return success;
}
/**
* Finalizes the Soft UART infrastructure.
*/
int imx_soft_uart_finalize(void)
{
free_irq(gpio_to_irq(gpio_rx), NULL);
gpio_set_value(gpio_tx, 0);
gpio_free(gpio_tx);
gpio_free(gpio_rx);
return 1;
}
/**
* Opens the Soft UART.
* @param tty
* @return 1 if the operation is successful. 0 otherwise.
*/
int imx_soft_uart_open(struct tty_struct* tty)
{
int success = 0;
mutex_lock(¤t_tty_mutex);
rx_bit_index = -1;
if (current_tty == NULL)
{
current_tty = tty;
initialize_queue(&queue_tx);
success = 1;
enable_irq(gpio_to_irq(gpio_rx));
}
mutex_unlock(¤t_tty_mutex);
return success;
}
/**
* Closes the Soft UART.
*/
int imx_soft_uart_close(void)
{
mutex_lock(¤t_tty_mutex);
disable_irq(gpio_to_irq(gpio_rx));
hrtimer_cancel(&timer_tx);
hrtimer_cancel(&timer_rx);
current_tty = NULL;
mutex_unlock(¤t_tty_mutex);
return 1;
}
/**
* Sets the Soft UART baudrate.
* @param baudrate desired baudrate
* @return 1 if the operation is successful. 0 otherwise.
*/
int imx_soft_uart_set_baudrate(const int baudrate)
{
period = ktime_set(0, 1000000000/baudrate);
half_period = ktime_set(0, 1000000000/baudrate/2);
t_half_period = half_period.tv64;
gpio_set_debounce(gpio_rx, 1000/baudrate/2);
return 1;
}
/**
* Adds a given string to the TX queue.
* @param string given string
* @param string_size size of the given string
* @return The amount of characters successfully added to the queue.
*/
int imx_soft_uart_send_string(const unsigned char* string, int string_size)
{
int result = enqueue_string(&queue_tx, string, string_size);
// Starts the TX timer if it is not already running.
if (!hrtimer_active(&timer_tx))
{
hrtimer_start(&timer_tx, period, HRTIMER_MODE_REL);
}
return result;
}
/*
* Gets the number of characters that can be added to the TX queue.
* @return number of characters.
*/
int imx_soft_uart_get_tx_queue_room(void)
{
return get_queue_room(&queue_tx);
}
/*
* Gets the number of characters in the TX queue.
* @return number of characters.
*/
int imx_soft_uart_get_tx_queue_size(void)
{
return get_queue_size(&queue_tx);
}
/**
* Sets the callback function to be called on received character.
* @param callback the callback function
*/
int imx_soft_uart_set_rx_callback(void (*callback)(unsigned char))
{
rx_callback = callback;
return 1;
}
//-----------------------------------------------------------------------------
// Internals
//-----------------------------------------------------------------------------
/**
* If we are waiting for the RX start bit, then starts the RX timer. Otherwise,
* does nothing.
*/
static irq_handler_t handle_rx_start(unsigned int irq, void* device, struct pt_regs* registers)
{
if (rx_bit_index == -1)
{
hrtimer_start(&timer_rx, ktime_set( 0, t_half_period), HRTIMER_MODE_REL);
}
return (irq_handler_t) IRQ_HANDLED;
}
/**
* If we are waiting for the RX start bit, then starts the RX timer. Otherwise,
* does nothing.
*/
static irq_handler_t handle_rx_bytes(unsigned int irq, void* device, struct pt_regs* registers)
{
return (irq_handler_t) IRQ_WAKE_THREAD;
}
/**
* Dequeues a character from the TX queue and sends it.
*/
static enum hrtimer_restart handle_tx(struct hrtimer* timer)
{
ktime_t current_time = ktime_get();
static unsigned char character = 0;
static int bit_index = -1;
enum hrtimer_restart result = HRTIMER_NORESTART;
bool must_restart_timer = false;
// Start bit.
if (bit_index == -1)
{
if (dequeue_character(&queue_tx, &character))
{
gpio_set_value(gpio_tx, 0);
bit_index++;
must_restart_timer = true;
}
}
// Data bits.
else if (0 <= bit_index && bit_index < 8)
{
gpio_set_value(gpio_tx, 1 & (character >> bit_index));
bit_index++;
must_restart_timer = true;
}
// Stop bit.
else if (bit_index == 8)
{
gpio_set_value(gpio_tx, 1);
character = 0;
bit_index = -1;
must_restart_timer = get_queue_size(&queue_tx) > 0;
}
// Restarts the TX timer.
if (must_restart_timer)
{
hrtimer_forward(&timer_tx, current_time, period);
result = HRTIMER_RESTART;
}
return result;
}
/*
* Receives a character and sends it to the kernel.
*/
static enum hrtimer_restart handle_rx(struct hrtimer* timer)
{
ktime_t current_time = ktime_get();
static unsigned int character = 0;
int bit_value = gpio_get_value(gpio_rx);
enum hrtimer_restart result = HRTIMER_NORESTART;
bool must_restart_timer = false;
// Start bit.
if (rx_bit_index == -1)
{
rx_bit_index++;
character = 0;
must_restart_timer = true;
}
// Data bits.
else if (0 <= rx_bit_index && rx_bit_index < 8)
{
if (bit_value == 0)
{
character &= 0xfeff;
}
else
{
character |= 0x0100;
}
rx_bit_index++;
character >>= 1;
must_restart_timer = true;
}
// Stop bit.
else if (rx_bit_index == 8)
{
receive_character(character);
rx_bit_index = -1;
}
// Restarts the RX timer.
if (must_restart_timer)
{
hrtimer_forward(&timer_rx, current_time, period);
result = HRTIMER_RESTART;
}
return result;
}
/**
* Adds a given (received) character to the RX buffer, which is managed by the kernel,
* and then flushes (flip) it.
* @param character given character
*/
void receive_character(unsigned char character)
{
mutex_lock(¤t_tty_mutex);
if (rx_callback != NULL) {
(*rx_callback)(character);
} else {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
if (current_tty != NULL && current_tty->port != NULL)
{
tty_insert_flip_char(current_tty->port, character, TTY_NORMAL);
tty_flip_buffer_push(current_tty->port);
}
#else
if (tty != NULL)
{
tty_insert_flip_char(current_tty, character, TTY_NORMAL);
tty_flip_buffer_push(tty);
}
#endif
}
mutex_unlock(¤t_tty_mutex);
}
Crash details:
[2019-11-23 21:58:12] ------------[ cut here ]------------
[2019-11-23 21:58:12] WARNING: CPU: 1 PID: 707 at /home/shalin/Documents/mainboard_src/yocto/core-image-base/linux_src/kernel/time/h)
[2019-11-23 21:58:12] Modules linked in: brcmfmac brcmutil usb_f_ecm g_ether usb_f_rndis u_ether libcomposite soft_uart bt8xxx(O) sd8xxx(O) mlan(PO) cfg80211
[2019-11-23 21:58:12] CPU: 1 PID: 707 Comm: hw_watchdog Tainted: P O 4.1.15-2.0.0-ga+yocto+g83728b9 #4
[2019-11-23 21:58:12] Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree)
[2019-11-23 21:58:12] Backtrace:
[2019-11-23 21:58:12] [<8010c358>] (dump_backtrace) from [<8010c5d4>] (show_stack+0x20/0x24)
[2019-11-23 21:58:12] r7:80190514 r6:80e45ca0 r5:00000000 r4:80e45ca0
[2019-11-23 21:58:12] [<8010c5b4>] (show_stack) from [<80923a58>] (dump_stack+0x7c/0xbc)
[2019-11-23 21:58:12] [<809239dc>] (dump_stack) from [<80133844>] (warn_slowpath_common+0x94/0xc4)
[2019-11-23 21:58:12] r7:80190514 r6:000004ce r5:00000009 r4:00000000
[2019-11-23 21:58:12] [<801337b0>] (warn_slowpath_common) from [<80133978>] (warn_slowpath_null+0x2c/0x34)
[2019-11-23 21:58:12] r8:00000001 r7:ab72e3c0 r6:ab72e3f8 r5:00005e38 r4:7f19e2a8
[2019-11-23 21:58:12] [<8013394c>] (warn_slowpath_null) from [<80190514>] (__run_hrtimer+0x248/0x294)
[2019-11-23 21:58:12] [<801902cc>] (__run_hrtimer) from [<8019096c>] (hrtimer_interrupt+0x138/0x344)
[2019-11-23 21:58:12] r9:00000001 r8:ab72e3c0 r7:00000000 r6:ab72e3f8 r5:00005e38 r4:be670b5f
[2019-11-23 21:58:12] [<80190834>] (hrtimer_interrupt) from [<80110d24>] (twd_handler+0x40/0x50)
[2019-11-23 21:58:12] r10:80e46000 r9:a8006d80 r8:00000001 r7:00000010 r6:a8035340 r5:ab7344c0
[2019-11-23 21:58:12] r4:00000001
[2019-11-23 21:58:12] [<80110ce4>] (twd_handler) from [<80180574>] (handle_percpu_devid_irq+0xac/0x1d0)
[2019-11-23 21:58:12] r5:ab7344c0 r4:00000010
[2019-11-23 21:58:12] [<801804c8>] (handle_percpu_devid_irq) from [<8017bbdc>] (generic_handle_irq+0x3c/0x4c)
[2019-11-23 21:58:12] r10:a872bcc0 r9:a8020000 r8:00000001 r7:00000000 r6:00000010 r5:00000000
[2019-11-23 21:58:12] r4:00000010 r3:801804c8
[2019-11-23 21:58:12] [<8017bba0>] (generic_handle_irq) from [<8017bf08>] (__handle_domain_irq+0x8c/0xfc)
[2019-11-23 21:58:12] r5:00000000 r4:80d9ac34
[2019-11-23 21:58:12] [<8017be7c>] (__handle_domain_irq) from [<80101560>] (gic_handle_irq+0x34/0x6c)
[2019-11-23 21:58:12] r10:000033d4 r9:00000000 r8:00000006 r7:f4a00100 r6:a872bcc0 r5:80e02f7c
[2019-11-23 21:58:12] r4:f4a0010c r3:a872bcc0
[2019-11-23 21:58:12] [<8010152c>] (gic_handle_irq) from [<8010d240>] (__irq_svc+0x40/0x74)
[2019-11-23 21:58:12] Exception stack(0xa872bcc0 to 0xa872bd08)
[2019-11-23 21:58:12] bcc0: 00000001 80000093 00000001 20000013 80ea5eb0 00000002 0000002b 80ed14a8
[2019-11-23 21:58:12] bce0: 00000006 00000000 000033d4 a872bd5c a872bc58 a872bd08 809296d8 8017a7a0
[2019-11-23 21:58:12] bd00: 60000013 ffffffff
[2019-11-23 21:58:12] r7:a872bcf4 r6:ffffffff r5:60000013 r4:8017a7a0
[2019-11-23 21:58:12] [<8017a468>] (console_unlock) from [<8017abdc>] (vprintk_emit+0x2ac/0x50c)
[2019-11-23 21:58:12] r10:00000000 r9:00000000 r8:00000000 r7:80e915a8 r6:80ed1efc r5:0000002a
[2019-11-23 21:58:12] r4:00000001
[2019-11-23 21:58:12] [<8017a930>] (vprintk_emit) from [<8056a758>] (dev_vprintk_emit+0xc0/0x1f8)
[2019-11-23 21:58:12] r10:a872bebc r9:80c0543c r8:80c36ab0 r7:a872bde4 r6:a8512200 r5:80e02508
[2019-11-23 21:58:12] r4:00000013
[2019-11-23 21:58:12] [<8056a698>] (dev_vprintk_emit) from [<8056a8d0>] (dev_printk_emit+0x40/0x5c)
[2019-11-23 21:58:12] r10:a86dc788 r9:00000008 r8:00000000 r7:a602bc38 r6:a849649c r5:a84964b4
[2019-11-23 21:58:12] r4:80e02508
[2019-11-23 21:58:12] [<8056a894>] (dev_printk_emit) from [<8056ac40>] (__dev_printk+0x58/0x98)
[2019-11-23 21:58:12] r3:80c36ab0 r2:80c0543c
[2019-11-23 21:58:12] r4:80e02508
[2019-11-23 21:58:12] [<8056abe8>] (__dev_printk) from [<8056ae28>] (dev_crit+0x58/0x74)
[2019-11-23 21:58:12] [<8056add4>] (dev_crit) from [<806b9f0c>] (watchdog_release+0xd4/0xd8)
[2019-11-23 21:58:12] r3:00000003 r2:00000000 r1:80c36b18
[2019-11-23 21:58:12] r4:a8496434
[2019-11-23 21:58:12] [<806b9e38>] (watchdog_release) from [<8024ce80>] (__fput+0x90/0x1e0)
[2019-11-23 21:58:12] r7:a602bc38 r6:a8534850 r5:a84e8da8 r4:a86dc780
[2019-11-23 21:58:12] [<8024cdf0>] (__fput) from [<8024d040>] (____fput+0x18/0x1c)
[2019-11-23 21:58:12] r10:00000000 r9:a872a000 r8:80108124 r7:a8b27700 r6:80e90f20 r5:00000000
[2019-11-23 21:58:12] r4:a8b27b18
[2019-11-23 21:58:12] [<8024d028>] (____fput) from [<8014f834>] (task_work_run+0xc0/0xf8)
[2019-11-23 21:58:12] [<8014f774>] (task_work_run) from [<8010bbd8>] (do_work_pending+0x8c/0xb4)
[2019-11-23 21:58:12] r7:00000006 r6:a872bfb0 r5:80108124 r4:a872a000
[2019-11-23 21:58:12] [<8010bb4c>] (do_work_pending) from [<80107fcc>] (work_pending+0xc/0x20)
[2019-11-23 21:58:12] r7:00000006 r6:00010a78 r5:00000004 r4:00000001
[2019-11-23 21:58:12] ---[ end trace 4de5a0751e851227 ]---