* 3.8.0-rc3: possible circular locking dependency: &tty->legacy_mutex / &tty->hangup_work with serial/RFCOMM connection via USB bluetooth dongle
From: Sander Eikelenboom @ 2013-01-12 18:46 UTC (permalink / raw)
To: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-serial-u79uwXL29TY76Z2rM5mHXA,
linux-bluetooth-u79uwXL29TY76Z2rM5mHXA
Cc: Alan Cox, Greg Kroah-Hartman, marcel-kz+m5ild9QBg9hUCZPvPmw
Hi,
Running a 3.8.0-rc3 kernel (latest commit b719f43059903820c31edb30f4663a2818836e7f) kernel (debian squeeze os), i'm running into this lockdep warning when:
- Running a perl script that uses rfcomm to communicatie via bluetooth with a bluetooth/TTL converter.
- It can run ok for a few hours before this lockdep occurs and the perl script freezes.
- The info related to bluetooth from syslog:
Jan 12 10:24:08 serveerstertje kernel: [ 7.919775] Bluetooth: Virtual HCI driver ver 1.3
Jan 12 10:24:08 serveerstertje kernel: [ 7.920314] Bluetooth: HCI UART driver ver 2.2
Jan 12 10:24:08 serveerstertje kernel: [ 7.920316] Bluetooth: HCI H4 protocol initialized
Jan 12 10:24:08 serveerstertje kernel: [ 7.920317] Bluetooth: HCI BCSP protocol initialized
Jan 12 10:24:08 serveerstertje kernel: [ 7.920318] Bluetooth: HCILL protocol initialized
Jan 12 10:24:08 serveerstertje kernel: [ 7.920318] Bluetooth: HCIATH3K protocol initialized
Jan 12 10:24:08 serveerstertje kernel: [ 7.920319] Bluetooth: HCI Three-wire UART (H5) protocol initialized
Jan 12 10:24:08 serveerstertje kernel: [ 8.191897] Bluetooth: RFCOMM TTY layer initialized
Jan 12 10:24:08 serveerstertje kernel: [ 8.191930] Bluetooth: RFCOMM socket layer initialized
Jan 12 10:24:08 serveerstertje kernel: [ 8.191931] Bluetooth: RFCOMM ver 1.11
Jan 12 10:24:08 serveerstertje kernel: [ 8.191932] Bluetooth: BNEP (Ethernet Emulation) ver 1.3
Jan 12 10:24:08 serveerstertje kernel: [ 8.191933] Bluetooth: BNEP filters: protocol multicast
Jan 12 10:24:08 serveerstertje kernel: [ 8.191944] Bluetooth: BNEP socket layer initialized
Jan 12 10:24:08 serveerstertje kernel: [ 8.191945] Bluetooth: HIDP (Human Interface Emulation) ver 1.2
Jan 12 10:24:08 serveerstertje kernel: [ 8.191954] Bluetooth: HIDP socket layer initialized
Jan 12 10:24:09 serveerstertje bluetoothd[3912]: Bluetooth deamon 4.66
Jan 12 10:24:09 serveerstertje bluetoothd[3912]: Starting SDP server
Jan 12 10:24:09 serveerstertje bluetoothd[3912]: Starting experimental netlink support
Jan 12 10:24:09 serveerstertje bluetoothd[3912]: Failed to find Bluetooth netlink family
Jan 12 10:24:09 serveerstertje bluetoothd[3912]: Failed to init netlink plugin
Jan 12 10:24:09 serveerstertje bluetoothd[3912]: bridge pan0 created
Jan 12 10:24:09 serveerstertje bluetoothd[3912]: HCI dev 0 registered
Jan 12 10:24:09 serveerstertje bluetoothd[3912]: Failed to open RFKILL control device
Jan 12 10:24:09 serveerstertje bluetoothd[3912]: HCI dev 0 up
Jan 12 10:24:09 serveerstertje bluetoothd[3912]: Starting security manager 0
Jan 12 10:24:09 serveerstertje bluetoothd[3912]: Adapter /org/bluez/3912/hci0 has been enabled
Jan 12 10:24:09 serveerstertje bluetoothd[3912]: Failed to access HAL
- And the lockdep warning itself:
[28678.458250]
[28678.476588] ======================================================
[28678.494887] [ INFO: possible circular locking dependency detected ]
[28678.513013] 3.8.0-rc3-20130112-netpatched-rocketscience-radeon #1 Not tainted
[28678.530909] -------------------------------------------------------
[28678.548636] kworker/2:1/19513 is trying to acquire lock:
[28678.566070] (&tty->legacy_mutex){+.+.+.}, at: [<ffffffff819ba5ee>] tty_lock_nested+0x3e/0x80
[28678.583577]
[28678.583577] but task is already holding lock:
[28678.617615] ((&tty->hangup_work)){+.+...}, at: [<ffffffff81080bf8>] process_one_work+0x158/0x4b0
[28678.634569]
[28678.634569] which lock already depends on the new lock.
[28678.634569]
[28678.683868]
[28678.683868] the existing dependency chain (in reverse order) is:
[28678.715354]
[28678.715354] -> #2 ((&tty->hangup_work)){+.+...}:
[28678.745890] [<ffffffff810b4d2e>] __lock_acquire+0x44e/0xdd0
[28678.760975] [<ffffffff810b576a>] lock_acquire+0xba/0x100
[28678.775834] [<ffffffff8108322a>] flush_work+0x3a/0x250
[28678.790408] [<ffffffff81451568>] tty_ldisc_flush_works+0x18/0x40
[28678.804877] [<ffffffff814517ae>] tty_ldisc_release+0x2e/0x90
[28678.818952] [<ffffffff8144b827>] tty_release+0x3c7/0x590
[28678.832813] [<ffffffff8114e009>] __fput+0xa9/0x2c0
[28678.846411] [<ffffffff8114e289>] ____fput+0x9/0x10
[28678.859644] [<ffffffff810854d5>] task_work_run+0x95/0xb0
[28678.872661] [<ffffffff8100dc4d>] do_notify_resume+0x6d/0x80
[28678.885516] [<ffffffff819bb5a2>] int_signal+0x12/0x17
[28678.898047]
[28678.898047] -> #1 (&tty->legacy_mutex/1){+.+...}:
[28678.922334] [<ffffffff810b4d2e>] __lock_acquire+0x44e/0xdd0
[28678.934268] [<ffffffff810b576a>] lock_acquire+0xba/0x100
[28678.945916] [<ffffffff819b754c>] mutex_lock_nested+0x4c/0x450
[28678.957318] [<ffffffff819ba5ee>] tty_lock_nested+0x3e/0x80
[28678.968500] [<ffffffff819ba6aa>] tty_lock_pair+0x6a/0x70
[28678.979405] [<ffffffff8144b5cb>] tty_release+0x16b/0x590
[28678.990012] [<ffffffff8114e009>] __fput+0xa9/0x2c0
[28679.000367] [<ffffffff8114e289>] ____fput+0x9/0x10
[28679.009455] FW: BLOCKED low udp input: IN=eth0 OUT= MAC=40:61:86:f4:67:d9:00:08:ae:10:46:60:08:00 SRC=112.203.174.221 DST=88.159.69.252 LEN=131 TOS=0x00 PREC=0x00 TTL=38 ID=17898 PROTO=UDP SPT=27001 DPT=1024 LEN=111
[28679.030869] [<ffffffff810854d5>] task_work_run+0x95/0xb0
[28679.040727] [<ffffffff8100dc4d>] do_notify_resume+0x6d/0x80
[28679.050419] [<ffffffff819bb5a2>] int_signal+0x12/0x17
[28679.059880]
[28679.059880] -> #0 (&tty->legacy_mutex){+.+.+.}:
[28679.077823] [<ffffffff810b41d8>] validate_chain+0x1258/0x1300
[28679.086583] [<ffffffff810b4d2e>] __lock_acquire+0x44e/0xdd0
[28679.095126] [<ffffffff810b576a>] lock_acquire+0xba/0x100
[28679.103399] [<ffffffff819b754c>] mutex_lock_nested+0x4c/0x450
[28679.111468] [<ffffffff819ba5ee>] tty_lock_nested+0x3e/0x80
[28679.119247] [<ffffffff819ba63b>] tty_lock+0xb/0x10
[28679.126712] [<ffffffff814492b5>] __tty_hangup+0x65/0x3c0
[28679.133940] [<ffffffff81449620>] do_tty_hangup+0x10/0x20
[28679.140970] [<ffffffff81080c60>] process_one_work+0x1c0/0x4b0
[28679.147755] [<ffffffff8108134e>] worker_thread+0x11e/0x3d0
[28679.154383] [<ffffffff81088a36>] kthread+0xd6/0xe0
[28679.160649] [<ffffffff819bb1bc>] ret_from_fork+0x7c/0xb0
[28679.166666]
[28679.166666] other info that might help us debug this:
[28679.166666]
[28679.183748] Chain exists of:
[28679.183748] &tty->legacy_mutex --> &tty->legacy_mutex/1 --> (&tty->hangup_work)
[28679.183748]
[28679.200495] Possible unsafe locking scenario:
[28679.200495]
[28679.211416] CPU0 CPU1
[28679.216751] ---- ----
[28679.222049] lock((&tty->hangup_work));
[28679.227206] lock(&tty->legacy_mutex/1);
[28679.232380] lock((&tty->hangup_work));
[28679.237532] lock(&tty->legacy_mutex);
[28679.242673]
[28679.242673] *** DEADLOCK ***
[28679.242673]
[28679.257840] 2 locks held by kworker/2:1/19513:
[28679.262888] #0: (events){.+.+.+}, at: [<ffffffff81080bf8>] process_one_work+0x158/0x4b0
[28679.268053] #1: ((&tty->hangup_work)){+.+...}, at: [<ffffffff81080bf8>] process_one_work+0x158/0x4b0
[28679.273381]
[28679.273381] stack backtrace:
[28679.283820] Pid: 19513, comm: kworker/2:1 Not tainted 3.8.0-rc3-20130112-netpatched-rocketscience-radeon #1
[28679.289347] Call Trace:
[28679.294804] [<ffffffff810b2c74>] print_circular_bug+0x204/0x300
[28679.300384] [<ffffffff810b41d8>] validate_chain+0x1258/0x1300
[28679.305997] [<ffffffff810b4d2e>] __lock_acquire+0x44e/0xdd0
[28679.311599] [<ffffffff810b4d4b>] ? __lock_acquire+0x46b/0xdd0
[28679.317222] [<ffffffff810b576a>] lock_acquire+0xba/0x100
[28679.322889] [<ffffffff819ba5ee>] ? tty_lock_nested+0x3e/0x80
[28679.328481] [<ffffffff819ba5ee>] ? tty_lock_nested+0x3e/0x80
[28679.334023] [<ffffffff819b754c>] mutex_lock_nested+0x4c/0x450
[28679.339415] [<ffffffff819ba5ee>] ? tty_lock_nested+0x3e/0x80
[28679.344784] [<ffffffff810b5788>] ? lock_acquire+0xd8/0x100
[28679.350154] [<ffffffff81449279>] ? __tty_hangup+0x29/0x3c0
[28679.355506] [<ffffffff819ba5ee>] tty_lock_nested+0x3e/0x80
[28679.360939] [<ffffffff819ba63b>] tty_lock+0xb/0x10
[28679.366282] [<ffffffff814492b5>] __tty_hangup+0x65/0x3c0
[28679.371651] [<ffffffff81080bf8>] ? process_one_work+0x158/0x4b0
[28679.377032] [<ffffffff810b1918>] ? trace_hardirqs_on_caller+0xf8/0x200
[28679.382273] [<ffffffff81449620>] do_tty_hangup+0x10/0x20
[28679.387216] [<ffffffff81080c60>] process_one_work+0x1c0/0x4b0
[28679.392118] [<ffffffff81080bf8>] ? process_one_work+0x158/0x4b0
[28679.397039] [<ffffffff81449610>] ? __tty_hangup+0x3c0/0x3c0
[28679.401952] [<ffffffff8108134e>] worker_thread+0x11e/0x3d0
[28679.406859] [<ffffffff810b1918>] ? trace_hardirqs_on_caller+0xf8/0x200
[28679.411787] [<ffffffff81081230>] ? manage_workers+0x2e0/0x2e0
[28679.416683] [<ffffffff81088a36>] kthread+0xd6/0xe0
[28679.421538] [<ffffffff81088960>] ? __init_kthread_worker+0x70/0x70
[28679.426429] [<ffffffff819bb1bc>] ret_from_fork+0x7c/0xb0
[28679.431278] [<ffffffff81088960>] ? __init_kthread_worker+0x70/0x70
- This is followed by blocked task messages for the perl script:
Jan 12 18:25:29 serveerstertje kernel: [28926.144229] INFO: task zabbix_slimmeme:26976 blocked for more than 120 seconds.
Jan 12 18:25:29 serveerstertje kernel: [28926.162883] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
Jan 12 18:25:29 serveerstertje kernel: [28926.181312] zabbix_slimmeme D ffff88003851d230 0 26976 22112 0x00000000
Jan 12 18:25:29 serveerstertje kernel: [28926.199596] ffff88002d473818 0000000000000216 ffff880000000002 ffffffff8202be38
Jan 12 18:25:29 serveerstertje kernel: [28926.217728] ffff88003851d230 0000000000013040 ffff88002d473fd8 ffff88002d472010
Jan 12 18:25:29 serveerstertje kernel: [28926.235627] 0000000000013040 0000000000013040 ffff88002d473fd8 0000000000013040
Jan 12 18:25:29 serveerstertje kernel: [28926.253346] Call Trace:
Jan 12 18:25:29 serveerstertje kernel: [28926.270648] [<ffffffff810be1ed>] ? __module_text_address+0xd/0x60
Jan 12 18:25:29 serveerstertje kernel: [28926.322462] [<ffffffff810be1ed>] ? __module_text_address+0xd/0x60
Jan 12 18:25:29 serveerstertje kernel: [28926.339617] [<ffffffff810be44b>] ? is_module_text_address+0x2b/0x60
Jan 12 18:25:29 serveerstertje kernel: [28926.356452] [<ffffffff81085958>] ? __kernel_text_address+0x58/0x80
Jan 12 18:25:29 serveerstertje kernel: [28926.373057] [<ffffffff81140049>] ? sysfs_slab_add+0x149/0x200
Jan 12 18:25:29 serveerstertje kernel: [28926.389435] [<ffffffff81140067>] ? sysfs_slab_add+0x167/0x200
Jan 12 18:25:29 serveerstertje kernel: [28926.405516] [<ffffffff819b8d04>] schedule+0x24/0x70
Jan 12 18:25:29 serveerstertje kernel: [28926.421242] [<ffffffff819b5f6d>] schedule_timeout+0x1bd/0x220
Jan 12 18:25:29 serveerstertje kernel: [28926.436793] [<ffffffff810b5788>] ? lock_acquire+0xd8/0x100
Jan 12 18:25:29 serveerstertje kernel: [28926.452138] [<ffffffff819b8201>] ? wait_for_common+0x31/0x170
Jan 12 18:25:29 serveerstertje kernel: [28926.467171] [<ffffffff810b5c17>] ? lock_release+0x117/0x250
Jan 12 18:25:29 serveerstertje kernel: [28926.481938] [<ffffffff819b82d1>] wait_for_common+0x101/0x170
Jan 12 18:25:29 serveerstertje kernel: [28926.496482] [<ffffffff81098730>] ? try_to_wake_up+0x310/0x310
Jan 12 18:25:29 serveerstertje kernel: [28926.510873] [<ffffffff819b83e8>] wait_for_completion+0x18/0x20
Jan 12 18:25:29 serveerstertje kernel: [28926.525014] [<ffffffff81083385>] flush_work+0x195/0x250
Jan 12 18:25:29 serveerstertje kernel: [28926.538855] [<ffffffff810833a0>] ? flush_work+0x1b0/0x250
Jan 12 18:25:29 serveerstertje kernel: [28926.552411] [<ffffffff81080400>] ? cwq_dec_nr_in_flight+0xd0/0xd0
Jan 12 18:25:29 serveerstertje kernel: [28926.565910] [<ffffffff81451568>] tty_ldisc_flush_works+0x18/0x40
Jan 12 18:25:29 serveerstertje kernel: [28926.579013] [<ffffffff814517ae>] tty_ldisc_release+0x2e/0x90
Jan 12 18:25:29 serveerstertje kernel: [28926.591876] [<ffffffff8144b827>] tty_release+0x3c7/0x590
Jan 12 18:25:29 serveerstertje kernel: [28926.604527] [<ffffffff810b1a2d>] ? trace_hardirqs_on+0xd/0x10
Jan 12 18:25:29 serveerstertje kernel: [28926.616853] [<ffffffff819b63a9>] ? __mutex_unlock_slowpath+0x149/0x1d0
Jan 12 18:25:29 serveerstertje kernel: [28926.628997] [<ffffffff81098730>] ? try_to_wake_up+0x310/0x310
Jan 12 18:25:29 serveerstertje kernel: [28926.640952] [<ffffffff8144bdb4>] tty_open+0x3c4/0x5f0
Jan 12 18:25:30 serveerstertje kernel: [28926.652584] [<ffffffff81150a18>] chrdev_open+0x98/0x170
Jan 12 18:25:30 serveerstertje kernel: [28926.663972] [<ffffffff810912cd>] ? lg_local_unlock+0x3d/0x70
Jan 12 18:25:30 serveerstertje kernel: [28926.675152] [<ffffffff81150980>] ? cdev_put+0x30/0x30
Jan 12 18:25:30 serveerstertje kernel: [28926.686173] [<ffffffff8114b1fe>] do_dentry_open+0x25e/0x310
Jan 12 18:25:30 serveerstertje kernel: [28926.696868] [<ffffffff8114b3c0>] finish_open+0x30/0x50
Jan 12 18:25:30 serveerstertje kernel: [28926.707267] [<ffffffff8115a79e>] do_last+0x30e/0xe90
Jan 12 18:25:30 serveerstertje kernel: [28926.717404] [<ffffffff81157aba>] ? link_path_walk+0x9a/0x9f0
Jan 12 18:25:30 serveerstertje kernel: [28926.727353] [<ffffffff8115b3ce>] path_openat+0xae/0x4e0
Jan 12 18:25:30 serveerstertje kernel: [28926.737008] [<ffffffff810b5c17>] ? lock_release+0x117/0x250
Jan 12 18:25:30 serveerstertje kernel: [28926.746482] [<ffffffff81160264>] ? do_select+0x5f4/0x6d0
Jan 12 18:25:30 serveerstertje kernel: [28926.755613] [<ffffffff8115b934>] do_filp_open+0x44/0xa0
Jan 12 18:25:30 serveerstertje kernel: [28926.764542] [<ffffffff811691e3>] ? __alloc_fd+0xb3/0x150
Jan 12 18:25:30 serveerstertje kernel: [28926.773224] [<ffffffff8114ad13>] do_sys_open+0x103/0x1f0
Jan 12 18:25:30 serveerstertje kernel: [28926.781585] [<ffffffff8114ae3c>] sys_open+0x1c/0x20
Jan 12 18:25:30 serveerstertje kernel: [28926.789685] [<ffffffff819bb269>] system_call_fastpath+0x16/0x1b
Jan 12 18:25:30 serveerstertje kernel: [28926.797570] INFO: lockdep is turned off.
^ permalink raw reply
* Warning about not setting tty->port: what to set it to?
From: Grant Edwards @ 2013-01-11 20:34 UTC (permalink / raw)
To: linux-serial
I maintain a serial card driver which, starting with kernel 3.7,
produces this warning when a port is opened:
tty_init_dev: ttyXYZ driver does not set tty->port. This will crash the kernel later. Fix the driver!
The driver still seems to work fine, but apparently I shouldn't expect
it to continue to do so.
What am I supposed to set tty->port _to_ ?
Obviously, it's supposed to point to an instance of the type (struct tty_port).
Is there somewhere in particular I'm supposed to get that structure
instance from?
Am I supposed to allocate/clear one when the port is opened and free
it when the port is closed? Or does the contents the structure
pointed to by tty->port need to be preserved?
Am I expected to do anything with the contents of that structure?
Or am I just providing some storage space for use by the tty layer
code?
--
Grant Edwards grant.b.edwards Yow! I'm young ... I'm
at HEALTHY ... I can HIKE
gmail.com THRU CAPT GROGAN'S LUMBAR
REGIONS!
^ permalink raw reply
* Re: [PATCH 4/4] serial/arc-uart: switch to devicetree based probing
From: Arnd Bergmann @ 2013-01-11 20:17 UTC (permalink / raw)
To: Vineet Gupta
Cc: linux-serial, linux-kernel, Grant Likely, Alan Cox,
Greg Kroah-Hartman, devicetree-discuss, Rob Herring, Rob Landley
In-Reply-To: <50EFFDAA.6060204@synopsys.com>
On Friday 11 January 2013, Vineet Gupta wrote:
> On Friday 11 January 2013 05:03 PM, Arnd Bergmann wrote:
> > Quick question about the name though: is this UART only used
> > on ARC, or is it something that synopsys licenses to other
> > parties as well? If the latter is true, we might want to
> > add a more generic "compatible" value for those that use
> > it on another architecture.
>
> It's not licensed as standalone IP - since its not a standard 8250. It is only
> (but actively) used on the internal FPGA flows from ARC days.
>
Ok, thanks for the confirmation.
Arnd
^ permalink raw reply
* Re: [PATCH] ARM: PL011: Add support for Rx DMA buffer polling
From: Linus Walleij @ 2013-01-11 18:34 UTC (permalink / raw)
To: Chanho Min
Cc: Alan Cox, Russell King, Greg Kroah-Hartman, linux-kernel,
linux-serial, Pawel Moll
In-Reply-To: <50efad8d.84fc440a.589e.ffff9546SMTPIN_ADDED_BROKEN@mx.google.com>
On Fri, Jan 11, 2013 at 7:13 AM, Chanho Min <chanho.min@lge.com> wrote:
> In DMA support, Received data is not triggered until the DMA buffer is filled.
Interesting! As you can see in commits:
commit ead76f329f777c7301e0a5456a0a1c7a081570bd
"ARM: 6763/1: pl011: add optional RX DMA to PL011 v2"
commit 5d7b8467e18b14ed44c5781d77993bfdcd8c826b
"mach-ux500: config Ux500 PL011 PL022 PL180 for DMA"
commit ec8f12533b4a439a8feb0d1a3bf15516781804be
"mach-u300: config U300 PL180 PL011 PL022 for DMA"
We have enabled RX DMA for Ux500 and U300.
It does work on our machines, I'm using it every day
and deploying the ux500 systems in the millions.
Let's recap how this can work for us. As you can see, when
using DMA we turn off UART011_RXIM and instead rely on
either:
1) DMA completes and we read in the entire buffer to
the TTY
or
2) UART011_RTIM (recieve timeout) to happen. This is a
timeout that need to be set low enough so that interactivity
on a console will not be hampered.
Apparently this timeout cannot be configured on the ARM
variants while the ST variant has a register for that (which
is currently unused.)
The amazing thing is that we're using this. We're getting
timeouts, so the small set of characters in the FIFO on
an interactive console is polled perfectly.
This even works on the U300, which has the ARM version
of the PL011 and I have once tested it on the RealView
PB11MPcore (the only reference design with a working
PL08x DMA controller) and it worked on that system
as well.
As we've discussed before, in order for this to work,
the PL011 refman says:
----------8<------------------8<-----------------
UARTRXDMASREQ
Single character DMA transfer request, asserted by the UART.
For receive, one character consists of up to 12 bits. This signal
is asserted when the receive FIFO contains at least one character.
UARTRXDMABREQ
Burst DMA transfer request, asserted by the UART. This
signal is asserted when the receive FIFO contains more
characters than the programmed watermark level. You can
program the watermark level for each FIFO through the
UARTIFLS register.
UARTRXDMACLR
DMA request clear, asserted by the DMA controller to clear
the receive request signals. If DMA burst transfer is
requested, the clear signal is asserted during the transfer of
the last data in the burst.
----------8<------------------8<-----------------
We were worried that DMA would suck out characters
of the FIFO so quickly that it would never contain the
one character necessary to trigger the timeout, so that
we would read out the data from the DMA page, due
to this part of the refman:
----------8<------------------8<-----------------
UARTRTINTR
The receive timeout interrupt is asserted when the receive FIFO is
not empty, and no further data is received over a 32-bit period. The
receive timeout interrupt is cleared either when the FIFO becomes
empty through reading all the data (or by reading the holding register),
or when a 1 is written to the corresponding bit of the UARTICR
register.
----------8<------------------8<-----------------
The crucial part is "FIFO is not empty" - when using DMA
the FIFO will of course be empty, as DMA is sucking out
anything immediately. See this discussion:
http://comments.gmane.org/gmane.linux.ports.arm.kernel/92513
But when I tried it out in practice, it must be
wired differently or contain some VHDL hacks, because it
worked like a charm. I got the timeout IRQs and all. I never
managed to get it to fail. Sadly I don't have the VHDL code
for the PL011 so I cannot confirm how they (ARMs
IP core engineers) solved this. (Paging Pawel on this.)
So I suspect that maybe your DMA controller is badly
configured, or erroneous, atleast if this is a stock PL011:
- What DMA controller are you using with the
PL011?
- How are the burst lines configured in the DMA
controller? (This is often a platform-specific
property.) Did you make sure both single and burst
request lines are enabled? If only burst is enabled
you will get *exactly* the phenomena you are trying
to work around above...
- If they cannot be software-configured, how are
they then configured in hardware? Burst-only?
Yours,
Linus Walleij
^ permalink raw reply
* Re: [PATCH] ARM: PL011: Add support for Rx DMA buffer polling
From: Russell King - ARM Linux @ 2013-01-11 16:18 UTC (permalink / raw)
To: Chanho Min
Cc: 'Alan Cox', 'Greg Kroah-Hartman',
'Linus Walleij', linux-kernel, linux-serial
In-Reply-To: <006c01cdefc2$c7e1cb90$57a562b0$@min@lge.com>
On Fri, Jan 11, 2013 at 03:13:31PM +0900, Chanho Min wrote:
> In DMA support, Received data is not triggered until the DMA buffer is filled.
> In order to actually use Rx DMA, We would like to suggest the use of the timer
> for polling DMA buffer. It makes possible character-level trigger.
> In our test, no data loss occurred at high-baudrate as compared with interrupt
> driven (We tested with 3Mbps). We know it will be because of the increased Rx
> buffer rather than DMA effect. but,It is very useful for high speed uart device.
> We changes:
>
> - CONFIG_SERIAL_AMBA_PL011_DMAPOLL is added to select this feature.
>
> - add timer and last_residue for polling. Every polling, timer handler checks
> the residue in the dma buffer and transfer data to the tty. Also, last_residue
> is updated for the next polling.
>
> - We use consistent DMA mappings instead of streaming DMA mappings to avoid from
> the frequent cache operation.
>
> - pl011_dma_rx_chars is modified. the pending size is recalculated because data
> can be taken by polling.
>
> - add module parameter for adjusting polling interval.
Here's the question: what is the effect of having to poll every tick on
the overall system?
What I'm getting at is: what is the cost of that polling with DMA enabled
over not having DMA on the receive side at all? What is the trade-off
vs baud rate? Should we scale the polling interval according to baud
rate?
^ permalink raw reply
* Re: [PATCH 4/4] serial/arc-uart: switch to devicetree based probing
From: Vineet Gupta @ 2013-01-11 11:55 UTC (permalink / raw)
To: Arnd Bergmann
Cc: linux-serial, linux-kernel, Grant Likely, Alan Cox,
Greg Kroah-Hartman, devicetree-discuss, Rob Herring, Rob Landley
In-Reply-To: <201301111133.43507.arnd@arndb.de>
On Friday 11 January 2013 05:03 PM, Arnd Bergmann wrote:
> On Friday 11 January 2013, Vineet Gupta wrote:
>> * DT binding for arc-uart
>> * With alll the bits in place we can now use DT probing.
>>
>> Note that there's a bit of kludge right now because earlyprintk portion
>> of driver can't use the DT infrastrcuture to get resoures/plat_data.
>> This requires some infrastructre changes to of_flat_ framework
>>
>> Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
>> Cc: Grant Likely <grant.likely@secretlab.ca>
>> Cc: Arnd Bergmann <arnd@arndb.de>
>> Cc: linux-serial@vger.kernel.org
>> Cc: Alan Cox <alan@linux.intel.com>
>> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
>> Cc: devicetree-discuss@lists.ozlabs.org
>> Cc: Rob Herring <rob.herring@calxeda.com>
>> Cc: Rob Landley <rob@landley.net>
>> Cc: linux-serial@vger.kernel.org
> Acked-by: Arnd Bergmann <arnd@arndb.de>
>
> Quick question about the name though: is this UART only used
> on ARC, or is it something that synopsys licenses to other
> parties as well? If the latter is true, we might want to
> add a more generic "compatible" value for those that use
> it on another architecture.
It's not licensed as standalone IP - since its not a standard 8250. It is only
(but actively) used on the internal FPGA flows from ARC days.
Thx,
Vineet
> Arnd
^ permalink raw reply
* Re: [PATCH 4/4] serial/arc-uart: switch to devicetree based probing
From: Arnd Bergmann @ 2013-01-11 11:33 UTC (permalink / raw)
To: Vineet Gupta
Cc: linux-serial, linux-kernel, Grant Likely, Alan Cox,
Greg Kroah-Hartman, devicetree-discuss, Rob Herring, Rob Landley
In-Reply-To: <1357885223-19243-5-git-send-email-vgupta@synopsys.com>
On Friday 11 January 2013, Vineet Gupta wrote:
> * DT binding for arc-uart
> * With alll the bits in place we can now use DT probing.
>
> Note that there's a bit of kludge right now because earlyprintk portion
> of driver can't use the DT infrastrcuture to get resoures/plat_data.
> This requires some infrastructre changes to of_flat_ framework
>
> Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
> Cc: Grant Likely <grant.likely@secretlab.ca>
> Cc: Arnd Bergmann <arnd@arndb.de>
> Cc: linux-serial@vger.kernel.org
> Cc: Alan Cox <alan@linux.intel.com>
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Cc: devicetree-discuss@lists.ozlabs.org
> Cc: Rob Herring <rob.herring@calxeda.com>
> Cc: Rob Landley <rob@landley.net>
> Cc: linux-serial@vger.kernel.org
Acked-by: Arnd Bergmann <arnd@arndb.de>
Quick question about the name though: is this UART only used
on ARC, or is it something that synopsys licenses to other
parties as well? If the latter is true, we might want to
add a more generic "compatible" value for those that use
it on another architecture.
Arnd
^ permalink raw reply
* [PATCH 2/4] serial/arc-uart: split probe from probe_earlyprintk
From: Vineet Gupta @ 2013-01-11 6:20 UTC (permalink / raw)
To: linux-serial, linux-kernel
Cc: Vineet Gupta, Alan Cox, Greg Kroah-Hartman, Jiri Slaby
In-Reply-To: <1357885223-19243-1-git-send-email-vgupta@synopsys.com>
This is in preparation for devicetree based probing, where earlyprintk
won't have access to DT serial aliases which the normal probe would
absolutely rely on.
Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
Cc: Alan Cox <alan@linux.intel.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: linux-serial@vger.kernel.org
---
drivers/tty/serial/arc_uart.c | 21 +++++++++++----------
1 files changed, 11 insertions(+), 10 deletions(-)
diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c
index 8089dc3..9de26ba 100644
--- a/drivers/tty/serial/arc_uart.c
+++ b/drivers/tty/serial/arc_uart.c
@@ -651,7 +651,7 @@ static struct __initdata console arc_early_serial_console = {
.index = -1
};
-static int arc_serial_probe_earlyprintk(struct platform_device *pdev)
+static int __init arc_serial_probe_earlyprintk(struct platform_device *pdev)
{
int dev_id = pdev->id < 0 ? 0 : pdev->id;
int rc;
@@ -667,20 +667,12 @@ static int arc_serial_probe_earlyprintk(struct platform_device *pdev)
register_console(&arc_early_serial_console);
return 0;
}
-#else
-static int arc_serial_probe_earlyprintk(struct platform_device *pdev)
-{
- return -ENODEV;
-}
#endif /* CONFIG_SERIAL_ARC_CONSOLE */
static int arc_serial_probe(struct platform_device *pdev)
{
int rc, dev_id;
- if (is_early_platform_device(pdev))
- return arc_serial_probe_earlyprintk(pdev);
-
dev_id = pdev->id < 0 ? 0 : pdev->id;
rc = arc_uart_init_one(pdev, dev_id);
if (rc)
@@ -706,6 +698,15 @@ static struct platform_driver arc_platform_driver = {
};
#ifdef CONFIG_SERIAL_ARC_CONSOLE
+
+static struct platform_driver early_arc_platform_driver = {
+ .probe = arc_serial_probe_earlyprintk,
+ .remove = arc_serial_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+};
/*
* Register an early platform driver of "earlyprintk" class.
* ARCH platform code installs the driver and probes the early devices
@@ -713,7 +714,7 @@ static struct platform_driver arc_platform_driver = {
* or it could be done independently, for all "earlyprintk" class drivers.
* [see arch/arc/plat-arcfpga/platform.c]
*/
-early_platform_init("earlyprintk", &arc_platform_driver);
+early_platform_init("earlyprintk", &early_arc_platform_driver);
#endif /* CONFIG_SERIAL_ARC_CONSOLE */
--
1.7.4.1
^ permalink raw reply related
* [PATCH 4/4] serial/arc-uart: switch to devicetree based probing
From: Vineet Gupta @ 2013-01-11 6:20 UTC (permalink / raw)
To: linux-serial, linux-kernel
Cc: Vineet Gupta, Grant Likely, Arnd Bergmann, Alan Cox,
Greg Kroah-Hartman, devicetree-discuss, Rob Herring, Rob Landley
In-Reply-To: <1357885223-19243-1-git-send-email-vgupta@synopsys.com>
* DT binding for arc-uart
* With alll the bits in place we can now use DT probing.
Note that there's a bit of kludge right now because earlyprintk portion
of driver can't use the DT infrastrcuture to get resoures/plat_data.
This requires some infrastructre changes to of_flat_ framework
Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: linux-serial@vger.kernel.org
Cc: Alan Cox <alan@linux.intel.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: devicetree-discuss@lists.ozlabs.org
Cc: Rob Herring <rob.herring@calxeda.com>
Cc: Rob Landley <rob@landley.net>
Cc: linux-serial@vger.kernel.org
---
.../devicetree/bindings/tty/serial/arc-uart.txt | 26 ++++++++++++
drivers/tty/serial/arc_uart.c | 43 ++++++++++++++++++-
2 files changed, 66 insertions(+), 3 deletions(-)
create mode 100644 Documentation/devicetree/bindings/tty/serial/arc-uart.txt
diff --git a/Documentation/devicetree/bindings/tty/serial/arc-uart.txt b/Documentation/devicetree/bindings/tty/serial/arc-uart.txt
new file mode 100644
index 0000000..c3bd8f9
--- /dev/null
+++ b/Documentation/devicetree/bindings/tty/serial/arc-uart.txt
@@ -0,0 +1,26 @@
+* Synopsys ARC UART : Non standard UART used in some of the ARC FPGA boards
+
+Required properties:
+- compatible : "snps,arc-uart"
+- reg : offset and length of the register set for the device.
+- interrupts : device interrupt
+- clock-frequency : the input clock frequency for the UART
+- baud : baud rate for UART
+
+e.g.
+
+arcuart0: serial@c0fc1000 {
+ compatible = "snps,arc-uart";
+ reg = <0xc0fc1000 0x100>;
+ interrupts = <5>;
+ clock-frequency = <80000000>;
+ baud = <115200>;
+ status = "okay";
+};
+
+Note: Each port should have an alias correctly numbered in "aliases" node.
+
+e.g.
+aliases {
+ serial0 = &arcuart0;
+};
diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c
index 2db6410..b468601 100644
--- a/drivers/tty/serial/arc_uart.c
+++ b/drivers/tty/serial/arc_uart.c
@@ -37,6 +37,8 @@
#include <linux/tty_flip.h>
#include <linux/serial_core.h>
#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
/*************************************
* ARC UART Hardware Specs
@@ -537,8 +539,26 @@ arc_uart_init_one(struct platform_device *pdev, int dev_id)
return -ENODEV;
uart->is_emulated = !!plat_data[0]; /* workaround ISS bug */
- uart->port.uartclk = plat_data[1];
- uart->baud = plat_data[2];
+
+ if (is_early_platform_device(pdev)) {
+ uart->port.uartclk = plat_data[1];
+ uart->baud = plat_data[2];
+ } else {
+ struct device_node *np = pdev->dev.of_node;
+ u32 val;
+
+ if (of_property_read_u32(np, "clock-frequency", &val)) {
+ dev_err(&pdev->dev, "clock-frequency property NOTset\n");
+ return -EINVAL;
+ }
+ uart->port.uartclk = val;
+
+ if (of_property_read_u32(np, "baud", &val)) {
+ dev_err(&pdev->dev, "baud property NOT set\n");
+ return -EINVAL;
+ }
+ uart->baud = val;
+ }
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
@@ -673,8 +693,18 @@ static int __init arc_serial_probe_earlyprintk(struct platform_device *pdev)
static int arc_serial_probe(struct platform_device *pdev)
{
int rc, dev_id;
+ struct device_node *np = pdev->dev.of_node;
+
+ /* no device tree device */
+ if (!np)
+ return -ENODEV;
+
+ dev_id = of_alias_get_id(np, "serial");
+ if (dev_id < 0) {
+ dev_err(&pdev->dev, "failed to get alias id: %d\n", dev_id);
+ return dev_id;
+ }
- dev_id = pdev->id < 0 ? 0 : pdev->id;
rc = arc_uart_init_one(pdev, dev_id);
if (rc)
return rc;
@@ -689,12 +719,19 @@ static int arc_serial_remove(struct platform_device *pdev)
return 0;
}
+static const struct of_device_id arc_uart_dt_ids[] = {
+ { .compatible = "snps,arc-uart" },
+ { /* Sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, arc_uart_dt_ids);
+
static struct platform_driver arc_platform_driver = {
.probe = arc_serial_probe,
.remove = arc_serial_remove,
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
+ .of_match_table = arc_uart_dt_ids,
},
};
--
1.7.4.1
^ permalink raw reply related
* [PATCH 3/4] serial/arc-uart: platform_data order changed
From: Vineet Gupta @ 2013-01-11 6:20 UTC (permalink / raw)
To: linux-serial, linux-kernel
Cc: Vineet Gupta, Alan Cox, Greg Kroah-Hartman, Jiri Slaby
In-Reply-To: <1357885223-19243-1-git-send-email-vgupta@synopsys.com>
* is_emulated is now 1st element, rather than last
* also tucked all platform data refs together
Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
Cc: Alan Cox <alan@linux.intel.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: linux-serial@vger.kernel.org
---
drivers/tty/serial/arc_uart.c | 11 ++++++-----
1 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c
index 9de26ba..2db6410 100644
--- a/drivers/tty/serial/arc_uart.c
+++ b/drivers/tty/serial/arc_uart.c
@@ -533,7 +533,12 @@ arc_uart_init_one(struct platform_device *pdev, int dev_id)
struct arc_uart_port *uart = &arc_uart_ports[dev_id];
plat_data = ((unsigned long *)(pdev->dev.platform_data));
- uart->baud = plat_data[0];
+ if (!plat_data)
+ return -ENODEV;
+
+ uart->is_emulated = !!plat_data[0]; /* workaround ISS bug */
+ uart->port.uartclk = plat_data[1];
+ uart->baud = plat_data[2];
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
@@ -556,7 +561,6 @@ arc_uart_init_one(struct platform_device *pdev, int dev_id)
uart->port.line = dev_id;
uart->port.ops = &arc_serial_pops;
- uart->port.uartclk = plat_data[1];
uart->port.fifosize = ARC_UART_TX_FIFO_SIZE;
/*
@@ -565,9 +569,6 @@ arc_uart_init_one(struct platform_device *pdev, int dev_id)
*/
uart->port.ignore_status_mask = 0;
- /* Real Hardware vs. emulated to work around a bug */
- uart->is_emulated = !!plat_data[2];
-
return 0;
}
--
1.7.4.1
^ permalink raw reply related
* [PATCH 1/4] serial/arc-uart: Don't index with -ve platform_device->id
From: Vineet Gupta @ 2013-01-11 6:20 UTC (permalink / raw)
To: linux-serial, linux-kernel
Cc: Vineet Gupta, Alan Cox, Greg Kroah-Hartman, Jiri Slaby
In-Reply-To: <1357885223-19243-1-git-send-email-vgupta@synopsys.com>
probe routine could index into port[] with -ve index. The check in
arc_uart_init_one() was too late.
This came to light when trying to port driver to CONFIG_OF, where
bydefault of-core code sets -ve platform dev id and in absence of
DT serial aliases, driver would use the -ve index.
Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
Cc: Alan Cox <alan@linux.intel.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: linux-serial@vger.kernel.org
---
drivers/tty/serial/arc_uart.c | 29 +++++++++++++++--------------
1 files changed, 15 insertions(+), 14 deletions(-)
diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c
index 3e0b3fa..8089dc3 100644
--- a/drivers/tty/serial/arc_uart.c
+++ b/drivers/tty/serial/arc_uart.c
@@ -526,15 +526,11 @@ static struct uart_ops arc_serial_pops = {
};
static int
-arc_uart_init_one(struct platform_device *pdev, struct arc_uart_port *uart)
+arc_uart_init_one(struct platform_device *pdev, int dev_id)
{
struct resource *res, *res2;
unsigned long *plat_data;
-
- if (pdev->id < 0 || pdev->id >= CONFIG_SERIAL_ARC_NR_PORTS) {
- dev_err(&pdev->dev, "Wrong uart platform device id.\n");
- return -ENOENT;
- }
+ struct arc_uart_port *uart = &arc_uart_ports[dev_id];
plat_data = ((unsigned long *)(pdev->dev.platform_data));
uart->baud = plat_data[0];
@@ -557,7 +553,7 @@ arc_uart_init_one(struct platform_device *pdev, struct arc_uart_port *uart)
uart->port.dev = &pdev->dev;
uart->port.iotype = UPIO_MEM;
uart->port.flags = UPF_BOOT_AUTOCONF;
- uart->port.line = pdev->id;
+ uart->port.line = dev_id;
uart->port.ops = &arc_serial_pops;
uart->port.uartclk = plat_data[1];
@@ -657,9 +653,14 @@ static struct __initdata console arc_early_serial_console = {
static int arc_serial_probe_earlyprintk(struct platform_device *pdev)
{
- arc_early_serial_console.index = pdev->id;
+ int dev_id = pdev->id < 0 ? 0 : pdev->id;
+ int rc;
- arc_uart_init_one(pdev, &arc_uart_ports[pdev->id]);
+ arc_early_serial_console.index = dev_id;
+
+ rc = arc_uart_init_one(pdev, dev_id);
+ if (rc)
+ panic("early console init failed\n");
arc_serial_console_setup(&arc_early_serial_console, NULL);
@@ -675,18 +676,18 @@ static int arc_serial_probe_earlyprintk(struct platform_device *pdev)
static int arc_serial_probe(struct platform_device *pdev)
{
- struct arc_uart_port *uart;
- int rc;
+ int rc, dev_id;
if (is_early_platform_device(pdev))
return arc_serial_probe_earlyprintk(pdev);
- uart = &arc_uart_ports[pdev->id];
- rc = arc_uart_init_one(pdev, uart);
+ dev_id = pdev->id < 0 ? 0 : pdev->id;
+ rc = arc_uart_init_one(pdev, dev_id);
if (rc)
return rc;
- return uart_add_one_port(&arc_uart_driver, &uart->port);
+ rc = uart_add_one_port(&arc_uart_driver, &arc_uart_ports[dev_id].port);
+ return rc;
}
static int arc_serial_remove(struct platform_device *pdev)
--
1.7.4.1
^ permalink raw reply related
* [PATCH 0/4] switch arc-uart to devicetree based probing
From: Vineet Gupta @ 2013-01-11 6:20 UTC (permalink / raw)
To: linux-serial, linux-kernel; +Cc: Vineet Gupta
Hi,
As part of converting ARC Port to devicetree infrastructure, the following
series converts the arc-uart driver to DT.
* The first patch is a bug-fix which showed up in the process as DT based
platform devices by default have -ve id
* Next two prepare the driver for forthcoming DT changes.
* Last one contains the DT bindings and driver using those.
Couple of points worth mentioning:
* The earlyprintk portion of driver still relies on static platform data
we would need some earlyprintk handling in of_fdt_* to clean it up properly
* Two of the three platform data instances are now retrieved from DT.
However one still needs to be dynamically passed by platform (using
of_dev_auxdata) as we want to run same image in simulator and hardware
Tested on in-works ARC 3.8 port.
P.S. Greg, can this be treated as a bug-fix for 3.8
Thx,
-Vineet
Vineet Gupta (4):
serial/arc-uart: Don't index with -ve platform_device->id
serial/arc-uart: split probe from probe_earlyprintk
serial/arc-uart: platform_data order changed
serial/arc-uart: switch to devicetree based probing
.../devicetree/bindings/tty/serial/arc-uart.txt | 26 ++++++
drivers/tty/serial/arc_uart.c | 95 ++++++++++++++------
2 files changed, 94 insertions(+), 27 deletions(-)
create mode 100644 Documentation/devicetree/bindings/tty/serial/arc-uart.txt
--
1.7.4.1
^ permalink raw reply
* [PATCHv3 8/8] serial: 8250_dw: Enable DMA support with ACPI
From: Heikki Krogerus @ 2013-01-10 9:25 UTC (permalink / raw)
To: Greg Kroah-Hartman; +Cc: Alan Cox, Jamie Iles, linux-serial, linux-kernel
In-Reply-To: <1357809912-25790-1-git-send-email-heikki.krogerus@linux.intel.com>
With ACPI 5.0 we can use the FixedDMA Resource Descriptor to
extract the needed information for DMA support.
Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
---
drivers/tty/serial/8250/8250_dw.c | 65 +++++++++++++++++++++++++++++++++++++
1 file changed, 65 insertions(+)
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index f6eeff0..ceacf5e 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -27,6 +27,8 @@
#include <linux/slab.h>
#include <linux/acpi.h>
+#include "8250.h"
+
/* Offsets for the DesignWare specific registers */
#define DW_UART_USR 0x1f /* UART Status Register */
#define DW_UART_CPR 0xf4 /* Component Parameter Register */
@@ -143,9 +145,64 @@ static int dw8250_probe_of(struct uart_port *p)
return 0;
}
+static bool dw8250_acpi_dma_filter(struct dma_chan *chan, void *parm)
+{
+ return chan->chan_id == *(int *)parm;
+}
+
+static acpi_status
+dw8250_acpi_walk_resource(struct acpi_resource *res, void *data)
+{
+ struct uart_port *p = data;
+ struct uart_8250_port *port;
+ struct uart_8250_dma *dma;
+ struct acpi_resource_fixed_dma *fixed_dma;
+ struct dma_slave_config *slave;
+
+ port = container_of(p, struct uart_8250_port, port);
+
+ switch (res->type) {
+ case ACPI_RESOURCE_TYPE_FIXED_DMA:
+ fixed_dma = &res->data.fixed_dma;
+
+ /* TX comes first */
+ if (!port->dma) {
+ dma = devm_kzalloc(p->dev, sizeof(*dma), GFP_KERNEL);
+ if (!dma)
+ return AE_NO_MEMORY;
+
+ port->dma = dma;
+ slave = &dma->txconf;
+
+ slave->direction = DMA_MEM_TO_DEV;
+ slave->dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ slave->slave_id = fixed_dma->request_lines;
+
+ dma->tx_chan_id = fixed_dma->channels;
+ dma->tx_param = &dma->tx_chan_id;
+ dma->fn = dw8250_acpi_dma_filter;
+ } else {
+ dma = port->dma;
+ slave = &dma->rxconf;
+
+ slave->direction = DMA_DEV_TO_MEM;
+ slave->src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ slave->slave_id = fixed_dma->request_lines;
+
+ dma->rx_chan_id = fixed_dma->channels;
+ dma->rx_param = &dma->rx_chan_id;
+ }
+
+ break;
+ }
+
+ return AE_OK;
+}
+
static int dw8250_probe_acpi(struct uart_port *p)
{
const struct acpi_device_id *id;
+ acpi_status status;
u32 reg;
id = acpi_match_device(p->dev->driver->acpi_match_table, p->dev);
@@ -158,6 +215,14 @@ static int dw8250_probe_acpi(struct uart_port *p)
p->regshift = 2;
p->uartclk = (unsigned int)id->driver_data;
+ status = acpi_walk_resources(ACPI_HANDLE(p->dev), METHOD_NAME__CRS,
+ dw8250_acpi_walk_resource, p);
+ if (ACPI_FAILURE(status)) {
+ dev_err_ratelimited(p->dev, "%s failed \"%s\"\n", __func__,
+ acpi_format_exception(status));
+ return -ENODEV;
+ }
+
/* Fix Haswell issue where the clocks do not get enabled */
if (!strcmp(id->id, "INT33C4") || !strcmp(id->id, "INT33C5")) {
reg = readl(p->membase + LPSS_PRV_CLOCK_PARAMS);
--
1.7.10.4
^ permalink raw reply related
* [PATCHv3 7/8] serial: 8250: Add support for dmaengine
From: Heikki Krogerus @ 2013-01-10 9:25 UTC (permalink / raw)
To: Greg Kroah-Hartman; +Cc: Alan Cox, Jamie Iles, linux-serial, linux-kernel
In-Reply-To: <1357809912-25790-1-git-send-email-heikki.krogerus@linux.intel.com>
Add support for dmaengine API. The drivers can implement the
struct uart_8250_dma member in struct uart_8250_port and
8250.c can take care of the rest.
Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
---
drivers/tty/serial/8250/8250.c | 31 +++++-
drivers/tty/serial/8250/8250.h | 50 +++++++++
drivers/tty/serial/8250/8250_dma.c | 213 ++++++++++++++++++++++++++++++++++++
drivers/tty/serial/8250/Kconfig | 8 ++
drivers/tty/serial/8250/Makefile | 1 +
include/linux/serial_8250.h | 4 +
6 files changed, 304 insertions(+), 3 deletions(-)
create mode 100644 drivers/tty/serial/8250/8250_dma.c
diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c
index da3f828..f952993 100644
--- a/drivers/tty/serial/8250/8250.c
+++ b/drivers/tty/serial/8250/8250.c
@@ -1335,7 +1335,9 @@ static void serial8250_start_tx(struct uart_port *port)
struct uart_8250_port *up =
container_of(port, struct uart_8250_port, port);
- if (!(up->ier & UART_IER_THRI)) {
+ if (up->dma && !serial8250_tx_dma(up)) {
+ return;
+ } else if (!(up->ier & UART_IER_THRI)) {
up->ier |= UART_IER_THRI;
serial_port_out(port, UART_IER, up->ier);
@@ -1536,6 +1538,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
unsigned long flags;
struct uart_8250_port *up =
container_of(port, struct uart_8250_port, port);
+ int dma_err = 0;
if (iir & UART_IIR_NO_INT)
return 0;
@@ -1546,8 +1549,13 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
DEBUG_INTR("status = %x...", status);
- if (status & (UART_LSR_DR | UART_LSR_BI))
- status = serial8250_rx_chars(up, status);
+ if (status & (UART_LSR_DR | UART_LSR_BI)) {
+ if (up->dma)
+ dma_err = serial8250_rx_dma(up, iir);
+
+ if (!up->dma || dma_err)
+ status = serial8250_rx_chars(up, status);
+ }
serial8250_modem_status(up);
if (status & UART_LSR_THRE)
serial8250_tx_chars(up);
@@ -2190,6 +2198,18 @@ dont_test_tx_en:
up->msr_saved_flags = 0;
/*
+ * Request DMA channels for both RX and TX.
+ */
+ if (up->dma) {
+ retval = serial8250_request_dma(up);
+ if (retval) {
+ pr_warn_ratelimited("ttyS%d - failed to request DMA\n",
+ serial_index(port));
+ up->dma = NULL;
+ }
+ }
+
+ /*
* Finally, enable interrupts. Note: Modem status interrupts
* are set via set_termios(), which will be occurring imminently
* anyway, so we don't enable them here.
@@ -2222,6 +2242,9 @@ static void serial8250_shutdown(struct uart_port *port)
up->ier = 0;
serial_port_out(port, UART_IER, 0);
+ if (up->dma)
+ serial8250_release_dma(up);
+
spin_lock_irqsave(&port->lock, flags);
if (port->flags & UPF_FOURPORT) {
/* reset interrupts on the AST Fourport board */
@@ -3286,6 +3309,8 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
uart->dl_read = up->dl_read;
if (up->dl_write)
uart->dl_write = up->dl_write;
+ if (up->dma)
+ uart->dma = up->dma;
if (serial8250_isa_config != NULL)
serial8250_isa_config(0, &uart->port,
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index 3b4ea84..363d549 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -12,6 +12,35 @@
*/
#include <linux/serial_8250.h>
+#include <linux/dmaengine.h>
+
+struct uart_8250_dma {
+ dma_filter_fn fn;
+ void *rx_param;
+ void *tx_param;
+
+ int rx_chan_id;
+ int tx_chan_id;
+
+ struct dma_slave_config rxconf;
+ struct dma_slave_config txconf;
+
+ struct dma_chan *rxchan;
+ struct dma_chan *txchan;
+
+ dma_addr_t rx_addr;
+ dma_addr_t tx_addr;
+
+ dma_cookie_t rx_cookie;
+ dma_cookie_t tx_cookie;
+
+ void *rx_buf;
+
+ size_t rx_size;
+ size_t tx_size;
+
+ unsigned char tx_running:1;
+};
struct old_serial_port {
unsigned int uart;
@@ -142,3 +171,24 @@ static inline int is_omap1510_8250(struct uart_8250_port *pt)
return 0;
}
#endif
+
+#ifdef CONFIG_SERIAL_8250_DMA
+extern int serial8250_tx_dma(struct uart_8250_port *);
+extern int serial8250_rx_dma(struct uart_8250_port *, unsigned int iir);
+extern int serial8250_request_dma(struct uart_8250_port *);
+extern void serial8250_release_dma(struct uart_8250_port *);
+#else
+static inline int serial8250_tx_dma(struct uart_8250_port *p)
+{
+ return -1;
+}
+static inline int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
+{
+ return -1;
+}
+static inline int serial8250_request_dma(struct uart_8250_port *p)
+{
+ return -1;
+}
+static inline void serial8250_release_dma(struct uart_8250_port *p) { }
+#endif
diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c
new file mode 100644
index 0000000..95516a1
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_dma.c
@@ -0,0 +1,213 @@
+/*
+ * 8250_dma.c - DMA Engine API support for 8250.c
+ *
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_reg.h>
+#include <linux/dma-mapping.h>
+
+#include "8250.h"
+
+static void __dma_tx_complete(void *param)
+{
+ struct uart_8250_port *p = param;
+ struct uart_8250_dma *dma = p->dma;
+ struct circ_buf *xmit = &p->port.state->xmit;
+
+ dma->tx_running = 0;
+
+ dma_sync_single_for_cpu(dma->txchan->device->dev, dma->tx_addr,
+ UART_XMIT_SIZE, DMA_TO_DEVICE);
+
+ xmit->tail += dma->tx_size;
+ xmit->tail &= UART_XMIT_SIZE - 1;
+ p->port.icount.tx += dma->tx_size;
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(&p->port);
+
+ if (!uart_circ_empty(xmit) && !uart_tx_stopped(&p->port)) {
+ serial8250_tx_dma(p);
+ uart_write_wakeup(&p->port);
+ }
+}
+
+static void __dma_rx_complete(void *param)
+{
+ struct uart_8250_port *p = param;
+ struct uart_8250_dma *dma = p->dma;
+ struct tty_struct *tty = p->port.state->port.tty;
+ struct dma_tx_state state;
+
+ dma_sync_single_for_cpu(dma->rxchan->device->dev, dma->rx_addr,
+ dma->rx_size, DMA_FROM_DEVICE);
+
+ dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
+ dmaengine_terminate_all(dma->rxchan);
+
+ tty_insert_flip_string(tty, dma->rx_buf, dma->rx_size - state.residue);
+ p->port.icount.rx += dma->rx_size - state.residue;
+
+ tty_flip_buffer_push(tty);
+}
+
+int serial8250_tx_dma(struct uart_8250_port *p)
+{
+ struct uart_8250_dma *dma = p->dma;
+ struct circ_buf *xmit = &p->port.state->xmit;
+ struct dma_async_tx_descriptor *desc;
+
+ if (dma->tx_running) {
+ uart_write_wakeup(&p->port);
+ return -EBUSY;
+ }
+
+ dma->tx_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
+
+ desc = dmaengine_prep_slave_single(dma->txchan,
+ dma->tx_addr + xmit->tail,
+ dma->tx_size, DMA_MEM_TO_DEV,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!desc)
+ return -EBUSY;
+
+ dma->tx_running = 1;
+
+ desc->callback = __dma_tx_complete;
+ desc->callback_param = p;
+
+ dma->tx_cookie = dmaengine_submit(desc);
+
+ dma_sync_single_for_device(dma->txchan->device->dev, dma->tx_addr,
+ UART_XMIT_SIZE, DMA_TO_DEVICE);
+
+ dma_async_issue_pending(dma->txchan);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(serial8250_tx_dma);
+
+int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
+{
+ struct uart_8250_dma *dma = p->dma;
+ struct dma_async_tx_descriptor *desc;
+ struct dma_tx_state state;
+ int dma_status;
+
+ /*
+ * If RCVR FIFO trigger level was not reached, complete the transfer and
+ * let 8250.c copy the remaining data.
+ */
+ if ((iir & 0x3f) == UART_IIR_RX_TIMEOUT) {
+ dma_status = dmaengine_tx_status(dma->rxchan, dma->rx_cookie,
+ &state);
+ if (dma_status == DMA_IN_PROGRESS) {
+ dmaengine_pause(dma->rxchan);
+ __dma_rx_complete(p);
+ }
+ return -ETIMEDOUT;
+ }
+
+ desc = dmaengine_prep_slave_single(dma->rxchan, dma->rx_addr,
+ dma->rx_size, DMA_DEV_TO_MEM,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!desc)
+ return -EBUSY;
+
+ desc->callback = __dma_rx_complete;
+ desc->callback_param = p;
+
+ dma->rx_cookie = dmaengine_submit(desc);
+
+ dma_sync_single_for_device(dma->rxchan->device->dev, dma->rx_addr,
+ dma->rx_size, DMA_FROM_DEVICE);
+
+ dma_async_issue_pending(dma->rxchan);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(serial8250_rx_dma);
+
+int serial8250_request_dma(struct uart_8250_port *p)
+{
+ struct uart_8250_dma *dma = p->dma;
+ dma_cap_mask_t mask;
+
+ dma->rxconf.src_addr = p->port.mapbase + UART_RX;
+ dma->txconf.dst_addr = p->port.mapbase + UART_TX;
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+
+ /* Get a channel for RX */
+ dma->rxchan = dma_request_channel(mask, dma->fn, dma->rx_param);
+ if (!dma->rxchan)
+ return -ENODEV;
+
+ dmaengine_slave_config(dma->rxchan, &dma->rxconf);
+
+ /* Get a channel for TX */
+ dma->txchan = dma_request_channel(mask, dma->fn, dma->tx_param);
+ if (!dma->txchan) {
+ dma_release_channel(dma->rxchan);
+ return -ENODEV;
+ }
+
+ dmaengine_slave_config(dma->txchan, &dma->txconf);
+
+ /* RX buffer */
+ if (!dma->rx_size)
+ dma->rx_size = PAGE_SIZE;
+
+ dma->rx_buf = dma_alloc_coherent(dma->rxchan->device->dev, dma->rx_size,
+ &dma->rx_addr, GFP_KERNEL);
+ if (!dma->rx_buf) {
+ dma_release_channel(dma->rxchan);
+ dma_release_channel(dma->txchan);
+ return -ENOMEM;
+ }
+
+ /* TX buffer */
+ dma->tx_addr = dma_map_single(dma->txchan->device->dev,
+ p->port.state->xmit.buf,
+ UART_XMIT_SIZE,
+ DMA_TO_DEVICE);
+
+ dev_dbg_ratelimited(p->port.dev, "got both dma channels\n");
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(serial8250_request_dma);
+
+void serial8250_release_dma(struct uart_8250_port *p)
+{
+ struct uart_8250_dma *dma = p->dma;
+
+ if (!dma)
+ return;
+
+ /* Release RX resources */
+ dmaengine_terminate_all(dma->rxchan);
+ dma_free_coherent(dma->rxchan->device->dev, dma->rx_size, dma->rx_buf,
+ dma->rx_addr);
+ dma_release_channel(dma->rxchan);
+ dma->rxchan = NULL;
+
+ /* Release TX resources */
+ dmaengine_terminate_all(dma->txchan);
+ dma_unmap_single(dma->txchan->device->dev, dma->tx_addr,
+ UART_XMIT_SIZE, DMA_TO_DEVICE);
+ dma_release_channel(dma->txchan);
+ dma->txchan = NULL;
+ dma->tx_running = 0;
+
+ dev_dbg_ratelimited(p->port.dev, "dma channels released\n");
+}
+EXPORT_SYMBOL_GPL(serial8250_release_dma);
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index 11adff1..2748125 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -84,6 +84,14 @@ config SERIAL_8250_GSC
depends on SERIAL_8250 && GSC
default SERIAL_8250
+config SERIAL_8250_DMA
+ bool "DMA support for 16550 compatible UART controllers" if EXPERT
+ depends on SERIAL_8250 && DMADEVICES=y
+ default SERIAL_8250
+ help
+ This builds DMA support that can be used with 8250/16650
+ compatible UART controllers that support DMA signaling.
+
config SERIAL_8250_PCI
tristate "8250/16550 PCI device support" if EXPERT
depends on SERIAL_8250 && PCI
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index 108fe7f..a23838a 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -5,6 +5,7 @@
obj-$(CONFIG_SERIAL_8250) += 8250_core.o
8250_core-y := 8250.o
8250_core-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o
+8250_core-$(CONFIG_SERIAL_8250_DMA) += 8250_dma.o
obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o
obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o
obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o
diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h
index c490d20..af47a8a 100644
--- a/include/linux/serial_8250.h
+++ b/include/linux/serial_8250.h
@@ -59,6 +59,8 @@ enum {
PLAT8250_DEV_SM501,
};
+struct uart_8250_dma;
+
/*
* This should be used by drivers which want to register
* their own 8250 ports without registering their own
@@ -91,6 +93,8 @@ struct uart_8250_port {
#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
unsigned char msr_saved_flags;
+ struct uart_8250_dma *dma;
+
/* 8250 specific callbacks */
int (*dl_read)(struct uart_8250_port *);
void (*dl_write)(struct uart_8250_port *, int);
--
1.7.10.4
^ permalink raw reply related
* [PATCHv3 5/8] serial: 8250_dw: Set FIFO size dynamically
From: Heikki Krogerus @ 2013-01-10 9:25 UTC (permalink / raw)
To: Greg Kroah-Hartman; +Cc: Alan Cox, Jamie Iles, linux-serial, linux-kernel
In-Reply-To: <1357809912-25790-1-git-send-email-heikki.krogerus@linux.intel.com>
Designware UART provides optional Component Parameter
Register that lists most of the capabilities of the UART,
including FIFO size. This uses that register to set FIFO
size for the port before registering it.
Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Reviewed-by: Jamie Iles <jamie@jamieiles.com>
Acked-by: Alan Cox <alan@linux.intel.com>
---
drivers/tty/serial/8250/8250_dw.c | 57 ++++++++++++++++++++++++++++++++++---
1 file changed, 53 insertions(+), 4 deletions(-)
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index d96e02e..e104092 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -25,6 +25,28 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
+/* Offsets for the DesignWare specific registers */
+#define DW_UART_USR 0x1f /* UART Status Register */
+#define DW_UART_CPR 0xf4 /* Component Parameter Register */
+#define DW_UART_UCV 0xf8 /* UART Component Version */
+
+/* Component Parameter Register bits */
+#define DW_UART_CPR_ABP_DATA_WIDTH (3 << 0)
+#define DW_UART_CPR_AFCE_MODE (1 << 4)
+#define DW_UART_CPR_THRE_MODE (1 << 5)
+#define DW_UART_CPR_SIR_MODE (1 << 6)
+#define DW_UART_CPR_SIR_LP_MODE (1 << 7)
+#define DW_UART_CPR_ADDITIONAL_FEATURES (1 << 8)
+#define DW_UART_CPR_FIFO_ACCESS (1 << 9)
+#define DW_UART_CPR_FIFO_STAT (1 << 10)
+#define DW_UART_CPR_SHADOW (1 << 11)
+#define DW_UART_CPR_ENCODED_PARMS (1 << 12)
+#define DW_UART_CPR_DMA_EXTRA (1 << 13)
+#define DW_UART_CPR_FIFO_MODE (0xff << 16)
+/* Helper for fifo size calculation */
+#define DW_UART_CPR_FIFO_SIZE(a) (((a >> 16) & 0xff) * 16)
+
+
struct dw8250_data {
int last_lcr;
int line;
@@ -66,9 +88,6 @@ static unsigned int dw8250_serial_in32(struct uart_port *p, int offset)
return readl(p->membase + offset);
}
-/* Offset for the DesignWare's UART Status Register. */
-#define UART_USR 0x1f
-
static int dw8250_handle_irq(struct uart_port *p)
{
struct dw8250_data *d = p->private_data;
@@ -78,7 +97,7 @@ static int dw8250_handle_irq(struct uart_port *p)
return 1;
} else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
/* Clear the USR and write the LCR again. */
- (void)p->serial_in(p, UART_USR);
+ (void)p->serial_in(p, DW_UART_USR);
p->serial_out(p, d->last_lcr, UART_LCR);
return 1;
@@ -119,6 +138,34 @@ static int dw8250_probe_of(struct uart_port *p)
return 0;
}
+static void dw8250_setup_port(struct uart_8250_port *up)
+{
+ struct uart_port *p = &up->port;
+ u32 reg = readl(p->membase + DW_UART_UCV);
+
+ /*
+ * If the Component Version Register returns zero, we know that
+ * ADDITIONAL_FEATURES are not enabled. No need to go any further.
+ */
+ if (!reg)
+ return;
+
+ dev_dbg_ratelimited(p->dev, "Designware UART version %c.%c%c\n",
+ (reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff);
+
+ reg = readl(p->membase + DW_UART_CPR);
+ if (!reg)
+ return;
+
+ /* Select the type based on fifo */
+ if (reg & DW_UART_CPR_FIFO_MODE) {
+ p->type = PORT_16550A;
+ p->flags |= UPF_FIXED_TYPE;
+ p->fifosize = DW_UART_CPR_FIFO_SIZE(reg);
+ up->tx_loadsz = p->fifosize;
+ }
+}
+
static int dw8250_probe(struct platform_device *pdev)
{
struct uart_8250_port uart = {};
@@ -156,6 +203,8 @@ static int dw8250_probe(struct platform_device *pdev)
return -ENODEV;
}
+ dw8250_setup_port(&uart);
+
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
--
1.7.10.4
^ permalink raw reply related
* [PATCHv3 4/8] serial: 8250_dw: Move device tree code to separate function
From: Heikki Krogerus @ 2013-01-10 9:25 UTC (permalink / raw)
To: Greg Kroah-Hartman; +Cc: Alan Cox, Jamie Iles, linux-serial, linux-kernel
In-Reply-To: <1357809912-25790-1-git-send-email-heikki.krogerus@linux.intel.com>
Trivial cleanup. This makes it easier to add different
methods to enumerate the device, for example ACPI 5.0
enumeration.
Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Reviewed-by: Jamie Iles <jamie@jamieiles.com>
Acked-by: Alan Cox <alan@linux.intel.com>
---
drivers/tty/serial/8250/8250_dw.c | 78 ++++++++++++++++++++++---------------
1 file changed, 47 insertions(+), 31 deletions(-)
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index e174901..d96e02e 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -87,25 +87,51 @@ static int dw8250_handle_irq(struct uart_port *p)
return 0;
}
+static int dw8250_probe_of(struct uart_port *p)
+{
+ struct device_node *np = p->dev->of_node;
+ u32 val;
+
+ if (!of_property_read_u32(np, "reg-io-width", &val)) {
+ switch (val) {
+ case 1:
+ break;
+ case 4:
+ p->iotype = UPIO_MEM32;
+ p->serial_in = dw8250_serial_in32;
+ p->serial_out = dw8250_serial_out32;
+ break;
+ default:
+ dev_err(p->dev, "unsupported reg-io-width (%u)\n", val);
+ return -EINVAL;
+ }
+ }
+
+ if (!of_property_read_u32(np, "reg-shift", &val))
+ p->regshift = val;
+
+ if (of_property_read_u32(np, "clock-frequency", &val)) {
+ dev_err(p->dev, "no clock-frequency property set\n");
+ return -EINVAL;
+ }
+ p->uartclk = val;
+
+ return 0;
+}
+
static int dw8250_probe(struct platform_device *pdev)
{
struct uart_8250_port uart = {};
struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- struct device_node *np = pdev->dev.of_node;
- u32 val;
struct dw8250_data *data;
+ int err;
if (!regs || !irq) {
dev_err(&pdev->dev, "no registers/irq defined\n");
return -EINVAL;
}
- data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
- if (!data)
- return -ENOMEM;
- uart.port.private_data = data;
-
spin_lock_init(&uart.port.lock);
uart.port.mapbase = regs->start;
uart.port.irq = irq->start;
@@ -121,30 +147,20 @@ static int dw8250_probe(struct platform_device *pdev)
uart.port.iotype = UPIO_MEM;
uart.port.serial_in = dw8250_serial_in;
uart.port.serial_out = dw8250_serial_out;
- if (!of_property_read_u32(np, "reg-io-width", &val)) {
- switch (val) {
- case 1:
- break;
- case 4:
- uart.port.iotype = UPIO_MEM32;
- uart.port.serial_in = dw8250_serial_in32;
- uart.port.serial_out = dw8250_serial_out32;
- break;
- default:
- dev_err(&pdev->dev, "unsupported reg-io-width (%u)\n",
- val);
- return -EINVAL;
- }
+
+ if (pdev->dev.of_node) {
+ err = dw8250_probe_of(&uart.port);
+ if (err)
+ return err;
+ } else {
+ return -ENODEV;
}
- if (!of_property_read_u32(np, "reg-shift", &val))
- uart.port.regshift = val;
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
- if (of_property_read_u32(np, "clock-frequency", &val)) {
- dev_err(&pdev->dev, "no clock-frequency property set\n");
- return -EINVAL;
- }
- uart.port.uartclk = val;
+ uart.port.private_data = data;
data->line = serial8250_register_8250_port(&uart);
if (data->line < 0)
@@ -187,17 +203,17 @@ static int dw8250_resume(struct platform_device *pdev)
#define dw8250_resume NULL
#endif /* CONFIG_PM */
-static const struct of_device_id dw8250_match[] = {
+static const struct of_device_id dw8250_of_match[] = {
{ .compatible = "snps,dw-apb-uart" },
{ /* Sentinel */ }
};
-MODULE_DEVICE_TABLE(of, dw8250_match);
+MODULE_DEVICE_TABLE(of, dw8250_of_match);
static struct platform_driver dw8250_platform_driver = {
.driver = {
.name = "dw-apb-uart",
.owner = THIS_MODULE,
- .of_match_table = dw8250_match,
+ .of_match_table = dw8250_of_match,
},
.probe = dw8250_probe,
.remove = dw8250_remove,
--
1.7.10.4
^ permalink raw reply related
* [PATCHv3 3/8] serial: 8250_dw: Map IO memory
From: Heikki Krogerus @ 2013-01-10 9:25 UTC (permalink / raw)
To: Greg Kroah-Hartman; +Cc: Alan Cox, Jamie Iles, linux-serial, linux-kernel
In-Reply-To: <1357809912-25790-1-git-send-email-heikki.krogerus@linux.intel.com>
This needs to be done in order to later access the
Designware specific registers.
Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Reviewed-by: Jamie Iles <jamie@jamieiles.com>
Acked-by: Alan Cox <alan@linux.intel.com>
---
drivers/tty/serial/8250/8250_dw.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index ff83ea5..e174901 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -111,10 +111,13 @@ static int dw8250_probe(struct platform_device *pdev)
uart.port.irq = irq->start;
uart.port.handle_irq = dw8250_handle_irq;
uart.port.type = PORT_8250;
- uart.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP |
- UPF_FIXED_PORT;
+ uart.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT;
uart.port.dev = &pdev->dev;
+ uart.port.membase = ioremap(regs->start, resource_size(regs));
+ if (!uart.port.membase)
+ return -ENOMEM;
+
uart.port.iotype = UPIO_MEM;
uart.port.serial_in = dw8250_serial_in;
uart.port.serial_out = dw8250_serial_out;
--
1.7.10.4
^ permalink raw reply related
* [PATCHv3 2/8] serial: 8250_dw: Don't use UPF_FIXED_TYPE
From: Heikki Krogerus @ 2013-01-10 9:25 UTC (permalink / raw)
To: Greg Kroah-Hartman; +Cc: Alan Cox, Jamie Iles, linux-serial, linux-kernel
In-Reply-To: <1357809912-25790-1-git-send-email-heikki.krogerus@linux.intel.com>
Allow 8250.c to determine the port type for us. This allows
the driver take advantage of FIFO on Designware UARTs that
have it.
Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Reviewed-by: Jamie Iles <jamie@jamieiles.com>
Acked-by: Alan Cox <alan@linux.intel.com>
---
drivers/tty/serial/8250/8250_dw.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index 1d0dba2..ff83ea5 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -112,7 +112,7 @@ static int dw8250_probe(struct platform_device *pdev)
uart.port.handle_irq = dw8250_handle_irq;
uart.port.type = PORT_8250;
uart.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP |
- UPF_FIXED_PORT | UPF_FIXED_TYPE;
+ UPF_FIXED_PORT;
uart.port.dev = &pdev->dev;
uart.port.iotype = UPIO_MEM;
--
1.7.10.4
^ permalink raw reply related
* [PATCHv3 1/8] serial: 8250: Allow drivers to deliver capabilities
From: Heikki Krogerus @ 2013-01-10 9:25 UTC (permalink / raw)
To: Greg Kroah-Hartman; +Cc: Alan Cox, Jamie Iles, linux-serial, linux-kernel
In-Reply-To: <1357809912-25790-1-git-send-email-heikki.krogerus@linux.intel.com>
Modern UARTs are able to provide information about their
capabilities such as FIFO size. This allows the drivers to
deliver this information to 8250.c when they are registering
ports.
Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Reviewed-by: Jamie Iles <jamie@jamieiles.com>
Acked-by: Alan Cox <alan@linux.intel.com>
---
drivers/tty/serial/8250/8250.c | 22 ++++++++++++++++------
1 file changed, 16 insertions(+), 6 deletions(-)
diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c
index d085e3a..da3f828 100644
--- a/drivers/tty/serial/8250/8250.c
+++ b/drivers/tty/serial/8250/8250.c
@@ -1980,9 +1980,12 @@ static int serial8250_startup(struct uart_port *port)
if (port->type == PORT_8250_CIR)
return -ENODEV;
- port->fifosize = uart_config[up->port.type].fifo_size;
- up->tx_loadsz = uart_config[up->port.type].tx_loadsz;
- up->capabilities = uart_config[up->port.type].flags;
+ if (!port->fifosize)
+ port->fifosize = uart_config[port->type].fifo_size;
+ if (!up->tx_loadsz)
+ up->tx_loadsz = uart_config[port->type].tx_loadsz;
+ if (!up->capabilities)
+ up->capabilities = uart_config[port->type].flags;
up->mcr = 0;
if (port->iotype != up->cur_iotype)
@@ -2815,9 +2818,12 @@ static void
serial8250_init_fixed_type_port(struct uart_8250_port *up, unsigned int type)
{
up->port.type = type;
- up->port.fifosize = uart_config[type].fifo_size;
- up->capabilities = uart_config[type].flags;
- up->tx_loadsz = uart_config[type].tx_loadsz;
+ if (!up->port.fifosize)
+ up->port.fifosize = uart_config[type].fifo_size;
+ if (!up->tx_loadsz)
+ up->tx_loadsz = uart_config[type].tx_loadsz;
+ if (!up->capabilities)
+ up->capabilities = uart_config[type].flags;
}
static void __init
@@ -3251,6 +3257,10 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
uart->bugs = up->bugs;
uart->port.mapbase = up->port.mapbase;
uart->port.private_data = up->port.private_data;
+ uart->port.fifosize = up->port.fifosize;
+ uart->tx_loadsz = up->tx_loadsz;
+ uart->capabilities = up->capabilities;
+
if (up->port.dev)
uart->port.dev = up->port.dev;
--
1.7.10.4
^ permalink raw reply related
* [PATCHv3 0/8] serial: 8250: 8250_dw changes and dmaengine support
From: Heikki Krogerus @ 2013-01-10 9:25 UTC (permalink / raw)
To: Greg Kroah-Hartman; +Cc: Alan Cox, Jamie Iles, linux-serial, linux-kernel
Changes since v2:
- ACPI support for 8250_dw.c
- dmaengine API support for 8250
It looks like there are a few UART drivers that are more or less
identical with 8250.c except they include DMA support, so if we had
DMA support in 8250.c there may be no need for them. Since dmaengine
is now supported on most platforms, I decided to suggest this
solution.
I tried to make the DMA support as simple as I could. Single transfers
with single descriptors. This should be sufficient in most cases.
Heikki Krogerus (8):
serial: 8250: Allow drivers to deliver capabilities
serial: 8250_dw: Don't use UPF_FIXED_TYPE
serial: 8250_dw: Map IO memory
serial: 8250_dw: Move device tree code to separate function
serial: 8250_dw: Set FIFO size dynamically
serial: 8250_dw: Add ACPI 5.0 support
serial: 8250: Add support for dmaengine
serial: 8250_dw: Enable DMA support with ACPI
drivers/tty/serial/8250/8250.c | 53 ++++++--
drivers/tty/serial/8250/8250.h | 50 ++++++++
drivers/tty/serial/8250/8250_dma.c | 213 +++++++++++++++++++++++++++++++
drivers/tty/serial/8250/8250_dw.c | 248 ++++++++++++++++++++++++++++++------
drivers/tty/serial/8250/Kconfig | 10 +-
drivers/tty/serial/8250/Makefile | 1 +
include/linux/serial_8250.h | 4 +
7 files changed, 532 insertions(+), 47 deletions(-)
create mode 100644 drivers/tty/serial/8250/8250_dma.c
--
1.7.10.4
^ permalink raw reply
* [PATCHv3 6/8] serial: 8250_dw: Add ACPI 5.0 support
From: Heikki Krogerus @ 2013-01-10 9:25 UTC (permalink / raw)
To: Greg Kroah-Hartman; +Cc: Alan Cox, Jamie Iles, linux-serial, linux-kernel
In-Reply-To: <1357809912-25790-1-git-send-email-heikki.krogerus@linux.intel.com>
This adds support for ACPI 5.0 enumerated Designware UARTs.
ACPI does not deliver information about uart clk, so
delivering it with the driver_data.
Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
---
drivers/tty/serial/8250/8250_dw.c | 41 +++++++++++++++++++++++++++++++++++++
drivers/tty/serial/8250/Kconfig | 2 +-
2 files changed, 42 insertions(+), 1 deletion(-)
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index e104092..f6eeff0 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -2,6 +2,7 @@
* Synopsys DesignWare 8250 driver.
*
* Copyright 2011 Picochip, Jamie Iles.
+ * Copyright 2013 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,12 +25,16 @@
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
+#include <linux/acpi.h>
/* Offsets for the DesignWare specific registers */
#define DW_UART_USR 0x1f /* UART Status Register */
#define DW_UART_CPR 0xf4 /* Component Parameter Register */
#define DW_UART_UCV 0xf8 /* UART Component Version */
+/* Intel Low Power Subsystem specific */
+#define LPSS_PRV_CLOCK_PARAMS 0x800
+
/* Component Parameter Register bits */
#define DW_UART_CPR_ABP_DATA_WIDTH (3 << 0)
#define DW_UART_CPR_AFCE_MODE (1 << 4)
@@ -138,6 +143,30 @@ static int dw8250_probe_of(struct uart_port *p)
return 0;
}
+static int dw8250_probe_acpi(struct uart_port *p)
+{
+ const struct acpi_device_id *id;
+ u32 reg;
+
+ id = acpi_match_device(p->dev->driver->acpi_match_table, p->dev);
+ if (!id)
+ return -ENODEV;
+
+ p->iotype = UPIO_MEM32;
+ p->serial_in = dw8250_serial_in32;
+ p->serial_out = dw8250_serial_out32;
+ p->regshift = 2;
+ p->uartclk = (unsigned int)id->driver_data;
+
+ /* Fix Haswell issue where the clocks do not get enabled */
+ if (!strcmp(id->id, "INT33C4") || !strcmp(id->id, "INT33C5")) {
+ reg = readl(p->membase + LPSS_PRV_CLOCK_PARAMS);
+ writel(reg | 1, p->membase + LPSS_PRV_CLOCK_PARAMS);
+ }
+
+ return 0;
+}
+
static void dw8250_setup_port(struct uart_8250_port *up)
{
struct uart_port *p = &up->port;
@@ -199,6 +228,10 @@ static int dw8250_probe(struct platform_device *pdev)
err = dw8250_probe_of(&uart.port);
if (err)
return err;
+ } else if (ACPI_HANDLE(&pdev->dev)) {
+ err = dw8250_probe_acpi(&uart.port);
+ if (err)
+ return err;
} else {
return -ENODEV;
}
@@ -258,11 +291,19 @@ static const struct of_device_id dw8250_of_match[] = {
};
MODULE_DEVICE_TABLE(of, dw8250_of_match);
+static const struct acpi_device_id dw8250_acpi_match[] = {
+ { "INT33C4", 100000000 },
+ { "INT33C5", 100000000 },
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match);
+
static struct platform_driver dw8250_platform_driver = {
.driver = {
.name = "dw-apb-uart",
.owner = THIS_MODULE,
.of_match_table = dw8250_of_match,
+ .acpi_match_table = ACPI_PTR(dw8250_acpi_match),
},
.probe = dw8250_probe,
.remove = dw8250_remove,
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index c31133a..11adff1 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -265,7 +265,7 @@ config SERIAL_8250_FSL
config SERIAL_8250_DW
tristate "Support for Synopsys DesignWare 8250 quirks"
- depends on SERIAL_8250 && OF
+ depends on SERIAL_8250
help
Selecting this option will enable handling of the extra features
present in the Synopsys DesignWare APB UART.
--
1.7.10.4
^ permalink raw reply related
* Re: [PATCH] drivers/tty/serial: avoid double free after call ioc4_serial_remove_one
From: Chen Gang @ 2013-01-10 8:03 UTC (permalink / raw)
To: alan; +Cc: linux-serial
In-Reply-To: <50DACC2F.5080302@asianux.com>
Hello Alan Cox:
can you have time to give a glance for it ?
I send it according to the MAINTAINER file,
if I send to an incorrect member, please tell me.
thanks.
gchen
于 2012年12月26日 18:06, Chen Gang 写道:
>
> before goto out5, soft, control, serial are all assigned to idd
> after finish call ioc4_serial_remove_one, all resources are released
> we need return instead of go on, or double free
>
> Signed-off-by: Chen Gang <gang.chen@asianux.com>
> ---
> drivers/tty/serial/ioc4_serial.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/drivers/tty/serial/ioc4_serial.c b/drivers/tty/serial/ioc4_serial.c
> index 3e7da10..c4e30b8 100644
> --- a/drivers/tty/serial/ioc4_serial.c
> +++ b/drivers/tty/serial/ioc4_serial.c
> @@ -2883,6 +2883,7 @@ ioc4_serial_attach_one(struct ioc4_driver_data *idd)
> /* error exits that give back resources */
> out5:
> ioc4_serial_remove_one(idd);
> + return ret;
> out4:
> kfree(soft);
> out3:
>
--
Chen Gang
Asianux Corporation
--
To unsubscribe from this list: send the line "unsubscribe linux-serial" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH] serial:ifx6x60:Delete SPI timer when shut down port
From: channing @ 2013-01-10 5:06 UTC (permalink / raw)
To: alan; +Cc: greg, richardx.r.gorby, jun.d.chen, linux-serial, linux-kernel
When shut down SPI port, it's possible that MRDY has been asserted and a SPI
timer was activated waiting for SRDY assert, in the case, it needs to delete
this timer.
Signed-off-by: Chen Jun <jun.d.chen@intel.com>
Signed-off-by: channing <chao.bi@intel.com>
---
drivers/tty/serial/ifx6x60.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c
index 675d94a..7eed323 100644
--- a/drivers/tty/serial/ifx6x60.c
+++ b/drivers/tty/serial/ifx6x60.c
@@ -637,6 +637,7 @@ static void ifx_port_shutdown(struct tty_port *port)
clear_bit(IFX_SPI_STATE_IO_AVAILABLE, &ifx_dev->flags);
mrdy_set_low(ifx_dev);
+ del_timer(&ifx_dev->spi_timer);
clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags);
tasklet_kill(&ifx_dev->io_work_tasklet);
}
--
1.7.1
^ permalink raw reply related
* Re: [PATCHv2 0/5] serial: 8250: 8250_dw changes and dynamic capabilities
From: Heikki Krogerus @ 2013-01-09 9:22 UTC (permalink / raw)
To: Greg Kroah-Hartman; +Cc: Alan Cox, Jamie Iles, linux-serial, LKML
In-Reply-To: <1354533479-27306-1-git-send-email-heikki.krogerus@linux.intel.com>
Hi,
On Mon, Dec 03, 2012 at 01:17:54PM +0200, Heikki Krogerus wrote:
> Changes since v1:
> - rebased on top of Greg's tty-next
>
> These are mainly small 8250_dw.c changes. The interesting patch is
> probable the first one that changes 8250.c so the drivers are able to
> deliver their UART's capabilities when they are registering ports.
I will make one more version of this set. I'll add ACPI support for
8250_dw.c, and also introduce dmaengine support for 8250.c.
--
heikki
^ permalink raw reply
* [RFC PATCH v4 3/3] UART: Add dummy devices to test the enumeration.
From: Lv Zheng @ 2013-01-09 9:18 UTC (permalink / raw)
To: Len Brown, Rafael J Wysocki, Greg Kroah-Hartman, Alan Cox,
Mika Westerberg
Cc: linux-acpi, linux-serial, Lv Zheng
In-Reply-To: <cover.1357837482.git.lv.zheng@intel.com>
This is a test patch that should not be merged into any of the published
Linux source tree.
The test is based on the following customized DSDT (containing the dummy
uart host adapter INTF000 and target device INTF001):
1. customized DSDT:
Device (UA00)
{
Name (_HID, "INTF000") // _HID: Hardware ID
Name (RBUF, ResourceTemplate ()
{
Memory32Fixed (ReadWrite,
0x00000000, // Address Base
0x00001000) // Address Length
})
Method (_CRS, 0, NotSerialized) // _CRS: Current Resource Settings
{
Return (RBUF)
}
Method (_STA, 0, NotSerialized) // _STA: Status
{
Return (0x0F)
}
Device (BTH0)
{
Name (_HID, "INTF001") // _HID: Hardware ID
Name (_CID, "PNPF001") // _CID: Compatible ID
Method (_CRS, 0, NotSerialized) // _CRS: Current Resource Settings
{
Name (UBUF, ResourceTemplate ()
{
UartSerialBus (0x0001C200, DataBitsEight, StopBitsOne,
0xC0, LittleEndian, ParityTypeNone, FlowControlHardware,
0x0020, 0x0020, "\\_SB.PCI0.UA00",
0x00, ResourceConsumer, ,
)
})
Return (UBUF)
}
Method (_STA, 0, NotSerialized) // _STA: Status
{
Return (0x0F)
}
}
}
2. uevent monitor:
# udevadm monitor --kernel --environment > ~/uart.uevents
# echo add > /sys/class/tty/uevent
# echo add > /sys/class/tty/devices/BTH0:00/uevent
# cat ~/uart.uevents
monitor will print the received events for:
KERNEL - the kernel uevent
KERNEL[252.443458] add /bus/tty_enum (bus)
ACTION=add
DEVPATH=/bus/tty_enum
SEQNUM=1142
SUBSYSTEM=bus
KERNEL[268.491709] add /devices/platform/INTF000:00/tty/ttyS0/BTH0:00 (tty)
ACTION=add
DEVPATH=/devices/platform/INTF000:00/tty/ttyS0/BTH0:00
DEVTYPE=tty_slave
MODALIAS=tty::INTF001:PNPF001:
SEQNUM=1144
SUBSYSTEM=tty
3. kobjects attributes and links:
# cat /sys/bus/tty_enum/devices/BTH0:00/modalias
tty::INTF001:PNPF001:
# cat /sys/bus/tty_enum/devices/BTH0:00/tty_attrs
115200 8N0 HW
# cat /sys/bus/tty_enum/devices/BTH0:00/modem_lines
LE:RTS,CTS,
# ls -l /sys/bus/tty_enum/devices/
BTH0:00 -> ../../../devices/platform/INTF000:00/tty/ttyS0/tty/BTH0:00
# ls -l /sys/devices/platform/INTF000:00/tty/ttyS0/BTH0:00/
firmware_node -> ../../../../../LNXSYSTM:00/device:00/INTF000:00/INTF001:00
subsystem -> ../../../../../../bus/tty_enum
# ls -l /sys/bus/acpi/devices/INTF001:00/
physical_node -> ../../../../pnp0/00:00
physical_node1 -> ../../../../platform/INTF000:00/tty/ttyS0/BTH0:00
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
drivers/acpi/scan.c | 1 +
drivers/tty/serial/8250/8250.c | 5 +-
drivers/tty/serial/8250/8250_dummy.c | 103 ++++++++++++++++++++++++++++++++++
drivers/tty/serial/8250/Kconfig | 10 ++++
drivers/tty/serial/8250/Makefile | 1 +
include/linux/serial_8250.h | 4 ++
include/linux/serial_core.h | 12 ++++
7 files changed, 133 insertions(+), 3 deletions(-)
create mode 100644 drivers/tty/serial/8250/8250_dummy.c
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 53502d1..56611f3 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -36,6 +36,7 @@ static const char *dummy_hid = "device";
static const struct acpi_device_id acpi_platform_device_ids[] = {
{ "PNP0D40" },
+ { "INTF000" },
/* Haswell LPSS devices */
{ "INT33C0", 0 },
diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c
index d085e3a..32dfad4 100644
--- a/drivers/tty/serial/8250/8250.c
+++ b/drivers/tty/serial/8250/8250.c
@@ -56,8 +56,6 @@ static unsigned int share_irqs = SERIAL8250_SHARE_IRQS;
static unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS;
-static struct uart_driver serial8250_reg;
-
static int serial_index(struct uart_port *port)
{
return (serial8250_reg.minor - 64) + port->line;
@@ -2978,7 +2976,7 @@ int serial8250_find_port(struct uart_port *p)
#define SERIAL8250_CONSOLE NULL
#endif
-static struct uart_driver serial8250_reg = {
+struct uart_driver serial8250_reg = {
.owner = THIS_MODULE,
.driver_name = "serial",
.dev_name = "ttyS",
@@ -2986,6 +2984,7 @@ static struct uart_driver serial8250_reg = {
.minor = 64,
.cons = SERIAL8250_CONSOLE,
};
+EXPORT_SYMBOL_GPL(serial8250_reg);
/*
* early_serial_setup - early registration for 8250 ports
diff --git a/drivers/tty/serial/8250/8250_dummy.c b/drivers/tty/serial/8250/8250_dummy.c
new file mode 100644
index 0000000..e5aadeb
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_dummy.c
@@ -0,0 +1,103 @@
+/*
+ * 8250_dummy.c: Dummy 8250 UART target device enumerator
+ *
+ * Copyright (c) 2012, Intel Corporation
+ * Author: Lv Zheng <lv.zheng@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ */
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/serial_8250.h>
+#include <linux/acpi.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+struct dummy8250_data {
+ int last_lcr;
+ int line;
+};
+
+static void dummy8250_serial_out(struct uart_port *p, int offset, int value)
+{
+}
+
+static unsigned int dummy8250_serial_in(struct uart_port *p, int offset)
+{
+ return 0;
+}
+
+static int __devinit dummy8250_probe(struct platform_device *pdev)
+{
+ struct uart_8250_port uart = {};
+ struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ struct dummy8250_data *data;
+
+ if (!regs) {
+ dev_err(&pdev->dev, "no registers defined\n");
+ return -EINVAL;
+ }
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+ uart.port.private_data = data;
+
+ spin_lock_init(&uart.port.lock);
+ uart.port.mapbase = regs->start;
+ uart.port.type = PORT_8250;
+ uart.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP |
+ UPF_FIXED_PORT | UPF_FIXED_TYPE;
+ uart.port.dev = &pdev->dev;
+
+ uart.port.iotype = UPIO_MEM;
+ uart.port.serial_in = dummy8250_serial_in;
+ uart.port.serial_out = dummy8250_serial_out;
+ uart.port.uartclk = 40000000;
+
+ data->line = serial8250_register_8250_port(&uart);
+ if (data->line < 0)
+ return data->line;
+
+#ifdef CONFIG_ACPI_UART
+ acpi_uart_register_devices(serial8250_tty_port(data->line));
+#endif
+ platform_set_drvdata(pdev, data);
+
+ return 0;
+}
+
+static int __devexit dummy8250_remove(struct platform_device *pdev)
+{
+ struct dummy8250_data *data = platform_get_drvdata(pdev);
+
+ serial8250_unregister_port(data->line);
+ return 0;
+}
+
+static const struct acpi_device_id dummy8250_match[] = {
+ { .id = "INTF000" },
+ { /* Sentinel */ }
+};
+MODULE_DEVICE_TABLE(acpi, dummy8250_match);
+
+static struct platform_driver dummy8250_platform_driver = {
+ .driver = {
+ .name = "dummy-uart",
+ .owner = THIS_MODULE,
+ .acpi_match_table = dummy8250_match,
+ },
+ .probe = dummy8250_probe,
+ .remove = __devexit_p(dummy8250_remove),
+};
+
+module_platform_driver(dummy8250_platform_driver);
+
+MODULE_AUTHOR("Lv Zheng");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Dummy 8250 serial port driver");
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index c31133a..3f04247 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -270,6 +270,16 @@ config SERIAL_8250_DW
Selecting this option will enable handling of the extra features
present in the Synopsys DesignWare APB UART.
+config SERIAL_8250_DUMMY
+ tristate "Support for dummy ACPI 8250"
+ depends on SERIAL_8250 && ACPI
+ help
+ Selecting this option will enable a test UART target device DUMMY
+ under the ISA serial8250 and a test UART host adapter INTF000
+ as an platform device for the purpose of testing the ACPI UART
+ enumeration support.
+ If unsure, say "N" here.
+
config SERIAL_8250_EM
tristate "Support for Emma Mobile integrated serial port"
depends on SERIAL_8250 && ARM && HAVE_CLK
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index 108fe7f..fb82aa9 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -19,3 +19,4 @@ obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o
obj-$(CONFIG_SERIAL_8250_FSL) += 8250_fsl.o
obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o
obj-$(CONFIG_SERIAL_8250_EM) += 8250_em.o
+obj-$(CONFIG_SERIAL_8250_DUMMY) += 8250_dummy.o
diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h
index c490d20..c7aef78 100644
--- a/include/linux/serial_8250.h
+++ b/include/linux/serial_8250.h
@@ -96,6 +96,10 @@ struct uart_8250_port {
void (*dl_write)(struct uart_8250_port *, int);
};
+extern struct uart_driver serial8250_reg;
+
+#define serial8250_tty_port(line) uart_tty_port(&serial8250_reg, (line))
+
int serial8250_register_8250_port(struct uart_8250_port *);
void serial8250_unregister_port(int line);
void serial8250_suspend_port(int line);
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index c6690a2..59f8582 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -246,6 +246,18 @@ struct uart_driver {
struct tty_driver *tty_driver;
};
+static inline struct tty_port *uart_tty_port(struct uart_driver *drv,
+ unsigned int line)
+{
+ struct uart_state *state;
+
+ if (line >= drv->nr)
+ return NULL;
+
+ state = drv->state + line;
+ return &state->port;
+}
+
void uart_write_wakeup(struct uart_port *port);
/*
--
1.7.10
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox