* [U-Boot] [PATCH 1/8] Move simple_itoa to vsprintf
From: Simon Glass @ 2011-10-22 4:51 UTC (permalink / raw)
To: u-boot
In-Reply-To: <1319259100-11376-1-git-send-email-sjg@chromium.org>
This function is generally useful and shouldn't hide away in hush. It
has been moved as is.
Signed-off-by: Simon Glass <sjg@chromium.org>
---
common/hush.c | 15 ---------------
include/common.h | 1 +
lib/vsprintf.c | 16 ++++++++++++++++
3 files changed, 17 insertions(+), 15 deletions(-)
diff --git a/common/hush.c b/common/hush.c
index 85a6030..9bdb499 100644
--- a/common/hush.c
+++ b/common/hush.c
@@ -17,7 +17,6 @@
* Erik W. Troan, which they placed in the public domain. I don't know
* how much of the Johnson/Troan code has survived the repeated rewrites.
* Other credits:
- * simple_itoa() was lifted from boa-0.93.15
* b_addchr() derived from similar w_addchar function in glibc-2.2
* setup_redirect(), redirect_opt_num(), and big chunks of main()
* and many builtins derived from contributions by Erik Andersen
@@ -922,20 +921,6 @@ static int b_addqchr(o_string *o, int ch, int quote)
return b_addchr(o, ch);
}
-/* belongs in utility.c */
-char *simple_itoa(unsigned int i)
-{
- /* 21 digits plus null terminator, good for 64-bit or smaller ints */
- static char local[22];
- char *p = &local[21];
- *p-- = '\0';
- do {
- *p-- = '0' + i % 10;
- i /= 10;
- } while (i > 0);
- return p + 1;
-}
-
#ifndef __U_BOOT__
static int b_adduint(o_string *o, unsigned int i)
{
diff --git a/include/common.h b/include/common.h
index eb19a44..55f772d 100644
--- a/include/common.h
+++ b/include/common.h
@@ -702,6 +702,7 @@ void panic(const char *fmt, ...)
int sprintf(char * buf, const char *fmt, ...)
__attribute__ ((format (__printf__, 2, 3)));
int vsprintf(char *buf, const char *fmt, va_list args);
+char *simple_itoa(ulong i);
/* lib/strmhz.c */
char * strmhz(char *buf, unsigned long hz);
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 79dead3..e497a86 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -7,6 +7,8 @@
/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
/*
* Wirzenius wrote this portably, Torvalds fucked it up :-)
+ *
+ * from hush: simple_itoa() was lifted from boa-0.93.15
*/
#include <stdarg.h>
@@ -738,3 +740,17 @@ void __assert_fail(const char *assertion, const char *file, unsigned line,
panic("%s:%u: %s: Assertion `%s' failed.", file, line, function,
assertion);
}
+
+char *simple_itoa(ulong i)
+{
+ /* 21 digits plus null terminator, good for 64-bit or smaller ints */
+ static char local[22];
+ char *p = &local[21];
+
+ *p-- = '\0';
+ do {
+ *p-- = '0' + i % 10;
+ i /= 10;
+ } while (i > 0);
+ return p + 1;
+}
--
1.7.3.1
^ permalink raw reply related
* [U-Boot] [PATCH 0/8] Add tftpput command for uploading files over network
From: Simon Glass @ 2011-10-22 4:51 UTC (permalink / raw)
To: u-boot
The tftpboot command permits reading of files over a network interface
using the Trivial FTP protocol. This patch series adds the ability to
transfer files the other way.
Why is this useful?
- Uploading boot time data to a server
- Uploading profiling information
- Uploading large mounts of data for comparison / checking on a host
(e.g. use tftpput and ghex2 instead of the 'md' command)
Mostly the existing code can be re-used and I have tried to avoid too
much refactoring or cleaning up.
The feature is activated by the CONFIG_CMD_TFTPPUT option.
This has been very lightly tested on a Seaboard with a USB network
adaptor. I don't think it handles block number overflow.
Simon Glass (8):
Move simple_itoa to vsprintf
Add setenv_uint() and setenv_addr()
tftpput: Rename TFTP to TFTPGET
tftpput: move common code into separate functions
tftpput: support selecting get/put for tftp
tftpput: add save_addr and save_size global variables
tftpput: implement tftp logic
tftpput: add tftpput command
README | 2 +
common/cmd_net.c | 31 +++++++-
common/cmd_nvedit.c | 31 ++++++++
common/hush.c | 15 ----
include/common.h | 5 +
include/config_cmd_all.h | 1 +
include/net.h | 8 +-
lib/vsprintf.c | 16 ++++
net/bootp.c | 2 +-
net/net.c | 22 +++---
net/tftp.c | 189 +++++++++++++++++++++++++++++++++-------------
net/tftp.h | 2 +-
12 files changed, 238 insertions(+), 86 deletions(-)
--
1.7.3.1
^ permalink raw reply
* Re: [PATCH 01/11] swiotlb: Expose swiotlb_nr_tlb function to modules
From: FUJITA Tomonori @ 2011-10-22 4:49 UTC (permalink / raw)
To: konrad.wilk
Cc: thellstrom, xen-devel, thomas, linux-kernel, dri-devel,
fujita.tomonori, j.glisse, airlied, bskeggs
In-Reply-To: <1319062772-2793-2-git-send-email-konrad.wilk@oracle.com>
On Wed, 19 Oct 2011 18:19:22 -0400
Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> wrote:
> As a mechanism to detect whether SWIOTLB is enabled or not.
> We also fix the spelling - it was swioltb instead of
> swiotlb.
>
> CC: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
> [v1: Ripped out swiotlb_enabled]
> Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
> ---
> drivers/xen/swiotlb-xen.c | 2 +-
> include/linux/swiotlb.h | 2 +-
> lib/swiotlb.c | 5 +++--
> 3 files changed, 5 insertions(+), 4 deletions(-)
Acked-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
^ permalink raw reply
* Re: [PATCH 0/7] writeback: avoid touching dirtied_when on blocked inodes
From: Wu Fengguang @ 2011-10-22 4:46 UTC (permalink / raw)
To: linux-fsdevel@vger.kernel.org
Cc: Jan Kara, Dave Chinner, Christoph Hellwig, Andrew Morton, LKML
In-Reply-To: <20111020152240.751936131@intel.com>
Hi,
I get some test results for this patch: basically it's good until
patch 4. Further more, I got minor regressions when apply several
combinations of patches 5-7 and Jan's patch for the I_SYNC case.
[PATCH 1/7] writeback: introduce queue b_more_io_wait
[PATCH 2/7] writeback: avoid redirtying when ->write_inode failed to clear I_DIR
[PATCH 3/7] writeback: update wb->last_active on written pages/inodes
[PATCH 4/7] writeback: Retry kupdate work early if we need to retry some inode w
[PATCH 5/7] writeback: requeue_io_wait() on pages_skipped inode
[PATCH 6/7] writeback: requeue_io_wait() on blocked inode
[PATCH 7/7] writeback: requeue_io_wait() when failed to grab superblock
Based on the below results, I'd like to push only patches 1-4 to
linux-next and hold back the other patches for more investigation.
Overall throughput increases +1.2% if applying only patches 1-4:
3.1.0-rc9-ioless-full-next-20111014+ 3.1.0-rc9-ioless-full-more_io_wait-5-next-20111014+
------------------------ ------------------------
56.47 +3.1% 58.22 thresh=100M/btrfs-10dd-4k-8p-4096M-100M:10-X
56.28 +1.6% 57.20 thresh=100M/btrfs-1dd-4k-8p-4096M-100M:10-X
56.11 +2.6% 57.56 thresh=100M/btrfs-2dd-4k-8p-4096M-100M:10-X
37.86 +3.5% 39.20 thresh=100M/ext3-10dd-4k-8p-4096M-100M:10-X
45.91 +2.2% 46.92 thresh=100M/ext3-1dd-4k-8p-4096M-100M:10-X
41.87 +2.7% 42.98 thresh=100M/ext3-2dd-4k-8p-4096M-100M:10-X
45.68 +1.7% 46.43 thresh=100M/ext4-10dd-4k-8p-4096M-100M:10-X
55.74 +1.2% 56.41 thresh=100M/ext4-1dd-4k-8p-4096M-100M:10-X
53.32 +0.7% 53.71 thresh=100M/ext4-2dd-4k-8p-4096M-100M:10-X
46.20 -2.6% 44.99 thresh=100M/xfs-10dd-4k-8p-4096M-100M:10-X
55.72 +3.9% 57.90 thresh=100M/xfs-1dd-4k-8p-4096M-100M:10-X
54.01 +0.4% 54.21 thresh=100M/xfs-2dd-4k-8p-4096M-100M:10-X
55.08 +2.0% 56.17 thresh=1G/btrfs-100dd-4k-8p-4096M-1024M:10-X
55.49 +1.3% 56.24 thresh=1G/btrfs-10dd-4k-8p-4096M-1024M:10-X
55.38 +1.7% 56.30 thresh=1G/btrfs-1dd-4k-8p-4096M-1024M:10-X
36.70 +0.7% 36.96 thresh=1G/ext3-100dd-4k-8p-4096M-1024M:10-X
40.64 +0.3% 40.77 thresh=1G/ext3-10dd-4k-8p-4096M-1024M:10-X
48.65 +1.6% 49.45 thresh=1G/ext3-1dd-4k-8p-4096M-1024M:10-X
49.84 -2.6% 48.53 thresh=1G/ext4-100dd-4k-8p-4096M-1024M:10-X
56.03 -1.2% 55.34 thresh=1G/ext4-10dd-4k-8p-4096M-1024M:10-X
57.42 +0.2% 57.52 thresh=1G/ext4-1dd-4k-8p-4096M-1024M:10-X
45.74 +0.4% 45.92 thresh=1G/xfs-100dd-4k-8p-4096M-1024M:10-X
54.19 -0.7% 53.79 thresh=1G/xfs-10dd-4k-8p-4096M-1024M:10-X
55.93 -0.4% 55.72 thresh=1G/xfs-1dd-4k-8p-4096M-1024M:10-X
35.78 -0.0% 35.77 thresh=8M/ext4-10dd-4k-8p-4096M-8M:10-X
55.29 +2.1% 56.43 thresh=8M/ext4-1dd-4k-8p-4096M-8M:10-X
51.12 +1.6% 51.94 thresh=8M/ext4-2dd-4k-8p-4096M-8M:10-X
31.21 +0.9% 31.48 thresh=8M/xfs-10dd-4k-8p-4096M-8M:10-X
54.10 +3.9% 56.22 thresh=8M/xfs-1dd-4k-8p-4096M-8M:10-X
46.97 +3.8% 48.75 thresh=8M/xfs-2dd-4k-8p-4096M-8M:10-X
1490.73 +1.2% 1509.03 TOTAL write_bw
Overall throughput after the patchset increases +1.6% if replacing
patch 5 with another patch to remove redirty_tail() on pages_skipped:
3.1.0-rc9-ioless-full-more_io_wait-next-20111014+ 3.1.0-rc9-ioless-full-more_io_wait-7-next-20111014+
------------------------ ------------------------
46.22 +0.8% 46.58 thresh=100M/ext3-1dd-4k-8p-4096M-100M:10-X
42.19 +1.2% 42.68 thresh=100M/ext3-2dd-4k-8p-4096M-100M:10-X
45.50 +1.2% 46.06 thresh=100M/ext4-10dd-4k-8p-4096M-100M:10-X
54.51 +0.9% 54.97 thresh=100M/ext4-1dd-4k-8p-4096M-100M:10-X
53.19 +1.2% 53.83 thresh=100M/ext4-2dd-4k-8p-4096M-100M:10-X
43.98 +0.3% 44.11 thresh=100M/xfs-10dd-4k-8p-4096M-100M:10-X
55.76 +2.7% 57.25 thresh=100M/xfs-1dd-4k-8p-4096M-100M:10-X
52.94 +2.5% 54.29 thresh=100M/xfs-2dd-4k-8p-4096M-100M:10-X
54.52 +1.6% 55.36 thresh=1G/btrfs-100dd-4k-8p-4096M-1024M:10-X
54.94 +0.8% 55.40 thresh=1G/btrfs-10dd-4k-8p-4096M-1024M:10-X
53.91 +1.9% 54.96 thresh=1G/btrfs-1dd-4k-8p-4096M-1024M:10-X
36.15 +1.0% 36.53 thresh=1G/ext3-100dd-4k-8p-4096M-1024M:10-X
38.25 +6.7% 40.80 thresh=1G/ext3-10dd-4k-8p-4096M-1024M:10-X
45.30 +8.7% 49.24 thresh=1G/ext3-1dd-4k-8p-4096M-1024M:10-X
48.23 +1.5% 48.93 thresh=1G/ext4-100dd-4k-8p-4096M-1024M:10-X
54.21 +0.4% 54.41 thresh=1G/ext4-10dd-4k-8p-4096M-1024M:10-X
56.07 +1.4% 56.86 thresh=1G/ext4-1dd-4k-8p-4096M-1024M:10-X
45.12 -5.8% 42.52 thresh=1G/xfs-100dd-4k-8p-4096M-1024M:10-X
53.94 +1.3% 54.67 thresh=1G/xfs-10dd-4k-8p-4096M-1024M:10-X
55.66 +2.7% 57.15 thresh=1G/xfs-1dd-4k-8p-4096M-1024M:10-X
990.58 +1.6% 1006.59 TOTAL write_bw
But in general the performance is slightly worse when doing anything
more than patches 1-4.
patches 1-4 VS patches 1-4 plus requeue_io_wait() on I_SYNC
3.1.0-rc9-ioless-full-more_io_wait-5-next-20111014+ 3.1.0-rc9-ioless-full-more_io_wait-9-next-20111014+
------------------------ ------------------------
58.22 -3.2% 56.38 thresh=100M/btrfs-10dd-4k-8p-4096M-100M:10-X
57.20 -1.1% 56.56 thresh=100M/btrfs-1dd-4k-8p-4096M-100M:10-X
57.56 -2.3% 56.26 thresh=100M/btrfs-2dd-4k-8p-4096M-100M:10-X
39.20 -0.8% 38.87 thresh=100M/ext3-10dd-4k-8p-4096M-100M:10-X
46.92 +0.1% 46.98 thresh=100M/ext3-1dd-4k-8p-4096M-100M:10-X
42.98 -0.7% 42.70 thresh=100M/ext3-2dd-4k-8p-4096M-100M:10-X
46.43 -0.6% 46.14 thresh=100M/ext4-10dd-4k-8p-4096M-100M:10-X
56.41 +0.1% 56.47 thresh=100M/ext4-1dd-4k-8p-4096M-100M:10-X
53.71 +1.6% 54.58 thresh=100M/ext4-2dd-4k-8p-4096M-100M:10-X
44.99 +0.4% 45.18 thresh=100M/xfs-10dd-4k-8p-4096M-100M:10-X
57.90 -0.4% 57.66 thresh=100M/xfs-1dd-4k-8p-4096M-100M:10-X
54.21 +1.2% 54.85 thresh=100M/xfs-2dd-4k-8p-4096M-100M:10-X
56.17 -0.6% 55.81 thresh=1G/btrfs-100dd-4k-8p-4096M-1024M:10-X
56.24 -1.8% 55.20 thresh=1G/btrfs-10dd-4k-8p-4096M-1024M:10-X
56.30 -2.1% 55.13 thresh=1G/btrfs-1dd-4k-8p-4096M-1024M:10-X
36.96 -2.0% 36.23 thresh=1G/ext3-100dd-4k-8p-4096M-1024M:10-X
40.77 -0.2% 40.68 thresh=1G/ext3-10dd-4k-8p-4096M-1024M:10-X
49.45 -0.6% 49.14 thresh=1G/ext3-1dd-4k-8p-4096M-1024M:10-X
48.53 -1.6% 47.77 thresh=1G/ext4-100dd-4k-8p-4096M-1024M:10-X
55.34 -0.8% 54.89 thresh=1G/ext4-10dd-4k-8p-4096M-1024M:10-X
57.52 -1.5% 56.67 thresh=1G/ext4-1dd-4k-8p-4096M-1024M:10-X
45.92 -7.2% 42.63 thresh=1G/xfs-100dd-4k-8p-4096M-1024M:10-X
53.79 -1.0% 53.25 thresh=1G/xfs-10dd-4k-8p-4096M-1024M:10-X
55.72 +2.4% 57.04 thresh=1G/xfs-1dd-4k-8p-4096M-1024M:10-X
56.22 -2.2% 54.96 thresh=8M/xfs-1dd-4k-8p-4096M-8M:10-X
1284.66 -1.0% 1272.05 TOTAL write_bw
patches 1-4 VS patches 1-4,7 and remove redirty_tail() on pages_skipped
3.1.0-rc9-ioless-full-more_io_wait-5-next-20111014+ 3.1.0-rc9-ioless-full-more_io_wait-8-next-20111014+
------------------------ ------------------------
58.22 -2.9% 56.55 thresh=100M/btrfs-10dd-4k-8p-4096M-100M:10-X
57.20 -2.0% 56.03 thresh=100M/btrfs-1dd-4k-8p-4096M-100M:10-X
57.56 -2.1% 56.38 thresh=100M/btrfs-2dd-4k-8p-4096M-100M:10-X
39.20 -0.4% 39.06 thresh=100M/ext3-10dd-4k-8p-4096M-100M:10-X
46.92 -0.5% 46.68 thresh=100M/ext3-1dd-4k-8p-4096M-100M:10-X
42.98 -1.2% 42.45 thresh=100M/ext3-2dd-4k-8p-4096M-100M:10-X
46.43 -1.2% 45.89 thresh=100M/ext4-10dd-4k-8p-4096M-100M:10-X
56.41 -2.5% 54.98 thresh=100M/ext4-1dd-4k-8p-4096M-100M:10-X
53.71 -1.4% 52.96 thresh=100M/ext4-2dd-4k-8p-4096M-100M:10-X
44.99 -1.4% 44.36 thresh=100M/xfs-10dd-4k-8p-4096M-100M:10-X
57.90 -0.8% 57.42 thresh=100M/xfs-1dd-4k-8p-4096M-100M:10-X
54.21 -0.7% 53.84 thresh=100M/xfs-2dd-4k-8p-4096M-100M:10-X
56.17 -1.1% 55.57 thresh=1G/btrfs-100dd-4k-8p-4096M-1024M:10-X
56.24 -1.1% 55.61 thresh=1G/btrfs-10dd-4k-8p-4096M-1024M:10-X
56.30 -1.5% 55.47 thresh=1G/btrfs-1dd-4k-8p-4096M-1024M:10-X
36.96 -2.0% 36.23 thresh=1G/ext3-100dd-4k-8p-4096M-1024M:10-X
40.77 -0.8% 40.45 thresh=1G/ext3-10dd-4k-8p-4096M-1024M:10-X
49.45 -1.5% 48.71 thresh=1G/ext3-1dd-4k-8p-4096M-1024M:10-X
48.53 -2.8% 47.17 thresh=1G/ext4-100dd-4k-8p-4096M-1024M:10-X
55.34 -2.3% 54.05 thresh=1G/ext4-10dd-4k-8p-4096M-1024M:10-X
57.52 -3.6% 55.47 thresh=1G/ext4-1dd-4k-8p-4096M-1024M:10-X
45.92 +3.0% 47.30 thresh=1G/xfs-100dd-4k-8p-4096M-1024M:10-X
53.79 -2.3% 52.54 thresh=1G/xfs-10dd-4k-8p-4096M-1024M:10-X
55.72 +2.3% 57.02 thresh=1G/xfs-1dd-4k-8p-4096M-1024M:10-X
35.77 -0.7% 35.54 thresh=8M/ext4-10dd-4k-8p-4096M-8M:10-X
56.43 -2.8% 54.86 thresh=8M/ext4-1dd-4k-8p-4096M-8M:10-X
51.94 -2.7% 50.52 thresh=8M/ext4-2dd-4k-8p-4096M-8M:10-X
31.48 -0.7% 31.25 thresh=8M/xfs-10dd-4k-8p-4096M-8M:10-X
56.22 -2.2% 55.00 thresh=8M/xfs-1dd-4k-8p-4096M-8M:10-X
48.75 -2.1% 47.73 thresh=8M/xfs-2dd-4k-8p-4096M-8M:10-X
1509.03 -1.5% 1487.08 TOTAL write_bw
patches 1-4 VS patches 1-4,6 and remove redirty_tail() on pages_skipped
3.1.0-rc9-ioless-full-more_io_wait-5-next-20111014+ 3.1.0-rc9-ioless-full-more_io_wait-6-next-20111014+
------------------------ ------------------------
57.90 -0.7% 57.48 thresh=100M/xfs-1dd-4k-8p-4096M-100M:10-X
54.21 -0.4% 54.01 thresh=100M/xfs-2dd-4k-8p-4096M-100M:10-X
56.17 -1.1% 55.57 thresh=1G/btrfs-100dd-4k-8p-4096M-1024M:10-X
56.24 -1.5% 55.37 thresh=1G/btrfs-10dd-4k-8p-4096M-1024M:10-X
56.30 -1.6% 55.38 thresh=1G/btrfs-1dd-4k-8p-4096M-1024M:10-X
36.96 -1.8% 36.28 thresh=1G/ext3-100dd-4k-8p-4096M-1024M:10-X
40.77 -1.0% 40.37 thresh=1G/ext3-10dd-4k-8p-4096M-1024M:10-X
49.45 -0.5% 49.20 thresh=1G/ext3-1dd-4k-8p-4096M-1024M:10-X
48.53 +0.3% 48.68 thresh=1G/ext4-100dd-4k-8p-4096M-1024M:10-X
55.34 -1.8% 54.34 thresh=1G/ext4-10dd-4k-8p-4096M-1024M:10-X
57.52 -0.9% 57.03 thresh=1G/ext4-1dd-4k-8p-4096M-1024M:10-X
45.92 -0.5% 45.68 thresh=1G/xfs-100dd-4k-8p-4096M-1024M:10-X
53.79 +3.2% 55.52 thresh=1G/xfs-10dd-4k-8p-4096M-1024M:10-X
55.72 +3.2% 57.51 thresh=1G/xfs-1dd-4k-8p-4096M-1024M:10-X
724.81 -0.3% 722.43 TOTAL write_bw
patches 1-4 VS patches 1-4,6,7 and remove redirty_tail() on pages_skipped
3.1.0-rc9-ioless-full-more_io_wait-5-next-20111014+ 3.1.0-rc9-ioless-full-more_io_wait-7-next-20111014+
------------------------ ------------------------
46.92 -0.7% 46.58 thresh=100M/ext3-1dd-4k-8p-4096M-100M:10-X
42.98 -0.7% 42.68 thresh=100M/ext3-2dd-4k-8p-4096M-100M:10-X
46.43 -0.8% 46.06 thresh=100M/ext4-10dd-4k-8p-4096M-100M:10-X
56.41 -2.5% 54.97 thresh=100M/ext4-1dd-4k-8p-4096M-100M:10-X
53.71 +0.2% 53.83 thresh=100M/ext4-2dd-4k-8p-4096M-100M:10-X
44.99 -2.0% 44.11 thresh=100M/xfs-10dd-4k-8p-4096M-100M:10-X
57.90 -1.1% 57.25 thresh=100M/xfs-1dd-4k-8p-4096M-100M:10-X
54.21 +0.1% 54.29 thresh=100M/xfs-2dd-4k-8p-4096M-100M:10-X
56.17 -1.4% 55.36 thresh=1G/btrfs-100dd-4k-8p-4096M-1024M:10-X
56.24 -1.5% 55.40 thresh=1G/btrfs-10dd-4k-8p-4096M-1024M:10-X
56.30 -2.4% 54.96 thresh=1G/btrfs-1dd-4k-8p-4096M-1024M:10-X
36.96 -1.2% 36.53 thresh=1G/ext3-100dd-4k-8p-4096M-1024M:10-X
40.77 +0.1% 40.80 thresh=1G/ext3-10dd-4k-8p-4096M-1024M:10-X
49.45 -0.4% 49.24 thresh=1G/ext3-1dd-4k-8p-4096M-1024M:10-X
48.53 +0.8% 48.93 thresh=1G/ext4-100dd-4k-8p-4096M-1024M:10-X
55.34 -1.7% 54.41 thresh=1G/ext4-10dd-4k-8p-4096M-1024M:10-X
57.52 -1.2% 56.86 thresh=1G/ext4-1dd-4k-8p-4096M-1024M:10-X
45.92 -7.4% 42.52 thresh=1G/xfs-100dd-4k-8p-4096M-1024M:10-X
53.79 +1.6% 54.67 thresh=1G/xfs-10dd-4k-8p-4096M-1024M:10-X
55.72 +2.6% 57.15 thresh=1G/xfs-1dd-4k-8p-4096M-1024M:10-X
1016.26 -1.0% 1006.59 TOTAL write_bw
Thanks,
Fengguang
^ permalink raw reply
* Re: [PATCH] x86-64: Set siginfo and context on vsyscall emulation faults
From: Linus Torvalds @ 2011-10-22 4:46 UTC (permalink / raw)
To: Andy Lutomirski
Cc: x86, Ingo Molnar, richard -rw- weinberger, Adrian Bunk,
H. Peter Anvin, Thomas Gleixner, Ingo Molnar, linux-kernel
In-Reply-To: <1c0cef7faec24db26e2a6397fa8843089824750f.1319230509.git.luto@mit.edu>
On Sat, Oct 22, 2011 at 12:01 AM, Andy Lutomirski <luto@amacapital.net> wrote:
>
> +static bool write_ok_or_segv(unsigned long ptr, size_t size)
> +{
> + if (ptr == 0)
> + return true;
Why is ptr==0 special? That makes no sense.
Also, this whole function makes the notion of setting the "sigsegv on
fault" flag much less interesting. It would be much better if
access_ok() (including the cases embedded in get_user/put_user/etc)
just did it right automatically for everything, rather than
special-casing it for just this.
I wonder if we could just make access_ok() use a trap instead of just
the regular compares (and then in the trap handler do the same logic
as in the page fault handler)? Sadly, the 'bounds' instruction doesn't
work for this (in 32-bit mode it does a *signed* compare, and in
64-bit mode it no longer exists), but something like that might.
That said, I think that your patch looks acceptable as a "let's fix
vsyscalls without doing the bigger change". But I really don't see why
ptr==0 would be special.
So I think your write_ok_or_segv() function should just be
static bool write_ok_or_segv(unsigned long ptr, size_t size)
{
if (access_ok(ptr, size))
return true;
.. send signal ...
return false;
}
instead of that odd thing you have now.
Linus
^ permalink raw reply
* Re: [Qemu-devel] [V2 PATCH] rtl8139: check the buffer availiability
From: Jason Wang @ 2011-10-22 4:30 UTC (permalink / raw)
To: Michael S. Tsirkin; +Cc: blauwirbel, aliguori, qemu-devel, stefanha
In-Reply-To: <20111019012811.GA11400@redhat.com>
On 10/19/2011 09:28 AM, Michael S. Tsirkin wrote:
> On Mon, Oct 17, 2011 at 10:55:57AM +0800, Jason Wang wrote:
>> Reduce spurious packet drops on RX ring empty when in c+ mode by verifying that
>> we have at least 1 buffer ahead of the time.
>>
>> Change from v1:
>> Fix style comments from Stefan.
>>
>> Signed-off-by: Jason Wang <jasowang@redhat.com>
>> ---
>> hw/rtl8139.c | 44 ++++++++++++++++++++++++++++++--------------
>> 1 files changed, 30 insertions(+), 14 deletions(-)
>>
>> diff --git a/hw/rtl8139.c b/hw/rtl8139.c
>> index 3753950..bcbc5e3 100644
>> --- a/hw/rtl8139.c
>> +++ b/hw/rtl8139.c
>> @@ -84,6 +84,19 @@
>> #define VLAN_TCI_LEN 2
>> #define VLAN_HLEN (ETHER_TYPE_LEN + VLAN_TCI_LEN)
>>
>> +/* w0 ownership flag */
>> +#define CP_RX_OWN (1<<31)
>> +/* w0 end of ring flag */
>> +#define CP_RX_EOR (1<<30)
>> +/* w0 bits 0...12 : buffer size */
>> +#define CP_RX_BUFFER_SIZE_MASK ((1<<13) - 1)
>> +/* w1 tag available flag */
>> +#define CP_RX_TAVA (1<<16)
>> +/* w1 bits 0...15 : VLAN tag */
>> +#define CP_RX_VLAN_TAG_MASK ((1<<16) - 1)
>> +/* w2 low 32bit of Rx buffer ptr */
>> +/* w3 high 32bit of Rx buffer ptr */
>> +
>> #if defined (DEBUG_RTL8139)
>> # define DPRINTF(fmt, ...) \
>> do { fprintf(stderr, "RTL8139: " fmt, ## __VA_ARGS__); } while (0)
>> @@ -805,6 +818,22 @@ static inline target_phys_addr_t rtl8139_addr64(uint32_t low, uint32_t high)
>> #endif
>> }
>>
>> +/* Verify that we have at least one available rx buffer */
>> +static int rtl8139_cp_has_rxbuf(RTL8139State *s)
>> +{
>> + uint32_t val, rxdw0;
>> + target_phys_addr_t cplus_rx_ring_desc = rtl8139_addr64(s->RxRingAddrLO,
>> + s->RxRingAddrHI);
>> + cplus_rx_ring_desc += 16 * s->currCPlusRxDesc;
>> + cpu_physical_memory_read(cplus_rx_ring_desc, &val, 4);
>
> Interesting. Please note that cpu_physical_memory_read is not
> done atomically. Can guest be writing the value while
> we read it? If yes we'll get a corrupted value here,
> because CP_RX_OWN is the high bit so it is read last.
> Correct?
>
Yes, there's a race, we need use atomic memory access method.
> I realize we have the same pattern in other places in this
> device, probably a bug as well?
>
Yes, we need use atomic method at least for ownership check during TX/RX.
>
>> + rxdw0 = le32_to_cpu(val);
>> + if (rxdw0 & CP_RX_OWN) {
>> + return 1;
>> + } else {
>> + return 0;
>> + }
>
> Do we need to check that buffer size is large enough
> to include the packet like we do for non c+ mode?
>
Not sure here is the best place, the buffer size is checked during
receiving.
>> +}
>> +
>> static int rtl8139_can_receive(VLANClientState *nc)
>> {
>> RTL8139State *s = DO_UPCAST(NICState, nc, nc)->opaque;
>> @@ -819,7 +848,7 @@ static int rtl8139_can_receive(VLANClientState *nc)
>> if (rtl8139_cp_receiver_enabled(s)) {
>> /* ??? Flow control not implemented in c+ mode.
>> This is a hack to work around slirp deficiencies anyway. */
>> - return 1;
>> + return rtl8139_cp_has_rxbuf(s);
>> } else {
>> avail = MOD2(s->RxBufferSize + s->RxBufPtr - s->RxBufAddr,
>> s->RxBufferSize);
>> @@ -965,19 +994,6 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_
>>
>> /* begin C+ receiver mode */
>>
>> -/* w0 ownership flag */
>> -#define CP_RX_OWN (1<<31)
>> -/* w0 end of ring flag */
>> -#define CP_RX_EOR (1<<30)
>> -/* w0 bits 0...12 : buffer size */
>> -#define CP_RX_BUFFER_SIZE_MASK ((1<<13) - 1)
>> -/* w1 tag available flag */
>> -#define CP_RX_TAVA (1<<16)
>> -/* w1 bits 0...15 : VLAN tag */
>> -#define CP_RX_VLAN_TAG_MASK ((1<<16) - 1)
>> -/* w2 low 32bit of Rx buffer ptr */
>> -/* w3 high 32bit of Rx buffer ptr */
>> -
>> int descriptor = s->currCPlusRxDesc;
>> target_phys_addr_t cplus_rx_ring_desc;
>>
^ permalink raw reply
* Re: [PATCH 1/2] writeback: Improve busyloop prevention
From: Wu Fengguang @ 2011-10-22 4:20 UTC (permalink / raw)
To: Jan Kara; +Cc: linux-fsdevel@vger.kernel.org, Christoph Hellwig, Dave Chinner
In-Reply-To: <20111020222616.GA20542@quack.suse.cz>
On Fri, Oct 21, 2011 at 06:26:16AM +0800, Jan Kara wrote:
> On Thu 20-10-11 21:39:38, Wu Fengguang wrote:
> > On Thu, Oct 20, 2011 at 08:33:00PM +0800, Wu Fengguang wrote:
> > > On Thu, Oct 20, 2011 at 08:09:09PM +0800, Wu Fengguang wrote:
> > > > Jan,
> > > >
> > > > I tried the below combined patch over the ioless one, and find some
> > > > minor regressions. I studied the thresh=1G/ext3-1dd case in particular
> > > > and find that nr_writeback and the iostat avgrq-sz drops from time to time.
> > > >
> > > > I'll try to bisect the changeset.
> >
> > This is interesting, the culprit is found to be patch 1, which is
> > simply
> > if (work->for_kupdate) {
> > oldest_jif = jiffies -
> > msecs_to_jiffies(dirty_expire_interval * 10);
> > - work->older_than_this = &oldest_jif;
> > - }
> > + } else if (work->for_background)
> > + oldest_jif = jiffies;
> Yeah. I had a look into the trace and you can notice that during the
> whole dd run, we were running a single background writeback work (you can
> verify that by work->nr_pages decreasing steadily).
Yes, it is.
> Without refreshing
> oldest_jif, we'd write block device inode for /dev/sda (you can identify
> that by bdi=8:0, ino=0) only once. When refreshing oldest_jif, we write it
> every 5 seconds (kjournald dirties the device inode after committing a
> transaction by dirtying metadata buffers which were just committed and can
> now be checkpointed either by kjournald or flusher thread).
OK, now I understand the regular drops of nr_writeback and avgrq-sz:
on every 5s, it takes _some time_ to write inode 0, during which the
flusher is blocked and the IO queue runs low.
> So although the performance is slightly reduced, I'd say that the
> behavior is a desired one.
OK. However it's sad to see the flusher get blocked from time to time...
> Also if you observed the performance on a really long run, the difference
> should get smaller because eventually, kjournald has to flush the metadata
> blocks when the journal fills up and we need to free some journal space and
> at that point flushing is even more expensive because we have to do a
> blocking write during which all transaction operations, thus effectively
> the whole filesystem, are blocked.
OK. The dd test time was 300s, I'll increase it to 900s (cannot do
more because it's a 90GB disk partition).
Thanks,
Fengguang
^ permalink raw reply
* [PATCH 06/14] ARM : SAMSUNG : S3C2416 Added io mapping for Static memory controller.
From: Paul Schilling @ 2011-10-22 4:21 UTC (permalink / raw)
To: Kukjin Kim, Russell King, Yauhen Kharuzhy, Rafael J. Wysocki,
Greg Kroah-Hartman, linux-arm-kernel, linux-kernel
Cc: Paul Schilling, Paul Schilling
In-Reply-To: <static_memory>
Added MMU access to the Static Memory Controller.
Signed-off-by: Paul Schilling <paul.s.schilling@gmail.com>
---
arch/arm/mach-s3c2416/s3c2416.c | 12 ++++++++++++
1 files changed, 12 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-s3c2416/s3c2416.c b/arch/arm/mach-s3c2416/s3c2416.c
index 494ce91..823a034 100644
--- a/arch/arm/mach-s3c2416/s3c2416.c
+++ b/arch/arm/mach-s3c2416/s3c2416.c
@@ -65,6 +65,18 @@ static struct map_desc s3c2416_iodesc[] __initdata = {
IODESC_ENT(WATCHDOG),
IODESC_ENT(CLKPWR),
IODESC_ENT(TIMER),
+ {
+ .virtual = (u32)S3C2412_VA_SSMC,
+ .pfn = __phys_to_pfn(S3C2412_PA_SSMC),
+ .length = SZ_1M,
+ .type = MT_DEVICE,
+ },
+ /*{
+ .virtual = (u32)S3C2412_VA_EBI,
+ .pfn = __phys_to_pfn(S3C2412_PA_EBI),
+ .length = SZ_1M,
+ .type = MT_DEVICE,
+ },*/
};
struct sysdev_class s3c2416_sysclass = {
--
1.7.6.4
^ permalink raw reply related
* [PATCH 06/14] ARM : SAMSUNG : S3C2416 Added io mapping for Static memory controller.
From: Paul Schilling @ 2011-10-22 4:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <static_memory>
Added MMU access to the Static Memory Controller.
Signed-off-by: Paul Schilling <paul.s.schilling@gmail.com>
---
arch/arm/mach-s3c2416/s3c2416.c | 12 ++++++++++++
1 files changed, 12 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-s3c2416/s3c2416.c b/arch/arm/mach-s3c2416/s3c2416.c
index 494ce91..823a034 100644
--- a/arch/arm/mach-s3c2416/s3c2416.c
+++ b/arch/arm/mach-s3c2416/s3c2416.c
@@ -65,6 +65,18 @@ static struct map_desc s3c2416_iodesc[] __initdata = {
IODESC_ENT(WATCHDOG),
IODESC_ENT(CLKPWR),
IODESC_ENT(TIMER),
+ {
+ .virtual = (u32)S3C2412_VA_SSMC,
+ .pfn = __phys_to_pfn(S3C2412_PA_SSMC),
+ .length = SZ_1M,
+ .type = MT_DEVICE,
+ },
+ /*{
+ .virtual = (u32)S3C2412_VA_EBI,
+ .pfn = __phys_to_pfn(S3C2412_PA_EBI),
+ .length = SZ_1M,
+ .type = MT_DEVICE,
+ },*/
};
struct sysdev_class s3c2416_sysclass = {
--
1.7.6.4
^ permalink raw reply related
* Re: [Qemu-devel] [V2 PATCH] rtl8139: check the buffer availiability
From: Jason Wang @ 2011-10-22 4:18 UTC (permalink / raw)
To: Mark Wu; +Cc: blauwirbel, aliguori, qemu-devel, stefanha, mst
In-Reply-To: <4E9D5066.7070305@vnet.linux.ibm.com>
On 10/18/2011 06:09 PM, Mark Wu wrote:
> Hi Jason,
> Could you please elaborate what problem you try to resolve by this
> patch? And do you think we need notify I/O thread re-polling tap fd
> when receive descriptor becomes available? Otherwise, tap read polling
> will be disabled until the I/O handlers are updated by other reasons. Am
> I right?
Hi Mark, sorry for the late reply.
I think this patch may help to reduce packets dropping at the head of
the queue ( tap or netqueue in qemu) which may lead out of order packet
receiving in guest stack.
For the iothread notification, it looks impossible for 8139 as the
ownership was tracked through descriptor it self instead of a dedicated
register and there's no register which could be used to 'kick' 8139 for
packet receiving. When guest have refilled rx buffer of 8139cp,
tap_can_send() would return true and qemu would re-pool it. This may
introduce some latency when qemu is doning a block select() in
main_loop_wait().
Thanks.
>
>
> On 10/17/2011 10:55 AM, Jason Wang wrote:
>> Reduce spurious packet drops on RX ring empty when in c+ mode by
>> verifying that
>> we have at least 1 buffer ahead of the time.
>>
>> Change from v1:
>> Fix style comments from Stefan.
>>
>> Signed-off-by: Jason Wang<jasowang@redhat.com>
>> ---
>> hw/rtl8139.c | 44 ++++++++++++++++++++++++++++++--------------
>> 1 files changed, 30 insertions(+), 14 deletions(-)
>>
>> diff --git a/hw/rtl8139.c b/hw/rtl8139.c
>> index 3753950..bcbc5e3 100644
>> --- a/hw/rtl8139.c
>> +++ b/hw/rtl8139.c
>> @@ -84,6 +84,19 @@
>> #define VLAN_TCI_LEN 2
>> #define VLAN_HLEN (ETHER_TYPE_LEN + VLAN_TCI_LEN)
>>
>> +/* w0 ownership flag */
>> +#define CP_RX_OWN (1<<31)
>> +/* w0 end of ring flag */
>> +#define CP_RX_EOR (1<<30)
>> +/* w0 bits 0...12 : buffer size */
>> +#define CP_RX_BUFFER_SIZE_MASK ((1<<13) - 1)
>> +/* w1 tag available flag */
>> +#define CP_RX_TAVA (1<<16)
>> +/* w1 bits 0...15 : VLAN tag */
>> +#define CP_RX_VLAN_TAG_MASK ((1<<16) - 1)
>> +/* w2 low 32bit of Rx buffer ptr */
>> +/* w3 high 32bit of Rx buffer ptr */
>> +
>> #if defined (DEBUG_RTL8139)
>> # define DPRINTF(fmt, ...) \
>> do { fprintf(stderr, "RTL8139: " fmt, ## __VA_ARGS__); } while (0)
>> @@ -805,6 +818,22 @@ static inline target_phys_addr_t
>> rtl8139_addr64(uint32_t low, uint32_t high)
>> #endif
>> }
>>
>> +/* Verify that we have at least one available rx buffer */
>> +static int rtl8139_cp_has_rxbuf(RTL8139State *s)
>> +{
>> + uint32_t val, rxdw0;
>> + target_phys_addr_t cplus_rx_ring_desc =
>> rtl8139_addr64(s->RxRingAddrLO,
>> +
>> s->RxRingAddrHI);
>> + cplus_rx_ring_desc += 16 * s->currCPlusRxDesc;
>> + cpu_physical_memory_read(cplus_rx_ring_desc,&val, 4);
>> + rxdw0 = le32_to_cpu(val);
>> + if (rxdw0& CP_RX_OWN) {
>> + return 1;
>> + } else {
>> + return 0;
>> + }
>> +}
>> +
>> static int rtl8139_can_receive(VLANClientState *nc)
>> {
>> RTL8139State *s = DO_UPCAST(NICState, nc, nc)->opaque;
>> @@ -819,7 +848,7 @@ static int rtl8139_can_receive(VLANClientState *nc)
>> if (rtl8139_cp_receiver_enabled(s)) {
>> /* ??? Flow control not implemented in c+ mode.
>> This is a hack to work around slirp deficiencies anyway. */
>> - return 1;
>> + return rtl8139_cp_has_rxbuf(s);
>> } else {
>> avail = MOD2(s->RxBufferSize + s->RxBufPtr - s->RxBufAddr,
>> s->RxBufferSize);
>> @@ -965,19 +994,6 @@ static ssize_t rtl8139_do_receive(VLANClientState
>> *nc, const uint8_t *buf, size_
>>
>> /* begin C+ receiver mode */
>>
>> -/* w0 ownership flag */
>> -#define CP_RX_OWN (1<<31)
>> -/* w0 end of ring flag */
>> -#define CP_RX_EOR (1<<30)
>> -/* w0 bits 0...12 : buffer size */
>> -#define CP_RX_BUFFER_SIZE_MASK ((1<<13) - 1)
>> -/* w1 tag available flag */
>> -#define CP_RX_TAVA (1<<16)
>> -/* w1 bits 0...15 : VLAN tag */
>> -#define CP_RX_VLAN_TAG_MASK ((1<<16) - 1)
>> -/* w2 low 32bit of Rx buffer ptr */
>> -/* w3 high 32bit of Rx buffer ptr */
>> -
>> int descriptor = s->currCPlusRxDesc;
>> target_phys_addr_t cplus_rx_ring_desc;
>>
>>
>>
>
>
^ permalink raw reply
* Re: [PATCH 01/14] ATA : vortex86 : fix vortex86dx/sx hardware CRC bug.
From: Jeff Garzik @ 2011-10-22 4:12 UTC (permalink / raw)
To: Paul Schilling
Cc: David S. Miller, Jesse Barnes, linux-ide, linux-kernel, linux-pci
In-Reply-To: <1319254458-4692-1-git-send-email-paul.s.schilling@gmail.com>
On 10/21/2011 11:34 PM, Paul Schilling wrote:
> This fixes a DMA issue related to a CRC bug on
> the RDC pata peripherial found on the vortex86sx and vortex86dx.
>
> Signed-off-by: Paul Schilling<paul.s.schilling@gmail.com>
I'm sorry, this is not acceptable.
You missed in hundreds of lines of useless reformatting in amongst the
fixes.
Please separate out logical changes - thus, any whitespace/reformatting
must be in a separate patch from your fixes.
^ permalink raw reply
* [PATCH 05/14] ARM : SAMSUNG : Add GPIO_EXTRA for S3C2416.
From: Paul Schilling @ 2011-10-22 4:08 UTC (permalink / raw)
To: Kukjin Kim, Russell King, linux-arm-kernel, linux-kernel
Cc: Paul Schilling, Paul Schilling
In-Reply-To: <GPIO_extra>
The S3C2416 has more GPIO than other S3C24XX processors.
Signed-off-by: Paul Schilling <paul.s.schilling@gmail.com>
---
arch/arm/mach-s3c2410/include/mach/gpio.h | 15 ++++++++++-----
arch/arm/plat-s3c24xx/gpiolib.c | 10 ++++++++--
2 files changed, 18 insertions(+), 7 deletions(-)
diff --git a/arch/arm/mach-s3c2410/include/mach/gpio.h b/arch/arm/mach-s3c2410/include/mach/gpio.h
index f7f6b07..65a0bce 100644
--- a/arch/arm/mach-s3c2410/include/mach/gpio.h
+++ b/arch/arm/mach-s3c2410/include/mach/gpio.h
@@ -20,22 +20,27 @@
* devices that need GPIO.
*/
+#if defined(CONFIG_CPU_S3C2443) || defined(CONFIG_CPU_S3C2416)
+#define ARCH_NR_GPIOS (32 * 12 + CONFIG_S3C24XX_GPIO_EXTRA)
+#else
#ifdef CONFIG_CPU_S3C244X
#define ARCH_NR_GPIOS (32 * 9 + CONFIG_S3C24XX_GPIO_EXTRA)
-#elif defined(CONFIG_CPU_S3C2443) || defined(CONFIG_CPU_S3C2416)
-#define ARCH_NR_GPIOS (32 * 12 + CONFIG_S3C24XX_GPIO_EXTRA)
#else
#define ARCH_NR_GPIOS (256 + CONFIG_S3C24XX_GPIO_EXTRA)
#endif
+#endif
#include <asm-generic/gpio.h>
#include <mach/gpio-nrs.h>
#include <mach/gpio-fns.h>
-#ifdef CONFIG_CPU_S3C244X
-#define S3C_GPIO_END (S3C2410_GPJ(0) + 32)
-#elif defined(CONFIG_CPU_S3C2443) || defined(CONFIG_CPU_S3C2416)
+
+#if defined(CONFIG_CPU_S3C2443) || defined(CONFIG_CPU_S3C2416)
#define S3C_GPIO_END (S3C2410_GPM(0) + 32)
#else
+#ifdef CONFIG_CPU_S3C244X
+#define S3C_GPIO_END (S3C2410_GPJ(0) + 32)
+else
#define S3C_GPIO_END (S3C2410_GPH(0) + 32)
#endif
+#endif
diff --git a/arch/arm/plat-s3c24xx/gpiolib.c b/arch/arm/plat-s3c24xx/gpiolib.c
index 243b641..93d4734 100644
--- a/arch/arm/plat-s3c24xx/gpiolib.c
+++ b/arch/arm/plat-s3c24xx/gpiolib.c
@@ -34,6 +34,11 @@ static int s3c24xx_gpiolib_banka_input(struct gpio_chip *chip, unsigned offset)
return -EINVAL;
}
+static int s3c24xx_gpiolib_bankm_output(struct gpio_chip *chip, unsigned offset, int value)
+{
+ return -EINVAL;
+}
+
static int s3c24xx_gpiolib_banka_output(struct gpio_chip *chip,
unsigned offset, int value)
{
@@ -93,7 +98,7 @@ struct s3c_gpio_chip s3c24xx_gpios[] = {
.base = S3C2410_GPA(0),
.owner = THIS_MODULE,
.label = "GPIOA",
- .ngpio = 24,
+ .ngpio = 27,
.direction_input = s3c24xx_gpiolib_banka_input,
.direction_output = s3c24xx_gpiolib_banka_output,
},
@@ -167,7 +172,7 @@ struct s3c_gpio_chip s3c24xx_gpios[] = {
.base = S3C2410_GPH(0),
.owner = THIS_MODULE,
.label = "GPIOH",
- .ngpio = 11,
+ .ngpio = 15,
},
},
/* GPIOS for the S3C2443 and later devices. */
@@ -206,6 +211,7 @@ struct s3c_gpio_chip s3c24xx_gpios[] = {
.owner = THIS_MODULE,
.label = "GPIOM",
.ngpio = 2,
+ .direction_output = s3c24xx_gpiolib_bankm_output,
},
},
};
--
1.7.6.4
^ permalink raw reply related
* Re: [PATCH] net: use INET_ECN_MASK instead of hardcoded 3
From: David Miller @ 2011-10-22 4:08 UTC (permalink / raw)
To: zenczykowski; +Cc: maze, netdev
In-Reply-To: <1319238710-11272-1-git-send-email-zenczykowski@gmail.com>
From: Maciej Żenczykowski <zenczykowski@gmail.com>
Date: Fri, 21 Oct 2011 16:11:50 -0700
> Signed-off-by: Maciej Żenczykowski <maze@google.com>
Applied.
^ permalink raw reply
* [PATCH 05/14] ARM : SAMSUNG : Add GPIO_EXTRA for S3C2416.
From: Paul Schilling @ 2011-10-22 4:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <GPIO_extra>
The S3C2416 has more GPIO than other S3C24XX processors.
Signed-off-by: Paul Schilling <paul.s.schilling@gmail.com>
---
arch/arm/mach-s3c2410/include/mach/gpio.h | 15 ++++++++++-----
arch/arm/plat-s3c24xx/gpiolib.c | 10 ++++++++--
2 files changed, 18 insertions(+), 7 deletions(-)
diff --git a/arch/arm/mach-s3c2410/include/mach/gpio.h b/arch/arm/mach-s3c2410/include/mach/gpio.h
index f7f6b07..65a0bce 100644
--- a/arch/arm/mach-s3c2410/include/mach/gpio.h
+++ b/arch/arm/mach-s3c2410/include/mach/gpio.h
@@ -20,22 +20,27 @@
* devices that need GPIO.
*/
+#if defined(CONFIG_CPU_S3C2443) || defined(CONFIG_CPU_S3C2416)
+#define ARCH_NR_GPIOS (32 * 12 + CONFIG_S3C24XX_GPIO_EXTRA)
+#else
#ifdef CONFIG_CPU_S3C244X
#define ARCH_NR_GPIOS (32 * 9 + CONFIG_S3C24XX_GPIO_EXTRA)
-#elif defined(CONFIG_CPU_S3C2443) || defined(CONFIG_CPU_S3C2416)
-#define ARCH_NR_GPIOS (32 * 12 + CONFIG_S3C24XX_GPIO_EXTRA)
#else
#define ARCH_NR_GPIOS (256 + CONFIG_S3C24XX_GPIO_EXTRA)
#endif
+#endif
#include <asm-generic/gpio.h>
#include <mach/gpio-nrs.h>
#include <mach/gpio-fns.h>
-#ifdef CONFIG_CPU_S3C244X
-#define S3C_GPIO_END (S3C2410_GPJ(0) + 32)
-#elif defined(CONFIG_CPU_S3C2443) || defined(CONFIG_CPU_S3C2416)
+
+#if defined(CONFIG_CPU_S3C2443) || defined(CONFIG_CPU_S3C2416)
#define S3C_GPIO_END (S3C2410_GPM(0) + 32)
#else
+#ifdef CONFIG_CPU_S3C244X
+#define S3C_GPIO_END (S3C2410_GPJ(0) + 32)
+else
#define S3C_GPIO_END (S3C2410_GPH(0) + 32)
#endif
+#endif
diff --git a/arch/arm/plat-s3c24xx/gpiolib.c b/arch/arm/plat-s3c24xx/gpiolib.c
index 243b641..93d4734 100644
--- a/arch/arm/plat-s3c24xx/gpiolib.c
+++ b/arch/arm/plat-s3c24xx/gpiolib.c
@@ -34,6 +34,11 @@ static int s3c24xx_gpiolib_banka_input(struct gpio_chip *chip, unsigned offset)
return -EINVAL;
}
+static int s3c24xx_gpiolib_bankm_output(struct gpio_chip *chip, unsigned offset, int value)
+{
+ return -EINVAL;
+}
+
static int s3c24xx_gpiolib_banka_output(struct gpio_chip *chip,
unsigned offset, int value)
{
@@ -93,7 +98,7 @@ struct s3c_gpio_chip s3c24xx_gpios[] = {
.base = S3C2410_GPA(0),
.owner = THIS_MODULE,
.label = "GPIOA",
- .ngpio = 24,
+ .ngpio = 27,
.direction_input = s3c24xx_gpiolib_banka_input,
.direction_output = s3c24xx_gpiolib_banka_output,
},
@@ -167,7 +172,7 @@ struct s3c_gpio_chip s3c24xx_gpios[] = {
.base = S3C2410_GPH(0),
.owner = THIS_MODULE,
.label = "GPIOH",
- .ngpio = 11,
+ .ngpio = 15,
},
},
/* GPIOS for the S3C2443 and later devices. */
@@ -206,6 +211,7 @@ struct s3c_gpio_chip s3c24xx_gpios[] = {
.owner = THIS_MODULE,
.label = "GPIOM",
.ngpio = 2,
+ .direction_output = s3c24xx_gpiolib_bankm_output,
},
},
};
--
1.7.6.4
^ permalink raw reply related
* Re: [PATCH] net: add sysctl allow_so_priority for SO_PRIORITY setsockopt
From: David Miller @ 2011-10-22 4:04 UTC (permalink / raw)
To: zenczykowski; +Cc: maze, netdev
In-Reply-To: <1319235725-3046-1-git-send-email-zenczykowski@gmail.com>
From: Maciej Żenczykowski <zenczykowski@gmail.com>
Date: Fri, 21 Oct 2011 15:22:05 -0700
> From: Maciej Żenczykowski <maze@google.com>
>
> This change adds a sysctl (/proc/sys/net/core/allow_so_priority)
> with a default of true (1), as such it does not change the default
> behaviour of the Linux kernel.
>
> This sysctl can be set to false (0), this will result in non
> CAP_NET_ADMIN processes being unable to set SO_PRIORITY socket
> option.
>
> This is desireable if we want to rely on socket/skb priorities
> being inferred from TOS/TCLASS bits.
>
> Signed-off-by: Maciej Żenczykowski <maze@google.com>
The socket layer is not the place to enforce this.
The ingress into your MPLS/RSVP cloud that actually provides the
quality of service is where you control and mangle the TOS as needed.
Sorry, I'm not applying anything like this. Any machine on your
network can spit out any TOS it wants, and if you have control over
the apps change it's behavior there. If you don't have control over
the apps then filter and mangle.
^ permalink raw reply
* [Buildroot] [Bug 4375] New: prevent unused-but-set warning on "ret" in makedevs.c
From: bugzilla at busybox.net @ 2011-10-22 4:04 UTC (permalink / raw)
To: buildroot
https://bugs.busybox.net/show_bug.cgi?id=4375
Summary: prevent unused-but-set warning on "ret" in makedevs.c
Product: buildroot
Version: unspecified
Platform: PC
OS/Version: Linux
Status: NEW
Severity: normal
Priority: P5
Component: Other
AssignedTo: unassigned at buildroot.uclibc.org
ReportedBy: d_mo1234 at yahoo.com
CC: buildroot at uclibc.org
Estimated Hours: 0.0
Created attachment 3673
--> https://bugs.busybox.net/attachment.cgi?id=3673
patch file
The makedevs program assigns "ret", but never reads from it. (It always
returns 0.) While using gcc 4.6.0 for an OMAP target, I got an unused-but-set
warning on "ret", which coupled with a -Werror that was set somewhere, bringing
the buildroot compile to a halt. So I have attached a patch that tests "ret",
and prints out a warning if there were any failures.
--
Configure bugmail: https://bugs.busybox.net/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are on the CC list for the bug.
^ permalink raw reply
* [Buildroot] [Bug 4369] New: Fix permissions on untared lsof archive
From: bugzilla at busybox.net @ 2011-10-22 3:47 UTC (permalink / raw)
To: buildroot
https://bugs.busybox.net/show_bug.cgi?id=4369
Summary: Fix permissions on untared lsof archive
Product: buildroot
Version: unspecified
Platform: PC
OS/Version: Linux
Status: NEW
Severity: minor
Priority: P5
Component: Other
AssignedTo: unassigned at buildroot.uclibc.org
ReportedBy: d_mo1234 at yahoo.com
CC: buildroot at uclibc.org
Estimated Hours: 0.0
Created attachment 3667
--> https://bugs.busybox.net/attachment.cgi?id=3667
patch file
When buildroot untars a package, it opens permissions on the untarred results,
(The comment is "some packages have messed up permissions inside".) However,
in the case of lsof, the tar.bz2 contains another .tar, which contains the
source code. It needs to have the same treatment as buildroot's normal untar
process, because lsof has read-only files in the inner tarball.
A patch file is attached.
--
Configure bugmail: https://bugs.busybox.net/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are on the CC list for the bug.
^ permalink raw reply
* [PATCH 02/14] ARM : SAMSUNG : Add RS485 support.
From: Paul Schilling @ 2011-10-22 3:46 UTC (permalink / raw)
To: Ben Dooks, Kukjin Kim, Russell King, Alan Cox, Greg Kroah-Hartman,
Boojin Kim, Nicolas Pitre, linux-arm-kernel, linux-kernel,
linux-serial
Cc: Paul Schilling, Paul Schilling
In-Reply-To: <samsung_rs485>
Add RS485 tranmit/recieve control line capabilities
This RS485 driver uses two methodes to determine if the transmit
should be disabled.
1. It uses a timer and polling to determine when transmit has completed.
2. Optionally uses a token used to terminate the message to be used in
the recieve interrupt to disable the transmit.
Option 1 alone can be used but doesn't garentee that the transmit line
wont be disabled within 1 to 2 character times depending on system load.
This patch adds an additional variable to the serial RS-485 struct so
that a program can change the terminate token value via the IOCTL.
Signed-off-by: Paul Schilling <paul.s.schilling@gmail.com>
---
arch/arm/plat-samsung/include/plat/regs-serial.h | 7 +
drivers/tty/serial/Kconfig | 16 +
drivers/tty/serial/samsung.c | 738 ++++++++++++++++++++--
drivers/tty/serial/samsung.h | 15 +
include/linux/serial.h | 5 +-
5 files changed, 722 insertions(+), 59 deletions(-)
diff --git a/arch/arm/plat-samsung/include/plat/regs-serial.h b/arch/arm/plat-samsung/include/plat/regs-serial.h
index bac36fa..9618e7d 100644
--- a/arch/arm/plat-samsung/include/plat/regs-serial.h
+++ b/arch/arm/plat-samsung/include/plat/regs-serial.h
@@ -261,6 +261,13 @@ struct s3c2410_uartcfg {
struct s3c24xx_uart_clksrc *clocks;
unsigned int clocks_size;
+
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+ signed int gpio_transmit_en;
+ signed int gpio_receive_en;
+ unsigned char enable_token;
+ unsigned char token;
+#endif
};
/* s3c24xx_uart_devs
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 4dcb37b..dab33c2 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -464,6 +464,22 @@ config SERIAL_SAMSUNG_UARTS
Select the number of available UART ports for the Samsung S3C
serial driver
+config SAMSUNG_HAS_RS485
+ bool "Enable RS485 support for Samsung"
+ depends on SERIAL_SAMSUNG && (MACH_CONDOR2440 || MACH_CONDOR2416 || MACH_MINI2440)
+ default y if (MACH_CONDOR2440 || MACH_CONDOR2416)
+ default n if (MACH_MINI2440)
+
+config SAMSUNG_485_LOW_RES_TIMER
+ bool "Samsung RS-485 use low res timer during transmit"
+ depends on SERIAL_SAMSUNG && SAMSUNG_HAS_RS485
+ default n
+ help
+ Use low resolution jiffies at 200 Hz for timer the RS-485
+ transmitter. This works but doesn't garantee hard realtime.
+ Say no if you need the transmitter off immediatly after sending
+ a string or character.
+
config SERIAL_SAMSUNG_DEBUG
bool "Samsung SoC serial debug"
depends on SERIAL_SAMSUNG && DEBUG_LL
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
index 6edafb5..bf61579 100644
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -4,12 +4,16 @@
* Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
* http://armlinux.simtec.co.uk/
*
+ * Paul Schilling, Copyright (c) 2011 Ecolab Corp.
+ * http://www.ecolab.com/
+ * Added RS-485 support to the Samsung UART driver.
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-/* Hote on 2410 error handling
+/* Note on 2410 error handling
*
* The s3c2410 manual has a love/hate affair with the contents of the
* UERSTAT register in the UART blocks, and keeps marking some of the
@@ -17,7 +21,7 @@
* it copes with BREAKs properly, so I am happy to ignore the RESERVED
* feature from the latter versions of the manual.
*
- * If it becomes aparrent that latter versions of the 2410 remove these
+ * If it becomes apparent that latter versions of the 2410 remove these
* bits, then action will have to be taken to differentiate the versions
* and change the policy on BREAK
*
@@ -42,6 +46,8 @@
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/cpufreq.h>
+#include <linux/uaccess.h>
+#include <linux/gpio.h>
#include <asm/irq.h>
@@ -66,11 +72,27 @@
/* flag to ignore all characters coming in */
#define RXSTAT_DUMMY_READ (0x10000000)
+static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS];
+
+
static inline struct s3c24xx_uart_port *to_ourport(struct uart_port *port)
{
return container_of(port, struct s3c24xx_uart_port, port);
}
+static inline struct s3c24xx_uart_info *s3c24xx_port_to_info(struct uart_port *port)
+{
+ return to_ourport(port)->info;
+}
+
+static inline struct s3c2410_uartcfg *s3c24xx_port_to_cfg(struct uart_port *port)
+{
+ if (port->dev == NULL)
+ return NULL;
+
+ return (struct s3c2410_uartcfg *)port->dev->platform_data;
+}
+
/* translate a port to the device name */
static inline const char *s3c24xx_serial_portname(struct uart_port *port)
@@ -83,6 +105,22 @@ static int s3c24xx_serial_txempty_nofifo(struct uart_port *port)
return (rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE);
}
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+/* Get the current transmit fifo count */
+static int s3c24xx_serial_tx_getfifocnt(struct s3c24xx_uart_port *ourport)
+{
+ struct s3c24xx_uart_info *info = ourport->info;
+ unsigned long ufstat = rd_regl(&(ourport->port), S3C2410_UFSTAT);
+
+ /* If FIFO is full then return FIFO size. */
+ if (ufstat & info->tx_fifofull)
+ return info->fifosize;
+
+ /* Else return number of entries in the FIFO. */
+ return (ufstat & info->tx_fifomask) >> info->tx_fifoshift;
+}
+#endif
+
static void s3c24xx_serial_rx_enable(struct uart_port *port)
{
unsigned long flags;
@@ -121,15 +159,205 @@ static void s3c24xx_serial_rx_disable(struct uart_port *port)
spin_unlock_irqrestore(&port->lock, flags);
}
+static void s3c24xx_serial_rx_fifo_enable(
+ struct uart_port *port,
+ unsigned int en)
+{
+ unsigned long flags;
+ unsigned int ucon;
+ static unsigned int last_state = 1;
+/* FIXME */
+ #if 0
+ if (last_state != en) {
+
+ struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ ucon = rd_regl(port, S3C2410_UCON);
+
+ ucon &= ~(S3C2440_UFCON_RXTRIG32 | S3C2410_UCON_RXILEVEL);
+
+ if (en) {
+ ucon |= cfg->ucon;
+ }
+
+ wr_regl(port, S3C2410_UCON, ucon);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+ }
+#endif
+}
+
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+/* Timer function to toggle RTS when using FAST_TIMER */
+#ifdef SAMSUNG485_LOW_RES_TIMER
+ static void rs485_toggle_rts_timer_function(unsigned long _data)
+ {
+ struct uart_port *port = (struct uart_port *)_data;
+ struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
+
+ struct s3c24xx_uart_port *ourport = to_ourport(port);
+
+ unsigned long utrstat;
+
+ utrstat = rd_regl(port, S3C2410_UTRSTAT);
+
+ if ((utrstat & S3C2410_UTRSTAT_TXE) ? 1 : 0) {
+ if (cfg->gpio_transmit_en > -1) {
+ gpio_set_value(cfg->gpio_transmit_en, 0);
+ }
+
+ if (cfg->gpio_receive_en > -1) {
+ gpio_set_value(cfg->gpio_receive_en, 0);
+ }
+ } else {
+ /* Set a short timer to toggle RTS */
+ mod_timer(
+ &(ourport->rs485_tx_timer),
+ jiffies + usecs_to_jiffies(
+ ourport->char_time_usec
+ / 10));
+ }
+ }
+#else
+
+
+static enum hrtimer_restart rs485_toggle_rts_timer_function(
+ struct s3c24xx_uart_port *ourport)
+{
+ struct s3c2410_uartcfg *cfg =
+ s3c24xx_port_to_cfg(&(ourport->port));
+
+ unsigned long utrstat;
+ enum hrtimer_restart ret;
+
+ /* Read UART transmit status register */
+ utrstat = rd_regl(&(ourport->port), S3C2410_UTRSTAT);
+
+ /* Check if the UART and shift register is empty*/
+ if ((utrstat & S3C2410_UTRSTAT_TXE) ? 1 : 0) {
+ /* Is the GPIO valid for RS485 transmit enable*/
+ if (cfg->gpio_transmit_en > -1) {
+ /* Request, Set, Free the transmit GPIO*/
+ gpio_set_value(cfg->gpio_transmit_en, 0);
+ }
+
+ /* Is the GPIO valid for the RS485 receive enable*/
+ if (cfg->gpio_receive_en > -1) {
+ /* Request, Set, Free the receive GPIO*/
+ gpio_set_value(cfg->gpio_receive_en, 0);
+ }
+
+ s3c24xx_serial_rx_fifo_enable(&(ourport->port), 1);
+
+ /* The timer has completed its task now we can disable it. */
+ ret = HRTIMER_NORESTART;
+ } else {
+
+ ktime_t kt;
+
+ if (s3c24xx_serial_tx_getfifocnt(ourport) > 1) {
+ kt = ktime_set(0, ourport->char_time_nanosec);
+ hrtimer_forward(&(ourport->hr_rs485_tx_timer),
+ ourport->hr_rs485_tx_timer.base->softirq_time,
+ kt);
+ } else {
+ kt = ktime_set(0, ourport->char_time_nanosec / 2);
+ hrtimer_forward(&(ourport->hr_rs485_tx_timer),
+ ourport->hr_rs485_tx_timer.base->softirq_time,
+ kt);
+ }
+
+ /* Timer will be enabled after the interrupt context */
+ ret = HRTIMER_RESTART;
+ }
+
+ return ret;
+}
+
+/* Uart 0 RS-485 timer callback */
+enum hrtimer_restart rs485_hr_timer_callback_uart0(struct hrtimer *timer)
+{
+
+ return rs485_toggle_rts_timer_function(&s3c24xx_serial_ports[0]);
+}
+
+/* Uart 0 RS-485 timer callback */
+enum hrtimer_restart rs485_hr_timer_callback_uart1(struct hrtimer *timer)
+{
+
+ return rs485_toggle_rts_timer_function(&s3c24xx_serial_ports[1]);
+}
+
+/* Uart 0 RS-485 timer callback */
+#if CONFIG_SERIAL_SAMSUNG_UARTS > 2
+enum hrtimer_restart rs485_hr_timer_callback_uart2(struct hrtimer *timer)
+{
+
+ return rs485_toggle_rts_timer_function(&s3c24xx_serial_ports[2]);
+}
+#endif
+
+/* Uart 0 RS-485 timer callback */
+#if CONFIG_SERIAL_SAMSUNG_UARTS > 3
+enum hrtimer_restart rs485_hr_timer_callback_uart3(struct hrtimer *timer)
+{
+
+ return rs485_toggle_rts_timer_function(&s3c24xx_serial_ports[3]);
+}
+#endif
+
+
+/* Callback array*/
+enum hrtimer_restart (*callback_list[CONFIG_SERIAL_SAMSUNG_UARTS])(struct hrtimer *) = {
+ &rs485_hr_timer_callback_uart0,
+ &rs485_hr_timer_callback_uart1,
+
+#if CONFIG_SERIAL_SAMSUNG_UARTS > 2
+ &rs485_hr_timer_callback_uart2,
+#endif
+
+#if CONFIG_SERIAL_SAMSUNG_UARTS > 3
+ &rs485_hr_timer_callback_uart3,
+#endif
+};
+
+#endif
+#endif /* CONFIG_SAMSUNG_HAS_RS485 */
+
+
static void s3c24xx_serial_stop_tx(struct uart_port *port)
{
struct s3c24xx_uart_port *ourport = to_ourport(port);
if (tx_enabled(port)) {
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+ if (ourport->rs485.flags & SER_RS485_ENABLED) {
+#ifdef CONFIG_SAMSUNG_485_LOW_RES_TIMER
+ /* Set a short timer to toggle RTS */
+ mod_timer(&(ourport->rs485_tx_timer),
+ jiffies + usecs_to_jiffies(ourport->char_time_usec * s3c24xx_serial_tx_getfifocnt(ourport)));
+#else
+ ktime_t kt;
+
+ /* Set time struct to one char time. */
+ kt = ktime_set(0, ourport->char_time_nanosec);
+
+ /* Start the high res timer. */
+ hrtimer_start(&(ourport->hr_rs485_tx_timer), kt, HRTIMER_MODE_REL);
+#endif /* CONFIG_SAMSUNG_485_LOW_RES_TIMER */
+
+ s3c24xx_serial_rx_fifo_enable(port, 0);
+
+ }
+#endif /* CONFIG_SAMSUNG_HAS_RS485 */
+
disable_irq_nosync(ourport->tx_irq);
tx_enabled(port) = 0;
- if (port->flags & UPF_CONS_FLOW)
+ if (port->flags & UPF_CONS_FLOW) {
s3c24xx_serial_rx_enable(port);
+ }
}
}
@@ -137,7 +365,42 @@ static void s3c24xx_serial_start_tx(struct uart_port *port)
{
struct s3c24xx_uart_port *ourport = to_ourport(port);
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+ hrtimer_try_to_cancel(&(ourport->hr_rs485_tx_timer));
+#endif
+
if (!tx_enabled(port)) {
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+ /* enable RS-485 */
+ if (ourport->rs485.flags & SER_RS485_ENABLED) {
+ struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
+
+ /* Is transmit GPIO valid */
+ if (cfg->gpio_transmit_en > -1) {
+ /* GPIO Request, Config, Direction, Value, and
+ * Free the pin*/
+ WARN_ON(s3c_gpio_cfgpin(cfg->gpio_transmit_en,
+ S3C_GPIO_OUTPUT));
+ gpio_direction_output(cfg->gpio_transmit_en, 1);
+ gpio_set_value(cfg->gpio_transmit_en, 1);
+ }
+
+ /* Is receive GPIO valid */
+ if ((cfg->gpio_receive_en > -1) &&
+ (!(ourport->rs485.flags &
+ SER_RS485_ALWAYS_LISTEN
+ ))) {
+ /* GPIO Request, Config, Direction, Value, and
+ * Free the pin*/
+ WARN_ON(s3c_gpio_cfgpin(cfg->gpio_receive_en,
+ S3C_GPIO_OUTPUT));
+ gpio_direction_output(cfg->gpio_receive_en, 1);
+ gpio_set_value(cfg->gpio_receive_en, 1);
+ }
+
+ }
+#endif /*CONFIG_SAMSUNG_HAS_RS485 */
+
if (port->flags & UPF_CONS_FLOW)
s3c24xx_serial_rx_disable(port);
@@ -162,18 +425,6 @@ static void s3c24xx_serial_enable_ms(struct uart_port *port)
{
}
-static inline struct s3c24xx_uart_info *s3c24xx_port_to_info(struct uart_port *port)
-{
- return to_ourport(port)->info;
-}
-
-static inline struct s3c2410_uartcfg *s3c24xx_port_to_cfg(struct uart_port *port)
-{
- if (port->dev == NULL)
- return NULL;
-
- return (struct s3c2410_uartcfg *)port->dev->platform_data;
-}
static int s3c24xx_serial_rx_fifocnt(struct s3c24xx_uart_port *ourport,
unsigned long ufstat)
@@ -186,6 +437,99 @@ static int s3c24xx_serial_rx_fifocnt(struct s3c24xx_uart_port *ourport,
return (ufstat & info->rx_fifomask) >> info->rx_fifoshift;
}
+static inline int
+s3c24xx_serial_getsource(struct uart_port *port, struct s3c24xx_uart_clksrc *c)
+{
+ struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
+
+ return (info->get_clksrc)(port, c);
+}
+
+static inline int
+s3c24xx_serial_setsource(struct uart_port *port, struct s3c24xx_uart_clksrc *c)
+{
+ struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
+
+ return (info->set_clksrc)(port, c);
+}
+
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+static void
+samsung_uart_get_options(struct uart_port *port, int *baud,
+ int *parity, int *stop, int *bits)
+{
+ struct s3c24xx_uart_clksrc clksrc;
+ struct clk *clk;
+ unsigned int ulcon;
+ unsigned int ucon;
+ unsigned int ubrdiv;
+ unsigned long rate;
+
+ ulcon = rd_regl(port, S3C2410_ULCON);
+ ucon = rd_regl(port, S3C2410_UCON);
+ ubrdiv = rd_regl(port, S3C2410_UBRDIV);
+
+ dbg("s3c24xx_serial_get_options: port=%p\n"
+ "registers: ulcon=%08x, ucon=%08x, ubdriv=%08x\n",
+ port, ulcon, ucon, ubrdiv);
+
+ if ((ucon & 0xf) != 0) {
+ /* consider the serial port configured if the tx/rx mode set */
+
+ switch (ulcon & S3C2410_LCON_CSMASK) {
+ case S3C2410_LCON_CS5:
+ *bits = 5;
+ break;
+ case S3C2410_LCON_CS6:
+ *bits = 6;
+ break;
+ case S3C2410_LCON_CS7:
+ *bits = 7;
+ break;
+ default:
+ case S3C2410_LCON_CS8:
+ *bits = 8;
+ break;
+ }
+
+ switch (ulcon & S3C2410_LCON_PMASK) {
+ case S3C2410_LCON_PEVEN:
+ *parity = 'e';
+ break;
+
+ case S3C2410_LCON_PODD:
+ *parity = 'o';
+ break;
+
+ case S3C2410_LCON_PNONE:
+ default:
+ *parity = 'n';
+ }
+
+ if (ulcon | S3C2410_LCON_STOPB) {
+ *stop = 2;
+ } else {
+ *stop = 1;
+ }
+
+ /* now calculate the baud rate */
+
+ s3c24xx_serial_getsource(port, &clksrc);
+
+ clk = clk_get(port->dev, clksrc.name);
+ if (!IS_ERR(clk) && clk != NULL)
+ rate = clk_get_rate(clk) / clksrc.divisor;
+ else
+ rate = 1;
+
+
+ *baud = rate / (16 * (ubrdiv + 1));
+ dbg("calculated baud %d\n", *baud);
+ }
+
+}
+#endif /* CONFIG_SAMSUNG_HAS_RS485 */
+
/* ? - where has parity gone?? */
#define S3C2410_UERSTAT_PARITY (0x1000)
@@ -209,6 +553,33 @@ s3c24xx_serial_rx_chars(int irq, void *dev_id)
uerstat = rd_regl(port, S3C2410_UERSTAT);
ch = rd_regb(port, S3C2410_URXH);
+ if (ourport->rs485.flags & SER_RS485_ENABLED) {
+ struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
+
+#ifdef CONFIG_TEST_485
+ /* Is the GPIO valid for the RS485 receive enable*/
+ if (cfg->gpio_receive_en > -1) {
+ /* Request, Set, Free the receive GPIO*/
+ gpio_set_value(cfg->gpio_receive_en, 1);
+ gpio_set_value(cfg->gpio_receive_en, 0);
+ }
+#endif
+
+ if ((SER_RS485_TOGGLE_ON_TOKEN & ourport->rs485.flags) &&
+ (ourport->rs485.toggle_token == ch)) {
+ /* Is the GPIO valid for RS485
+ * transmit enable*/
+ if (cfg->gpio_transmit_en > -1) {
+ /* Set the transmit GPIO line*/
+
+ gpio_set_value(cfg->gpio_transmit_en, 0);
+
+ }
+
+ s3c24xx_serial_rx_fifo_enable(port, 1);
+ }
+ }
+
if (port->flags & UPF_CONS_FLOW) {
int txe = s3c24xx_serial_txempty_nofifo(port);
@@ -488,21 +859,7 @@ static struct s3c24xx_uart_clksrc tmp_clksrc = {
.divisor = 1,
};
-static inline int
-s3c24xx_serial_getsource(struct uart_port *port, struct s3c24xx_uart_clksrc *c)
-{
- struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
-
- return (info->get_clksrc)(port, c);
-}
-static inline int
-s3c24xx_serial_setsource(struct uart_port *port, struct s3c24xx_uart_clksrc *c)
-{
- struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
-
- return (info->set_clksrc)(port, c);
-}
struct baud_calc {
struct s3c24xx_uart_clksrc *clksrc;
@@ -512,6 +869,41 @@ struct baud_calc {
struct clk *src;
};
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+/* Calculate the char_time depending on baudrate, number of bits etc. */
+static void update_char_time(struct uart_port *port)
+{
+
+ int bits = 8;
+ int baud = 9600;
+ int parity = 'n';
+ int stop = 1;
+
+ samsung_uart_get_options(port, &baud, &parity, &stop, &bits);
+
+ /* calc. number of bits / data byte */
+ /* databits + startbit and 1 stopbit */
+ bits++;
+
+ /* 2 stopbits ? */
+ bits += stop;
+
+ /* is parity enabled. */
+ if ('n' != parity) {
+ bits++;
+ }
+
+#ifdef CONFIG_SAMSUNG_485_LOW_RES_TIMER
+ /* calc timeout */
+ to_ourport(port)->char_time_usec = ((1000000 / baud) * bits) + 1;
+#else
+ /* calc timeout */
+ to_ourport(port)->char_time_nanosec = ((1000000000 / baud) * bits) + 1;
+#endif
+}
+
+#endif /*CONFIG_SAMSUNG_HAS_RS485 */
+
static int s3c24xx_serial_calcbaud(struct baud_calc *calc,
struct uart_port *port,
struct s3c24xx_uart_clksrc *clksrc,
@@ -785,7 +1177,7 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
port->ignore_status_mask = 0;
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= S3C2410_UERSTAT_OVERRUN;
- if (termios->c_iflag & IGNBRK && termios->c_iflag & IGNPAR)
+ if ((termios->c_iflag & IGNBRK) && (termios->c_iflag & IGNPAR))
port->ignore_status_mask |= S3C2410_UERSTAT_FRAME;
/*
@@ -795,6 +1187,12 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
port->ignore_status_mask |= RXSTAT_DUMMY_READ;
spin_unlock_irqrestore(&port->lock, flags);
+
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+ /* Update character time. */
+ update_char_time(port);
+#endif /* CONFIG_SAMSUNG_HAS_RS485 */
+
}
static const char *s3c24xx_serial_type(struct uart_port *port)
@@ -830,7 +1228,7 @@ static void s3c24xx_serial_config_port(struct uart_port *port, int flags)
{
struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
- if (flags & UART_CONFIG_TYPE &&
+ if ((flags & UART_CONFIG_TYPE) &&
s3c24xx_serial_request_port(port) == 0)
port->type = info->type;
}
@@ -849,6 +1247,73 @@ s3c24xx_serial_verify_port(struct uart_port *port, struct serial_struct *ser)
return 0;
}
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+/*
+ * Enable RS-485 called by IOCTL.
+ */
+static int
+s3c24xx_serial_enable_rs485(struct uart_port *port, struct serial_rs485 *r)
+{
+ struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
+ struct s3c24xx_uart_port *ourport = to_ourport(port);
+
+ /* Is GPIO valid for transmit enable. */
+ if (cfg->gpio_transmit_en > -1) {
+ /* GPIO Request, Config, Direction, Value, and Free the pin*/
+ gpio_set_value(cfg->gpio_transmit_en, 0);
+ }
+
+ /* Is GPIO valid for receive enable. */
+ if (cfg->gpio_receive_en > -1) {
+ /* GPIO Request, Config, Direction, Value, and Free the pin*/
+ gpio_set_value(cfg->gpio_receive_en, 0);
+ }
+
+ ourport->rs485 = *r;
+
+ /* Maximum delay before RTS equal to 1000 */
+ if (ourport->rs485.delay_rts_before_send >= 1000)
+ ourport->rs485.delay_rts_before_send = 1000;
+
+#if 0
+ dev_info(port., "rts: on send = %i, after = %i, enabled = %i",
+ info->rs485.rts_on_send,
+ info->rs485.rts_after_sent,
+ info->rs485.enabled
+ );
+#endif
+
+ return 0;
+}
+
+
+static int s3c24xx_serial_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg)
+{
+
+ struct serial_rs485 rs485conf;
+
+ switch (cmd) {
+ case TIOCSRS485:
+ if (copy_from_user(&rs485conf, (struct serial_rs485 *) arg,
+ sizeof(rs485conf)))
+ return -EFAULT;
+
+ s3c24xx_serial_enable_rs485(port, &rs485conf);
+ break;
+
+ case TIOCGRS485:
+ if (copy_to_user((struct serial_rs485 *) arg,
+ &(to_ourport(port)->rs485),
+ sizeof(rs485conf)))
+ return -EFAULT;
+ break;
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+#endif /*CONFIG_SAMSUNG_HAS_RS485*/
#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE
@@ -877,6 +1342,9 @@ static struct uart_ops s3c24xx_serial_ops = {
.request_port = s3c24xx_serial_request_port,
.config_port = s3c24xx_serial_config_port,
.verify_port = s3c24xx_serial_verify_port,
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+ .ioctl = s3c24xx_serial_ioctl,
+#endif /* CONFIG_SAMSUNG_HAS_RS485 */
};
@@ -955,9 +1423,16 @@ static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS
static inline int s3c24xx_serial_resetport(struct uart_port *port,
struct s3c2410_uartcfg *cfg)
{
+ int ret;
struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
- return (info->reset_port)(port, cfg);
+ ret = (info->reset_port)(port, cfg);
+
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+ update_char_time(port);
+#endif /* CONFIG_SAMSUNG_HAS_RS485 */
+
+ return ret;
}
@@ -1077,6 +1552,42 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
port->dev = &platdev->dev;
ourport->info = info;
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+
+ dev_info(port->dev, "port TX GPIO (%d)\n", cfg->gpio_transmit_en);
+ dev_info(port->dev, "port TX GPIO (%d)\n", cfg->gpio_receive_en);
+
+ if (cfg->gpio_transmit_en > -1) {
+ /* Setup 485 as default on capable ports.*/
+ ourport->rs485.flags = (SER_RS485_ENABLED | SER_RS485_ALWAYS_LISTEN |
+ (cfg->enable_token ? SER_RS485_TOGGLE_ON_TOKEN : 0));
+ ourport->rs485.toggle_token = cfg->token;
+
+#ifdef CONFIG_SAMSUNG_485_LOW_RES_TIMER
+ dev_info(&(port->dev), "Enable Lo Res Timer\n");
+ setup_timer(&(ourport->rs485_tx_timer),
+ rs485_toggle_rts_timer_function,
+ (unsigned long)port);
+#else
+ dev_info(port->dev, "Enable Hi Res Timer\n");
+
+ /* Initialize HR timer to relative and monotonic mode. */
+ hrtimer_init(&(ourport->hr_rs485_tx_timer),
+ CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+
+ /* register Callback to appropriate UART */
+ ourport->hr_rs485_tx_timer.function =
+ callback_list[ourport->port.line];
+
+#endif
+
+ dev_info(port->dev, "Port (%d) 485 Enabled\n", ourport->port.line);
+ } else {
+ /* disable 485 on ports inacable of mode. */
+ ourport->rs485.flags = 0;
+ }
+#endif /* CONFIG_SAMSUNG_HAS_RS485*/
+
/* copy the info in from provided structure */
ourport->port.fifosize = info->fifosize;
@@ -1137,6 +1648,55 @@ static ssize_t s3c24xx_serial_show_clksrc(struct device *dev,
static DEVICE_ATTR(clock_source, S_IRUGO, s3c24xx_serial_show_clksrc, NULL);
+
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+
+static ssize_t s3c24xx_serial_show_485_status(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret = 0;
+ struct uart_port *port = s3c24xx_dev_to_port(dev);
+ struct s3c24xx_uart_port *ourport = to_ourport(port);
+
+ if (ourport->rs485.flags & SER_RS485_ENABLED) {
+ ret = snprintf(buf, PAGE_SIZE, "[Enabled] Disabled\n");
+ } else {
+ ret = snprintf(buf, PAGE_SIZE, "Enabled [Disabled]\n");
+ }
+
+ return ret;
+}
+
+static ssize_t s3c24xx_serial_set_485_mode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+
+{
+ struct uart_port *port = s3c24xx_dev_to_port(dev);
+ struct s3c24xx_uart_port *ourport = to_ourport(port);
+
+ if (!strncmp(buf, "Enabled", 7)) {
+ ourport->rs485.flags |= SER_RS485_ENABLED;
+ } else if (!strncmp(buf, "Disabled", 8)) {
+ ourport->rs485.flags &= ~SER_RS485_ENABLED;
+ } else {
+ dev_err(port->dev, "unknown string\n");
+
+ return -EINVAL;
+ }
+
+ return count;
+
+}
+
+static DEVICE_ATTR(485_status,
+ S_IRUGO | S_IWUSR,
+ s3c24xx_serial_show_485_status,
+ s3c24xx_serial_set_485_mode);
+
+#endif
+
/* Device driver serial port probe */
static int probe_index;
@@ -1144,8 +1704,10 @@ static int probe_index;
int s3c24xx_serial_probe(struct platform_device *dev,
struct s3c24xx_uart_info *info)
{
- struct s3c24xx_uart_port *ourport;
int ret;
+ struct s3c24xx_uart_port *ourport;
+ struct s3c2410_uartcfg *cfg = s3c24xx_dev_to_cfg(&dev->dev);
+
dbg("s3c24xx_serial_probe(%p, %p) %d\n", dev, info, probe_index);
@@ -1170,6 +1732,33 @@ int s3c24xx_serial_probe(struct platform_device *dev,
if (ret < 0)
dev_err(&dev->dev, "failed to add cpufreq notifier\n");
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+
+ ret = device_create_file(&dev->dev, &dev_attr_485_status);
+ if (ret < 0)
+ printk(KERN_ERR "%s: failed to add 485 status attr.\n", __func__);
+
+
+ if (cfg->gpio_transmit_en > -1) {
+ WARN_ON(gpio_request(cfg->gpio_transmit_en, "RS485TX"));
+ WARN_ON(s3c_gpio_cfgpin(cfg->gpio_transmit_en, S3C_GPIO_OUTPUT));
+ gpio_direction_output(cfg->gpio_transmit_en, 0);
+ gpio_set_value(cfg->gpio_transmit_en, 0);
+
+ dev_info(ourport->port.dev, "Initialize TX(%d) GPIO\n", ourport->port.line);
+
+ if (cfg->gpio_receive_en > -1) {
+ WARN_ON(gpio_request(cfg->gpio_receive_en , "RS485RX"));
+ WARN_ON(s3c_gpio_cfgpin(cfg->gpio_receive_en, S3C_GPIO_OUTPUT));
+ gpio_direction_output(cfg->gpio_receive_en, 0);
+ gpio_set_value(cfg->gpio_receive_en, 0);
+
+ dev_info(ourport->port.dev, "Initialize RX(%d) GPIO\n", ourport->port.line);
+ }
+ }
+#endif
+
+
return 0;
probe_err:
@@ -1181,8 +1770,33 @@ EXPORT_SYMBOL_GPL(s3c24xx_serial_probe);
int __devexit s3c24xx_serial_remove(struct platform_device *dev)
{
struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
+ struct s3c2410_uartcfg *cfg = s3c24xx_dev_to_cfg(&dev->dev);
if (port) {
+
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+ if (cfg->gpio_transmit_en > -1) {
+ gpio_free(cfg->gpio_transmit_en);
+
+ dev_info(port->dev,
+ "Uninitialize TX(%d) GPIO\n", port->line);
+
+ if (cfg->gpio_receive_en > -1) {
+ gpio_free(cfg->gpio_receive_en);
+
+ dev_info(port->dev,
+ "Uninitialize RX(%d) GPIO\n",
+ port->line);
+ }
+ }
+
+ /* Delete timer after device is removed. */
+#ifdef CONFIG_SAMSUNG_485_LOW_RES_TIMER
+ del_timer_sync(&(to_ourport(port)->rs485_tx_timer));
+#else
+ hrtimer_cancel(&(to_ourport(port)->hr_rs485_tx_timer));
+#endif
+#endif /* CONFIG_SAMSUNG_HAS_RS485 */
s3c24xx_serial_cpufreq_deregister(to_ourport(port));
device_remove_file(&dev->dev, &dev_attr_clock_source);
uart_remove_one_port(&s3c24xx_uart_drv, port);
@@ -1308,9 +1922,33 @@ s3c24xx_serial_console_write(struct console *co, const char *s,
uart_console_write(cons_uart, s, count, s3c24xx_serial_console_putchar);
}
+
+/* s3c24xx_serial_init_ports
+ *
+ * initialise the serial ports from the machine provided initialisation
+ * data.
+*/
+
+static int s3c24xx_serial_init_ports(struct s3c24xx_uart_info **info)
+{
+ struct s3c24xx_uart_port *ptr = s3c24xx_serial_ports;
+ struct platform_device **platdev_ptr;
+ int i;
+
+ dbg("s3c24xx_serial_init_ports: initialising ports...\n");
+
+ platdev_ptr = s3c24xx_uart_devs;
+
+ for (i = 0; i < CONFIG_SERIAL_SAMSUNG_UARTS; i++, ptr++, platdev_ptr++) {
+ s3c24xx_serial_init_port(ptr, info[i], *platdev_ptr);
+ }
+
+ return 0;
+}
+
static void __init
s3c24xx_serial_get_options(struct uart_port *port, int *baud,
- int *parity, int *bits)
+ int *parity, int *stop, int *bits)
{
struct s3c24xx_uart_clksrc clksrc;
struct clk *clk;
@@ -1360,6 +1998,12 @@ s3c24xx_serial_get_options(struct uart_port *port, int *baud,
*parity = 'n';
}
+ if (ulcon | S3C2410_LCON_STOPB) {
+ *stop = 2;
+ } else {
+ *stop = 1;
+ }
+
/* now calculate the baud rate */
s3c24xx_serial_getsource(port, &clksrc);
@@ -1377,29 +2021,6 @@ s3c24xx_serial_get_options(struct uart_port *port, int *baud,
}
-/* s3c24xx_serial_init_ports
- *
- * initialise the serial ports from the machine provided initialisation
- * data.
-*/
-
-static int s3c24xx_serial_init_ports(struct s3c24xx_uart_info **info)
-{
- struct s3c24xx_uart_port *ptr = s3c24xx_serial_ports;
- struct platform_device **platdev_ptr;
- int i;
-
- dbg("s3c24xx_serial_init_ports: initialising ports...\n");
-
- platdev_ptr = s3c24xx_uart_devs;
-
- for (i = 0; i < CONFIG_SERIAL_SAMSUNG_UARTS; i++, ptr++, platdev_ptr++) {
- s3c24xx_serial_init_port(ptr, info[i], *platdev_ptr);
- }
-
- return 0;
-}
-
static int __init
s3c24xx_serial_console_setup(struct console *co, char *options)
{
@@ -1408,6 +2029,7 @@ s3c24xx_serial_console_setup(struct console *co, char *options)
int bits = 8;
int parity = 'n';
int flow = 'n';
+ int stop = 1;
dbg("s3c24xx_serial_console_setup: co=%p (%d), %s\n",
co, co->index, options);
@@ -1436,7 +2058,7 @@ s3c24xx_serial_console_setup(struct console *co, char *options)
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
else
- s3c24xx_serial_get_options(port, &baud, &parity, &bits);
+ s3c24xx_serial_get_options(port, &baud, &parity, &stop, &bits);
dbg("s3c24xx_serial_console_setup: baud %d\n", baud);
diff --git a/drivers/tty/serial/samsung.h b/drivers/tty/serial/samsung.h
index a69d9a5..f550dc3 100644
--- a/drivers/tty/serial/samsung.h
+++ b/drivers/tty/serial/samsung.h
@@ -4,6 +4,10 @@
* Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
* http://armlinux.simtec.co.uk/
*
+ * Paul Schilling, Copyright (c) 2011 Ecolab Corp.
+ * Added RS-485 support to the Samsung driver..
+ *
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
@@ -31,6 +35,7 @@ struct s3c24xx_uart_info {
/* uart controls */
int (*reset_port)(struct uart_port *, struct s3c2410_uartcfg *);
+
};
struct s3c24xx_uart_port {
@@ -48,6 +53,16 @@ struct s3c24xx_uart_port {
struct clk *baudclk;
struct uart_port port;
+ struct serial_rs485 rs485; /* RS-485 support */
+
+#ifdef CONFIG_SAMSUNG_485_LOW_RES_TIMER
+ unsigned long char_time_usec; /* The time for 1 char, in micro secs */
+ struct timer_list rs485_tx_timer;
+#else
+ unsigned long char_time_nanosec; /* The time for 1 char, in nano secs */
+ struct hrtimer hr_rs485_tx_timer; /* Timer for RS-485 Receive enable*/
+#endif
+
#ifdef CONFIG_CPU_FREQ
struct notifier_block freq_transition;
#endif
diff --git a/include/linux/serial.h b/include/linux/serial.h
index ef91406..826b1c0 100644
--- a/include/linux/serial.h
+++ b/include/linux/serial.h
@@ -211,9 +211,12 @@ struct serial_rs485 {
#define SER_RS485_RTS_ON_SEND (1 << 1)
#define SER_RS485_RTS_AFTER_SEND (1 << 2)
#define SER_RS485_RTS_BEFORE_SEND (1 << 3)
+#define SER_RS485_ALWAYS_LISTEN (1 << 4)
+#define SER_RS485_TOGGLE_ON_TOKEN (1 << 5)
__u32 delay_rts_before_send; /* Milliseconds */
__u32 delay_rts_after_send; /* Milliseconds */
- __u32 padding[5]; /* Memory is cheap, new structs
+ __u32 toggle_token; /* Token used to toggle to receive */
+ __u32 padding[4]; /* Memory is cheap, new structs
are a royal PITA .. */
};
--
1.7.6.4
^ permalink raw reply related
* [PATCH 02/14] ARM : SAMSUNG : Add RS485 support.
From: Paul Schilling @ 2011-10-22 3:46 UTC (permalink / raw)
To: Ben Dooks, Kukjin Kim, Russell King, Alan Cox, Greg Kroah-Hartman,
Boo
Cc: Paul Schilling, Paul Schilling
In-Reply-To: <samsung_rs485>
Add RS485 tranmit/recieve control line capabilities
This RS485 driver uses two methodes to determine if the transmit
should be disabled.
1. It uses a timer and polling to determine when transmit has completed.
2. Optionally uses a token used to terminate the message to be used in
the recieve interrupt to disable the transmit.
Option 1 alone can be used but doesn't garentee that the transmit line
wont be disabled within 1 to 2 character times depending on system load.
This patch adds an additional variable to the serial RS-485 struct so
that a program can change the terminate token value via the IOCTL.
Signed-off-by: Paul Schilling <paul.s.schilling@gmail.com>
---
arch/arm/plat-samsung/include/plat/regs-serial.h | 7 +
drivers/tty/serial/Kconfig | 16 +
drivers/tty/serial/samsung.c | 738 ++++++++++++++++++++--
drivers/tty/serial/samsung.h | 15 +
include/linux/serial.h | 5 +-
5 files changed, 722 insertions(+), 59 deletions(-)
diff --git a/arch/arm/plat-samsung/include/plat/regs-serial.h b/arch/arm/plat-samsung/include/plat/regs-serial.h
index bac36fa..9618e7d 100644
--- a/arch/arm/plat-samsung/include/plat/regs-serial.h
+++ b/arch/arm/plat-samsung/include/plat/regs-serial.h
@@ -261,6 +261,13 @@ struct s3c2410_uartcfg {
struct s3c24xx_uart_clksrc *clocks;
unsigned int clocks_size;
+
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+ signed int gpio_transmit_en;
+ signed int gpio_receive_en;
+ unsigned char enable_token;
+ unsigned char token;
+#endif
};
/* s3c24xx_uart_devs
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 4dcb37b..dab33c2 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -464,6 +464,22 @@ config SERIAL_SAMSUNG_UARTS
Select the number of available UART ports for the Samsung S3C
serial driver
+config SAMSUNG_HAS_RS485
+ bool "Enable RS485 support for Samsung"
+ depends on SERIAL_SAMSUNG && (MACH_CONDOR2440 || MACH_CONDOR2416 || MACH_MINI2440)
+ default y if (MACH_CONDOR2440 || MACH_CONDOR2416)
+ default n if (MACH_MINI2440)
+
+config SAMSUNG_485_LOW_RES_TIMER
+ bool "Samsung RS-485 use low res timer during transmit"
+ depends on SERIAL_SAMSUNG && SAMSUNG_HAS_RS485
+ default n
+ help
+ Use low resolution jiffies at 200 Hz for timer the RS-485
+ transmitter. This works but doesn't garantee hard realtime.
+ Say no if you need the transmitter off immediatly after sending
+ a string or character.
+
config SERIAL_SAMSUNG_DEBUG
bool "Samsung SoC serial debug"
depends on SERIAL_SAMSUNG && DEBUG_LL
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
index 6edafb5..bf61579 100644
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -4,12 +4,16 @@
* Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
* http://armlinux.simtec.co.uk/
*
+ * Paul Schilling, Copyright (c) 2011 Ecolab Corp.
+ * http://www.ecolab.com/
+ * Added RS-485 support to the Samsung UART driver.
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-/* Hote on 2410 error handling
+/* Note on 2410 error handling
*
* The s3c2410 manual has a love/hate affair with the contents of the
* UERSTAT register in the UART blocks, and keeps marking some of the
@@ -17,7 +21,7 @@
* it copes with BREAKs properly, so I am happy to ignore the RESERVED
* feature from the latter versions of the manual.
*
- * If it becomes aparrent that latter versions of the 2410 remove these
+ * If it becomes apparent that latter versions of the 2410 remove these
* bits, then action will have to be taken to differentiate the versions
* and change the policy on BREAK
*
@@ -42,6 +46,8 @@
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/cpufreq.h>
+#include <linux/uaccess.h>
+#include <linux/gpio.h>
#include <asm/irq.h>
@@ -66,11 +72,27 @@
/* flag to ignore all characters coming in */
#define RXSTAT_DUMMY_READ (0x10000000)
+static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS];
+
+
static inline struct s3c24xx_uart_port *to_ourport(struct uart_port *port)
{
return container_of(port, struct s3c24xx_uart_port, port);
}
+static inline struct s3c24xx_uart_info *s3c24xx_port_to_info(struct uart_port *port)
+{
+ return to_ourport(port)->info;
+}
+
+static inline struct s3c2410_uartcfg *s3c24xx_port_to_cfg(struct uart_port *port)
+{
+ if (port->dev == NULL)
+ return NULL;
+
+ return (struct s3c2410_uartcfg *)port->dev->platform_data;
+}
+
/* translate a port to the device name */
static inline const char *s3c24xx_serial_portname(struct uart_port *port)
@@ -83,6 +105,22 @@ static int s3c24xx_serial_txempty_nofifo(struct uart_port *port)
return (rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE);
}
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+/* Get the current transmit fifo count */
+static int s3c24xx_serial_tx_getfifocnt(struct s3c24xx_uart_port *ourport)
+{
+ struct s3c24xx_uart_info *info = ourport->info;
+ unsigned long ufstat = rd_regl(&(ourport->port), S3C2410_UFSTAT);
+
+ /* If FIFO is full then return FIFO size. */
+ if (ufstat & info->tx_fifofull)
+ return info->fifosize;
+
+ /* Else return number of entries in the FIFO. */
+ return (ufstat & info->tx_fifomask) >> info->tx_fifoshift;
+}
+#endif
+
static void s3c24xx_serial_rx_enable(struct uart_port *port)
{
unsigned long flags;
@@ -121,15 +159,205 @@ static void s3c24xx_serial_rx_disable(struct uart_port *port)
spin_unlock_irqrestore(&port->lock, flags);
}
+static void s3c24xx_serial_rx_fifo_enable(
+ struct uart_port *port,
+ unsigned int en)
+{
+ unsigned long flags;
+ unsigned int ucon;
+ static unsigned int last_state = 1;
+/* FIXME */
+ #if 0
+ if (last_state != en) {
+
+ struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ ucon = rd_regl(port, S3C2410_UCON);
+
+ ucon &= ~(S3C2440_UFCON_RXTRIG32 | S3C2410_UCON_RXILEVEL);
+
+ if (en) {
+ ucon |= cfg->ucon;
+ }
+
+ wr_regl(port, S3C2410_UCON, ucon);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+ }
+#endif
+}
+
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+/* Timer function to toggle RTS when using FAST_TIMER */
+#ifdef SAMSUNG485_LOW_RES_TIMER
+ static void rs485_toggle_rts_timer_function(unsigned long _data)
+ {
+ struct uart_port *port = (struct uart_port *)_data;
+ struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
+
+ struct s3c24xx_uart_port *ourport = to_ourport(port);
+
+ unsigned long utrstat;
+
+ utrstat = rd_regl(port, S3C2410_UTRSTAT);
+
+ if ((utrstat & S3C2410_UTRSTAT_TXE) ? 1 : 0) {
+ if (cfg->gpio_transmit_en > -1) {
+ gpio_set_value(cfg->gpio_transmit_en, 0);
+ }
+
+ if (cfg->gpio_receive_en > -1) {
+ gpio_set_value(cfg->gpio_receive_en, 0);
+ }
+ } else {
+ /* Set a short timer to toggle RTS */
+ mod_timer(
+ &(ourport->rs485_tx_timer),
+ jiffies + usecs_to_jiffies(
+ ourport->char_time_usec
+ / 10));
+ }
+ }
+#else
+
+
+static enum hrtimer_restart rs485_toggle_rts_timer_function(
+ struct s3c24xx_uart_port *ourport)
+{
+ struct s3c2410_uartcfg *cfg =
+ s3c24xx_port_to_cfg(&(ourport->port));
+
+ unsigned long utrstat;
+ enum hrtimer_restart ret;
+
+ /* Read UART transmit status register */
+ utrstat = rd_regl(&(ourport->port), S3C2410_UTRSTAT);
+
+ /* Check if the UART and shift register is empty*/
+ if ((utrstat & S3C2410_UTRSTAT_TXE) ? 1 : 0) {
+ /* Is the GPIO valid for RS485 transmit enable*/
+ if (cfg->gpio_transmit_en > -1) {
+ /* Request, Set, Free the transmit GPIO*/
+ gpio_set_value(cfg->gpio_transmit_en, 0);
+ }
+
+ /* Is the GPIO valid for the RS485 receive enable*/
+ if (cfg->gpio_receive_en > -1) {
+ /* Request, Set, Free the receive GPIO*/
+ gpio_set_value(cfg->gpio_receive_en, 0);
+ }
+
+ s3c24xx_serial_rx_fifo_enable(&(ourport->port), 1);
+
+ /* The timer has completed its task now we can disable it. */
+ ret = HRTIMER_NORESTART;
+ } else {
+
+ ktime_t kt;
+
+ if (s3c24xx_serial_tx_getfifocnt(ourport) > 1) {
+ kt = ktime_set(0, ourport->char_time_nanosec);
+ hrtimer_forward(&(ourport->hr_rs485_tx_timer),
+ ourport->hr_rs485_tx_timer.base->softirq_time,
+ kt);
+ } else {
+ kt = ktime_set(0, ourport->char_time_nanosec / 2);
+ hrtimer_forward(&(ourport->hr_rs485_tx_timer),
+ ourport->hr_rs485_tx_timer.base->softirq_time,
+ kt);
+ }
+
+ /* Timer will be enabled after the interrupt context */
+ ret = HRTIMER_RESTART;
+ }
+
+ return ret;
+}
+
+/* Uart 0 RS-485 timer callback */
+enum hrtimer_restart rs485_hr_timer_callback_uart0(struct hrtimer *timer)
+{
+
+ return rs485_toggle_rts_timer_function(&s3c24xx_serial_ports[0]);
+}
+
+/* Uart 0 RS-485 timer callback */
+enum hrtimer_restart rs485_hr_timer_callback_uart1(struct hrtimer *timer)
+{
+
+ return rs485_toggle_rts_timer_function(&s3c24xx_serial_ports[1]);
+}
+
+/* Uart 0 RS-485 timer callback */
+#if CONFIG_SERIAL_SAMSUNG_UARTS > 2
+enum hrtimer_restart rs485_hr_timer_callback_uart2(struct hrtimer *timer)
+{
+
+ return rs485_toggle_rts_timer_function(&s3c24xx_serial_ports[2]);
+}
+#endif
+
+/* Uart 0 RS-485 timer callback */
+#if CONFIG_SERIAL_SAMSUNG_UARTS > 3
+enum hrtimer_restart rs485_hr_timer_callback_uart3(struct hrtimer *timer)
+{
+
+ return rs485_toggle_rts_timer_function(&s3c24xx_serial_ports[3]);
+}
+#endif
+
+
+/* Callback array*/
+enum hrtimer_restart (*callback_list[CONFIG_SERIAL_SAMSUNG_UARTS])(struct hrtimer *) = {
+ &rs485_hr_timer_callback_uart0,
+ &rs485_hr_timer_callback_uart1,
+
+#if CONFIG_SERIAL_SAMSUNG_UARTS > 2
+ &rs485_hr_timer_callback_uart2,
+#endif
+
+#if CONFIG_SERIAL_SAMSUNG_UARTS > 3
+ &rs485_hr_timer_callback_uart3,
+#endif
+};
+
+#endif
+#endif /* CONFIG_SAMSUNG_HAS_RS485 */
+
+
static void s3c24xx_serial_stop_tx(struct uart_port *port)
{
struct s3c24xx_uart_port *ourport = to_ourport(port);
if (tx_enabled(port)) {
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+ if (ourport->rs485.flags & SER_RS485_ENABLED) {
+#ifdef CONFIG_SAMSUNG_485_LOW_RES_TIMER
+ /* Set a short timer to toggle RTS */
+ mod_timer(&(ourport->rs485_tx_timer),
+ jiffies + usecs_to_jiffies(ourport->char_time_usec * s3c24xx_serial_tx_getfifocnt(ourport)));
+#else
+ ktime_t kt;
+
+ /* Set time struct to one char time. */
+ kt = ktime_set(0, ourport->char_time_nanosec);
+
+ /* Start the high res timer. */
+ hrtimer_start(&(ourport->hr_rs485_tx_timer), kt, HRTIMER_MODE_REL);
+#endif /* CONFIG_SAMSUNG_485_LOW_RES_TIMER */
+
+ s3c24xx_serial_rx_fifo_enable(port, 0);
+
+ }
+#endif /* CONFIG_SAMSUNG_HAS_RS485 */
+
disable_irq_nosync(ourport->tx_irq);
tx_enabled(port) = 0;
- if (port->flags & UPF_CONS_FLOW)
+ if (port->flags & UPF_CONS_FLOW) {
s3c24xx_serial_rx_enable(port);
+ }
}
}
@@ -137,7 +365,42 @@ static void s3c24xx_serial_start_tx(struct uart_port *port)
{
struct s3c24xx_uart_port *ourport = to_ourport(port);
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+ hrtimer_try_to_cancel(&(ourport->hr_rs485_tx_timer));
+#endif
+
if (!tx_enabled(port)) {
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+ /* enable RS-485 */
+ if (ourport->rs485.flags & SER_RS485_ENABLED) {
+ struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
+
+ /* Is transmit GPIO valid */
+ if (cfg->gpio_transmit_en > -1) {
+ /* GPIO Request, Config, Direction, Value, and
+ * Free the pin*/
+ WARN_ON(s3c_gpio_cfgpin(cfg->gpio_transmit_en,
+ S3C_GPIO_OUTPUT));
+ gpio_direction_output(cfg->gpio_transmit_en, 1);
+ gpio_set_value(cfg->gpio_transmit_en, 1);
+ }
+
+ /* Is receive GPIO valid */
+ if ((cfg->gpio_receive_en > -1) &&
+ (!(ourport->rs485.flags &
+ SER_RS485_ALWAYS_LISTEN
+ ))) {
+ /* GPIO Request, Config, Direction, Value, and
+ * Free the pin*/
+ WARN_ON(s3c_gpio_cfgpin(cfg->gpio_receive_en,
+ S3C_GPIO_OUTPUT));
+ gpio_direction_output(cfg->gpio_receive_en, 1);
+ gpio_set_value(cfg->gpio_receive_en, 1);
+ }
+
+ }
+#endif /*CONFIG_SAMSUNG_HAS_RS485 */
+
if (port->flags & UPF_CONS_FLOW)
s3c24xx_serial_rx_disable(port);
@@ -162,18 +425,6 @@ static void s3c24xx_serial_enable_ms(struct uart_port *port)
{
}
-static inline struct s3c24xx_uart_info *s3c24xx_port_to_info(struct uart_port *port)
-{
- return to_ourport(port)->info;
-}
-
-static inline struct s3c2410_uartcfg *s3c24xx_port_to_cfg(struct uart_port *port)
-{
- if (port->dev == NULL)
- return NULL;
-
- return (struct s3c2410_uartcfg *)port->dev->platform_data;
-}
static int s3c24xx_serial_rx_fifocnt(struct s3c24xx_uart_port *ourport,
unsigned long ufstat)
@@ -186,6 +437,99 @@ static int s3c24xx_serial_rx_fifocnt(struct s3c24xx_uart_port *ourport,
return (ufstat & info->rx_fifomask) >> info->rx_fifoshift;
}
+static inline int
+s3c24xx_serial_getsource(struct uart_port *port, struct s3c24xx_uart_clksrc *c)
+{
+ struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
+
+ return (info->get_clksrc)(port, c);
+}
+
+static inline int
+s3c24xx_serial_setsource(struct uart_port *port, struct s3c24xx_uart_clksrc *c)
+{
+ struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
+
+ return (info->set_clksrc)(port, c);
+}
+
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+static void
+samsung_uart_get_options(struct uart_port *port, int *baud,
+ int *parity, int *stop, int *bits)
+{
+ struct s3c24xx_uart_clksrc clksrc;
+ struct clk *clk;
+ unsigned int ulcon;
+ unsigned int ucon;
+ unsigned int ubrdiv;
+ unsigned long rate;
+
+ ulcon = rd_regl(port, S3C2410_ULCON);
+ ucon = rd_regl(port, S3C2410_UCON);
+ ubrdiv = rd_regl(port, S3C2410_UBRDIV);
+
+ dbg("s3c24xx_serial_get_options: port=%p\n"
+ "registers: ulcon=%08x, ucon=%08x, ubdriv=%08x\n",
+ port, ulcon, ucon, ubrdiv);
+
+ if ((ucon & 0xf) != 0) {
+ /* consider the serial port configured if the tx/rx mode set */
+
+ switch (ulcon & S3C2410_LCON_CSMASK) {
+ case S3C2410_LCON_CS5:
+ *bits = 5;
+ break;
+ case S3C2410_LCON_CS6:
+ *bits = 6;
+ break;
+ case S3C2410_LCON_CS7:
+ *bits = 7;
+ break;
+ default:
+ case S3C2410_LCON_CS8:
+ *bits = 8;
+ break;
+ }
+
+ switch (ulcon & S3C2410_LCON_PMASK) {
+ case S3C2410_LCON_PEVEN:
+ *parity = 'e';
+ break;
+
+ case S3C2410_LCON_PODD:
+ *parity = 'o';
+ break;
+
+ case S3C2410_LCON_PNONE:
+ default:
+ *parity = 'n';
+ }
+
+ if (ulcon | S3C2410_LCON_STOPB) {
+ *stop = 2;
+ } else {
+ *stop = 1;
+ }
+
+ /* now calculate the baud rate */
+
+ s3c24xx_serial_getsource(port, &clksrc);
+
+ clk = clk_get(port->dev, clksrc.name);
+ if (!IS_ERR(clk) && clk != NULL)
+ rate = clk_get_rate(clk) / clksrc.divisor;
+ else
+ rate = 1;
+
+
+ *baud = rate / (16 * (ubrdiv + 1));
+ dbg("calculated baud %d\n", *baud);
+ }
+
+}
+#endif /* CONFIG_SAMSUNG_HAS_RS485 */
+
/* ? - where has parity gone?? */
#define S3C2410_UERSTAT_PARITY (0x1000)
@@ -209,6 +553,33 @@ s3c24xx_serial_rx_chars(int irq, void *dev_id)
uerstat = rd_regl(port, S3C2410_UERSTAT);
ch = rd_regb(port, S3C2410_URXH);
+ if (ourport->rs485.flags & SER_RS485_ENABLED) {
+ struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
+
+#ifdef CONFIG_TEST_485
+ /* Is the GPIO valid for the RS485 receive enable*/
+ if (cfg->gpio_receive_en > -1) {
+ /* Request, Set, Free the receive GPIO*/
+ gpio_set_value(cfg->gpio_receive_en, 1);
+ gpio_set_value(cfg->gpio_receive_en, 0);
+ }
+#endif
+
+ if ((SER_RS485_TOGGLE_ON_TOKEN & ourport->rs485.flags) &&
+ (ourport->rs485.toggle_token == ch)) {
+ /* Is the GPIO valid for RS485
+ * transmit enable*/
+ if (cfg->gpio_transmit_en > -1) {
+ /* Set the transmit GPIO line*/
+
+ gpio_set_value(cfg->gpio_transmit_en, 0);
+
+ }
+
+ s3c24xx_serial_rx_fifo_enable(port, 1);
+ }
+ }
+
if (port->flags & UPF_CONS_FLOW) {
int txe = s3c24xx_serial_txempty_nofifo(port);
@@ -488,21 +859,7 @@ static struct s3c24xx_uart_clksrc tmp_clksrc = {
.divisor = 1,
};
-static inline int
-s3c24xx_serial_getsource(struct uart_port *port, struct s3c24xx_uart_clksrc *c)
-{
- struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
-
- return (info->get_clksrc)(port, c);
-}
-static inline int
-s3c24xx_serial_setsource(struct uart_port *port, struct s3c24xx_uart_clksrc *c)
-{
- struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
-
- return (info->set_clksrc)(port, c);
-}
struct baud_calc {
struct s3c24xx_uart_clksrc *clksrc;
@@ -512,6 +869,41 @@ struct baud_calc {
struct clk *src;
};
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+/* Calculate the char_time depending on baudrate, number of bits etc. */
+static void update_char_time(struct uart_port *port)
+{
+
+ int bits = 8;
+ int baud = 9600;
+ int parity = 'n';
+ int stop = 1;
+
+ samsung_uart_get_options(port, &baud, &parity, &stop, &bits);
+
+ /* calc. number of bits / data byte */
+ /* databits + startbit and 1 stopbit */
+ bits++;
+
+ /* 2 stopbits ? */
+ bits += stop;
+
+ /* is parity enabled. */
+ if ('n' != parity) {
+ bits++;
+ }
+
+#ifdef CONFIG_SAMSUNG_485_LOW_RES_TIMER
+ /* calc timeout */
+ to_ourport(port)->char_time_usec = ((1000000 / baud) * bits) + 1;
+#else
+ /* calc timeout */
+ to_ourport(port)->char_time_nanosec = ((1000000000 / baud) * bits) + 1;
+#endif
+}
+
+#endif /*CONFIG_SAMSUNG_HAS_RS485 */
+
static int s3c24xx_serial_calcbaud(struct baud_calc *calc,
struct uart_port *port,
struct s3c24xx_uart_clksrc *clksrc,
@@ -785,7 +1177,7 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
port->ignore_status_mask = 0;
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= S3C2410_UERSTAT_OVERRUN;
- if (termios->c_iflag & IGNBRK && termios->c_iflag & IGNPAR)
+ if ((termios->c_iflag & IGNBRK) && (termios->c_iflag & IGNPAR))
port->ignore_status_mask |= S3C2410_UERSTAT_FRAME;
/*
@@ -795,6 +1187,12 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
port->ignore_status_mask |= RXSTAT_DUMMY_READ;
spin_unlock_irqrestore(&port->lock, flags);
+
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+ /* Update character time. */
+ update_char_time(port);
+#endif /* CONFIG_SAMSUNG_HAS_RS485 */
+
}
static const char *s3c24xx_serial_type(struct uart_port *port)
@@ -830,7 +1228,7 @@ static void s3c24xx_serial_config_port(struct uart_port *port, int flags)
{
struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
- if (flags & UART_CONFIG_TYPE &&
+ if ((flags & UART_CONFIG_TYPE) &&
s3c24xx_serial_request_port(port) == 0)
port->type = info->type;
}
@@ -849,6 +1247,73 @@ s3c24xx_serial_verify_port(struct uart_port *port, struct serial_struct *ser)
return 0;
}
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+/*
+ * Enable RS-485 called by IOCTL.
+ */
+static int
+s3c24xx_serial_enable_rs485(struct uart_port *port, struct serial_rs485 *r)
+{
+ struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
+ struct s3c24xx_uart_port *ourport = to_ourport(port);
+
+ /* Is GPIO valid for transmit enable. */
+ if (cfg->gpio_transmit_en > -1) {
+ /* GPIO Request, Config, Direction, Value, and Free the pin*/
+ gpio_set_value(cfg->gpio_transmit_en, 0);
+ }
+
+ /* Is GPIO valid for receive enable. */
+ if (cfg->gpio_receive_en > -1) {
+ /* GPIO Request, Config, Direction, Value, and Free the pin*/
+ gpio_set_value(cfg->gpio_receive_en, 0);
+ }
+
+ ourport->rs485 = *r;
+
+ /* Maximum delay before RTS equal to 1000 */
+ if (ourport->rs485.delay_rts_before_send >= 1000)
+ ourport->rs485.delay_rts_before_send = 1000;
+
+#if 0
+ dev_info(port., "rts: on send = %i, after = %i, enabled = %i",
+ info->rs485.rts_on_send,
+ info->rs485.rts_after_sent,
+ info->rs485.enabled
+ );
+#endif
+
+ return 0;
+}
+
+
+static int s3c24xx_serial_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg)
+{
+
+ struct serial_rs485 rs485conf;
+
+ switch (cmd) {
+ case TIOCSRS485:
+ if (copy_from_user(&rs485conf, (struct serial_rs485 *) arg,
+ sizeof(rs485conf)))
+ return -EFAULT;
+
+ s3c24xx_serial_enable_rs485(port, &rs485conf);
+ break;
+
+ case TIOCGRS485:
+ if (copy_to_user((struct serial_rs485 *) arg,
+ &(to_ourport(port)->rs485),
+ sizeof(rs485conf)))
+ return -EFAULT;
+ break;
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+#endif /*CONFIG_SAMSUNG_HAS_RS485*/
#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE
@@ -877,6 +1342,9 @@ static struct uart_ops s3c24xx_serial_ops = {
.request_port = s3c24xx_serial_request_port,
.config_port = s3c24xx_serial_config_port,
.verify_port = s3c24xx_serial_verify_port,
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+ .ioctl = s3c24xx_serial_ioctl,
+#endif /* CONFIG_SAMSUNG_HAS_RS485 */
};
@@ -955,9 +1423,16 @@ static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS
static inline int s3c24xx_serial_resetport(struct uart_port *port,
struct s3c2410_uartcfg *cfg)
{
+ int ret;
struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
- return (info->reset_port)(port, cfg);
+ ret = (info->reset_port)(port, cfg);
+
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+ update_char_time(port);
+#endif /* CONFIG_SAMSUNG_HAS_RS485 */
+
+ return ret;
}
@@ -1077,6 +1552,42 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
port->dev = &platdev->dev;
ourport->info = info;
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+
+ dev_info(port->dev, "port TX GPIO (%d)\n", cfg->gpio_transmit_en);
+ dev_info(port->dev, "port TX GPIO (%d)\n", cfg->gpio_receive_en);
+
+ if (cfg->gpio_transmit_en > -1) {
+ /* Setup 485 as default on capable ports.*/
+ ourport->rs485.flags = (SER_RS485_ENABLED | SER_RS485_ALWAYS_LISTEN |
+ (cfg->enable_token ? SER_RS485_TOGGLE_ON_TOKEN : 0));
+ ourport->rs485.toggle_token = cfg->token;
+
+#ifdef CONFIG_SAMSUNG_485_LOW_RES_TIMER
+ dev_info(&(port->dev), "Enable Lo Res Timer\n");
+ setup_timer(&(ourport->rs485_tx_timer),
+ rs485_toggle_rts_timer_function,
+ (unsigned long)port);
+#else
+ dev_info(port->dev, "Enable Hi Res Timer\n");
+
+ /* Initialize HR timer to relative and monotonic mode. */
+ hrtimer_init(&(ourport->hr_rs485_tx_timer),
+ CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+
+ /* register Callback to appropriate UART */
+ ourport->hr_rs485_tx_timer.function =
+ callback_list[ourport->port.line];
+
+#endif
+
+ dev_info(port->dev, "Port (%d) 485 Enabled\n", ourport->port.line);
+ } else {
+ /* disable 485 on ports inacable of mode. */
+ ourport->rs485.flags = 0;
+ }
+#endif /* CONFIG_SAMSUNG_HAS_RS485*/
+
/* copy the info in from provided structure */
ourport->port.fifosize = info->fifosize;
@@ -1137,6 +1648,55 @@ static ssize_t s3c24xx_serial_show_clksrc(struct device *dev,
static DEVICE_ATTR(clock_source, S_IRUGO, s3c24xx_serial_show_clksrc, NULL);
+
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+
+static ssize_t s3c24xx_serial_show_485_status(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret = 0;
+ struct uart_port *port = s3c24xx_dev_to_port(dev);
+ struct s3c24xx_uart_port *ourport = to_ourport(port);
+
+ if (ourport->rs485.flags & SER_RS485_ENABLED) {
+ ret = snprintf(buf, PAGE_SIZE, "[Enabled] Disabled\n");
+ } else {
+ ret = snprintf(buf, PAGE_SIZE, "Enabled [Disabled]\n");
+ }
+
+ return ret;
+}
+
+static ssize_t s3c24xx_serial_set_485_mode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+
+{
+ struct uart_port *port = s3c24xx_dev_to_port(dev);
+ struct s3c24xx_uart_port *ourport = to_ourport(port);
+
+ if (!strncmp(buf, "Enabled", 7)) {
+ ourport->rs485.flags |= SER_RS485_ENABLED;
+ } else if (!strncmp(buf, "Disabled", 8)) {
+ ourport->rs485.flags &= ~SER_RS485_ENABLED;
+ } else {
+ dev_err(port->dev, "unknown string\n");
+
+ return -EINVAL;
+ }
+
+ return count;
+
+}
+
+static DEVICE_ATTR(485_status,
+ S_IRUGO | S_IWUSR,
+ s3c24xx_serial_show_485_status,
+ s3c24xx_serial_set_485_mode);
+
+#endif
+
/* Device driver serial port probe */
static int probe_index;
@@ -1144,8 +1704,10 @@ static int probe_index;
int s3c24xx_serial_probe(struct platform_device *dev,
struct s3c24xx_uart_info *info)
{
- struct s3c24xx_uart_port *ourport;
int ret;
+ struct s3c24xx_uart_port *ourport;
+ struct s3c2410_uartcfg *cfg = s3c24xx_dev_to_cfg(&dev->dev);
+
dbg("s3c24xx_serial_probe(%p, %p) %d\n", dev, info, probe_index);
@@ -1170,6 +1732,33 @@ int s3c24xx_serial_probe(struct platform_device *dev,
if (ret < 0)
dev_err(&dev->dev, "failed to add cpufreq notifier\n");
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+
+ ret = device_create_file(&dev->dev, &dev_attr_485_status);
+ if (ret < 0)
+ printk(KERN_ERR "%s: failed to add 485 status attr.\n", __func__);
+
+
+ if (cfg->gpio_transmit_en > -1) {
+ WARN_ON(gpio_request(cfg->gpio_transmit_en, "RS485TX"));
+ WARN_ON(s3c_gpio_cfgpin(cfg->gpio_transmit_en, S3C_GPIO_OUTPUT));
+ gpio_direction_output(cfg->gpio_transmit_en, 0);
+ gpio_set_value(cfg->gpio_transmit_en, 0);
+
+ dev_info(ourport->port.dev, "Initialize TX(%d) GPIO\n", ourport->port.line);
+
+ if (cfg->gpio_receive_en > -1) {
+ WARN_ON(gpio_request(cfg->gpio_receive_en , "RS485RX"));
+ WARN_ON(s3c_gpio_cfgpin(cfg->gpio_receive_en, S3C_GPIO_OUTPUT));
+ gpio_direction_output(cfg->gpio_receive_en, 0);
+ gpio_set_value(cfg->gpio_receive_en, 0);
+
+ dev_info(ourport->port.dev, "Initialize RX(%d) GPIO\n", ourport->port.line);
+ }
+ }
+#endif
+
+
return 0;
probe_err:
@@ -1181,8 +1770,33 @@ EXPORT_SYMBOL_GPL(s3c24xx_serial_probe);
int __devexit s3c24xx_serial_remove(struct platform_device *dev)
{
struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
+ struct s3c2410_uartcfg *cfg = s3c24xx_dev_to_cfg(&dev->dev);
if (port) {
+
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+ if (cfg->gpio_transmit_en > -1) {
+ gpio_free(cfg->gpio_transmit_en);
+
+ dev_info(port->dev,
+ "Uninitialize TX(%d) GPIO\n", port->line);
+
+ if (cfg->gpio_receive_en > -1) {
+ gpio_free(cfg->gpio_receive_en);
+
+ dev_info(port->dev,
+ "Uninitialize RX(%d) GPIO\n",
+ port->line);
+ }
+ }
+
+ /* Delete timer after device is removed. */
+#ifdef CONFIG_SAMSUNG_485_LOW_RES_TIMER
+ del_timer_sync(&(to_ourport(port)->rs485_tx_timer));
+#else
+ hrtimer_cancel(&(to_ourport(port)->hr_rs485_tx_timer));
+#endif
+#endif /* CONFIG_SAMSUNG_HAS_RS485 */
s3c24xx_serial_cpufreq_deregister(to_ourport(port));
device_remove_file(&dev->dev, &dev_attr_clock_source);
uart_remove_one_port(&s3c24xx_uart_drv, port);
@@ -1308,9 +1922,33 @@ s3c24xx_serial_console_write(struct console *co, const char *s,
uart_console_write(cons_uart, s, count, s3c24xx_serial_console_putchar);
}
+
+/* s3c24xx_serial_init_ports
+ *
+ * initialise the serial ports from the machine provided initialisation
+ * data.
+*/
+
+static int s3c24xx_serial_init_ports(struct s3c24xx_uart_info **info)
+{
+ struct s3c24xx_uart_port *ptr = s3c24xx_serial_ports;
+ struct platform_device **platdev_ptr;
+ int i;
+
+ dbg("s3c24xx_serial_init_ports: initialising ports...\n");
+
+ platdev_ptr = s3c24xx_uart_devs;
+
+ for (i = 0; i < CONFIG_SERIAL_SAMSUNG_UARTS; i++, ptr++, platdev_ptr++) {
+ s3c24xx_serial_init_port(ptr, info[i], *platdev_ptr);
+ }
+
+ return 0;
+}
+
static void __init
s3c24xx_serial_get_options(struct uart_port *port, int *baud,
- int *parity, int *bits)
+ int *parity, int *stop, int *bits)
{
struct s3c24xx_uart_clksrc clksrc;
struct clk *clk;
@@ -1360,6 +1998,12 @@ s3c24xx_serial_get_options(struct uart_port *port, int *baud,
*parity = 'n';
}
+ if (ulcon | S3C2410_LCON_STOPB) {
+ *stop = 2;
+ } else {
+ *stop = 1;
+ }
+
/* now calculate the baud rate */
s3c24xx_serial_getsource(port, &clksrc);
@@ -1377,29 +2021,6 @@ s3c24xx_serial_get_options(struct uart_port *port, int *baud,
}
-/* s3c24xx_serial_init_ports
- *
- * initialise the serial ports from the machine provided initialisation
- * data.
-*/
-
-static int s3c24xx_serial_init_ports(struct s3c24xx_uart_info **info)
-{
- struct s3c24xx_uart_port *ptr = s3c24xx_serial_ports;
- struct platform_device **platdev_ptr;
- int i;
-
- dbg("s3c24xx_serial_init_ports: initialising ports...\n");
-
- platdev_ptr = s3c24xx_uart_devs;
-
- for (i = 0; i < CONFIG_SERIAL_SAMSUNG_UARTS; i++, ptr++, platdev_ptr++) {
- s3c24xx_serial_init_port(ptr, info[i], *platdev_ptr);
- }
-
- return 0;
-}
-
static int __init
s3c24xx_serial_console_setup(struct console *co, char *options)
{
@@ -1408,6 +2029,7 @@ s3c24xx_serial_console_setup(struct console *co, char *options)
int bits = 8;
int parity = 'n';
int flow = 'n';
+ int stop = 1;
dbg("s3c24xx_serial_console_setup: co=%p (%d), %s\n",
co, co->index, options);
@@ -1436,7 +2058,7 @@ s3c24xx_serial_console_setup(struct console *co, char *options)
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
else
- s3c24xx_serial_get_options(port, &baud, &parity, &bits);
+ s3c24xx_serial_get_options(port, &baud, &parity, &stop, &bits);
dbg("s3c24xx_serial_console_setup: baud %d\n", baud);
diff --git a/drivers/tty/serial/samsung.h b/drivers/tty/serial/samsung.h
index a69d9a5..f550dc3 100644
--- a/drivers/tty/serial/samsung.h
+++ b/drivers/tty/serial/samsung.h
@@ -4,6 +4,10 @@
* Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
* http://armlinux.simtec.co.uk/
*
+ * Paul Schilling, Copyright (c) 2011 Ecolab Corp.
+ * Added RS-485 support to the Samsung driver..
+ *
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
@@ -31,6 +35,7 @@ struct s3c24xx_uart_info {
/* uart controls */
int (*reset_port)(struct uart_port *, struct s3c2410_uartcfg *);
+
};
struct s3c24xx_uart_port {
@@ -48,6 +53,16 @@ struct s3c24xx_uart_port {
struct clk *baudclk;
struct uart_port port;
+ struct serial_rs485 rs485; /* RS-485 support */
+
+#ifdef CONFIG_SAMSUNG_485_LOW_RES_TIMER
+ unsigned long char_time_usec; /* The time for 1 char, in micro secs */
+ struct timer_list rs485_tx_timer;
+#else
+ unsigned long char_time_nanosec; /* The time for 1 char, in nano secs */
+ struct hrtimer hr_rs485_tx_timer; /* Timer for RS-485 Receive enable*/
+#endif
+
#ifdef CONFIG_CPU_FREQ
struct notifier_block freq_transition;
#endif
diff --git a/include/linux/serial.h b/include/linux/serial.h
index ef91406..826b1c0 100644
--- a/include/linux/serial.h
+++ b/include/linux/serial.h
@@ -211,9 +211,12 @@ struct serial_rs485 {
#define SER_RS485_RTS_ON_SEND (1 << 1)
#define SER_RS485_RTS_AFTER_SEND (1 << 2)
#define SER_RS485_RTS_BEFORE_SEND (1 << 3)
+#define SER_RS485_ALWAYS_LISTEN (1 << 4)
+#define SER_RS485_TOGGLE_ON_TOKEN (1 << 5)
__u32 delay_rts_before_send; /* Milliseconds */
__u32 delay_rts_after_send; /* Milliseconds */
- __u32 padding[5]; /* Memory is cheap, new structs
+ __u32 toggle_token; /* Token used to toggle to receive */
+ __u32 padding[4]; /* Memory is cheap, new structs
are a royal PITA .. */
};
--
1.7.6.4
^ permalink raw reply related
* [PATCH 02/14] ARM : SAMSUNG : Add RS485 support.
From: Paul Schilling @ 2011-10-22 3:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <samsung_rs485>
Add RS485 tranmit/recieve control line capabilities
This RS485 driver uses two methodes to determine if the transmit
should be disabled.
1. It uses a timer and polling to determine when transmit has completed.
2. Optionally uses a token used to terminate the message to be used in
the recieve interrupt to disable the transmit.
Option 1 alone can be used but doesn't garentee that the transmit line
wont be disabled within 1 to 2 character times depending on system load.
This patch adds an additional variable to the serial RS-485 struct so
that a program can change the terminate token value via the IOCTL.
Signed-off-by: Paul Schilling <paul.s.schilling@gmail.com>
---
arch/arm/plat-samsung/include/plat/regs-serial.h | 7 +
drivers/tty/serial/Kconfig | 16 +
drivers/tty/serial/samsung.c | 738 ++++++++++++++++++++--
drivers/tty/serial/samsung.h | 15 +
include/linux/serial.h | 5 +-
5 files changed, 722 insertions(+), 59 deletions(-)
diff --git a/arch/arm/plat-samsung/include/plat/regs-serial.h b/arch/arm/plat-samsung/include/plat/regs-serial.h
index bac36fa..9618e7d 100644
--- a/arch/arm/plat-samsung/include/plat/regs-serial.h
+++ b/arch/arm/plat-samsung/include/plat/regs-serial.h
@@ -261,6 +261,13 @@ struct s3c2410_uartcfg {
struct s3c24xx_uart_clksrc *clocks;
unsigned int clocks_size;
+
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+ signed int gpio_transmit_en;
+ signed int gpio_receive_en;
+ unsigned char enable_token;
+ unsigned char token;
+#endif
};
/* s3c24xx_uart_devs
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 4dcb37b..dab33c2 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -464,6 +464,22 @@ config SERIAL_SAMSUNG_UARTS
Select the number of available UART ports for the Samsung S3C
serial driver
+config SAMSUNG_HAS_RS485
+ bool "Enable RS485 support for Samsung"
+ depends on SERIAL_SAMSUNG && (MACH_CONDOR2440 || MACH_CONDOR2416 || MACH_MINI2440)
+ default y if (MACH_CONDOR2440 || MACH_CONDOR2416)
+ default n if (MACH_MINI2440)
+
+config SAMSUNG_485_LOW_RES_TIMER
+ bool "Samsung RS-485 use low res timer during transmit"
+ depends on SERIAL_SAMSUNG && SAMSUNG_HAS_RS485
+ default n
+ help
+ Use low resolution jiffies at 200 Hz for timer the RS-485
+ transmitter. This works but doesn't garantee hard realtime.
+ Say no if you need the transmitter off immediatly after sending
+ a string or character.
+
config SERIAL_SAMSUNG_DEBUG
bool "Samsung SoC serial debug"
depends on SERIAL_SAMSUNG && DEBUG_LL
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
index 6edafb5..bf61579 100644
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -4,12 +4,16 @@
* Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
* http://armlinux.simtec.co.uk/
*
+ * Paul Schilling, Copyright (c) 2011 Ecolab Corp.
+ * http://www.ecolab.com/
+ * Added RS-485 support to the Samsung UART driver.
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-/* Hote on 2410 error handling
+/* Note on 2410 error handling
*
* The s3c2410 manual has a love/hate affair with the contents of the
* UERSTAT register in the UART blocks, and keeps marking some of the
@@ -17,7 +21,7 @@
* it copes with BREAKs properly, so I am happy to ignore the RESERVED
* feature from the latter versions of the manual.
*
- * If it becomes aparrent that latter versions of the 2410 remove these
+ * If it becomes apparent that latter versions of the 2410 remove these
* bits, then action will have to be taken to differentiate the versions
* and change the policy on BREAK
*
@@ -42,6 +46,8 @@
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/cpufreq.h>
+#include <linux/uaccess.h>
+#include <linux/gpio.h>
#include <asm/irq.h>
@@ -66,11 +72,27 @@
/* flag to ignore all characters coming in */
#define RXSTAT_DUMMY_READ (0x10000000)
+static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS];
+
+
static inline struct s3c24xx_uart_port *to_ourport(struct uart_port *port)
{
return container_of(port, struct s3c24xx_uart_port, port);
}
+static inline struct s3c24xx_uart_info *s3c24xx_port_to_info(struct uart_port *port)
+{
+ return to_ourport(port)->info;
+}
+
+static inline struct s3c2410_uartcfg *s3c24xx_port_to_cfg(struct uart_port *port)
+{
+ if (port->dev == NULL)
+ return NULL;
+
+ return (struct s3c2410_uartcfg *)port->dev->platform_data;
+}
+
/* translate a port to the device name */
static inline const char *s3c24xx_serial_portname(struct uart_port *port)
@@ -83,6 +105,22 @@ static int s3c24xx_serial_txempty_nofifo(struct uart_port *port)
return (rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE);
}
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+/* Get the current transmit fifo count */
+static int s3c24xx_serial_tx_getfifocnt(struct s3c24xx_uart_port *ourport)
+{
+ struct s3c24xx_uart_info *info = ourport->info;
+ unsigned long ufstat = rd_regl(&(ourport->port), S3C2410_UFSTAT);
+
+ /* If FIFO is full then return FIFO size. */
+ if (ufstat & info->tx_fifofull)
+ return info->fifosize;
+
+ /* Else return number of entries in the FIFO. */
+ return (ufstat & info->tx_fifomask) >> info->tx_fifoshift;
+}
+#endif
+
static void s3c24xx_serial_rx_enable(struct uart_port *port)
{
unsigned long flags;
@@ -121,15 +159,205 @@ static void s3c24xx_serial_rx_disable(struct uart_port *port)
spin_unlock_irqrestore(&port->lock, flags);
}
+static void s3c24xx_serial_rx_fifo_enable(
+ struct uart_port *port,
+ unsigned int en)
+{
+ unsigned long flags;
+ unsigned int ucon;
+ static unsigned int last_state = 1;
+/* FIXME */
+ #if 0
+ if (last_state != en) {
+
+ struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ ucon = rd_regl(port, S3C2410_UCON);
+
+ ucon &= ~(S3C2440_UFCON_RXTRIG32 | S3C2410_UCON_RXILEVEL);
+
+ if (en) {
+ ucon |= cfg->ucon;
+ }
+
+ wr_regl(port, S3C2410_UCON, ucon);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+ }
+#endif
+}
+
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+/* Timer function to toggle RTS when using FAST_TIMER */
+#ifdef SAMSUNG485_LOW_RES_TIMER
+ static void rs485_toggle_rts_timer_function(unsigned long _data)
+ {
+ struct uart_port *port = (struct uart_port *)_data;
+ struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
+
+ struct s3c24xx_uart_port *ourport = to_ourport(port);
+
+ unsigned long utrstat;
+
+ utrstat = rd_regl(port, S3C2410_UTRSTAT);
+
+ if ((utrstat & S3C2410_UTRSTAT_TXE) ? 1 : 0) {
+ if (cfg->gpio_transmit_en > -1) {
+ gpio_set_value(cfg->gpio_transmit_en, 0);
+ }
+
+ if (cfg->gpio_receive_en > -1) {
+ gpio_set_value(cfg->gpio_receive_en, 0);
+ }
+ } else {
+ /* Set a short timer to toggle RTS */
+ mod_timer(
+ &(ourport->rs485_tx_timer),
+ jiffies + usecs_to_jiffies(
+ ourport->char_time_usec
+ / 10));
+ }
+ }
+#else
+
+
+static enum hrtimer_restart rs485_toggle_rts_timer_function(
+ struct s3c24xx_uart_port *ourport)
+{
+ struct s3c2410_uartcfg *cfg =
+ s3c24xx_port_to_cfg(&(ourport->port));
+
+ unsigned long utrstat;
+ enum hrtimer_restart ret;
+
+ /* Read UART transmit status register */
+ utrstat = rd_regl(&(ourport->port), S3C2410_UTRSTAT);
+
+ /* Check if the UART and shift register is empty*/
+ if ((utrstat & S3C2410_UTRSTAT_TXE) ? 1 : 0) {
+ /* Is the GPIO valid for RS485 transmit enable*/
+ if (cfg->gpio_transmit_en > -1) {
+ /* Request, Set, Free the transmit GPIO*/
+ gpio_set_value(cfg->gpio_transmit_en, 0);
+ }
+
+ /* Is the GPIO valid for the RS485 receive enable*/
+ if (cfg->gpio_receive_en > -1) {
+ /* Request, Set, Free the receive GPIO*/
+ gpio_set_value(cfg->gpio_receive_en, 0);
+ }
+
+ s3c24xx_serial_rx_fifo_enable(&(ourport->port), 1);
+
+ /* The timer has completed its task now we can disable it. */
+ ret = HRTIMER_NORESTART;
+ } else {
+
+ ktime_t kt;
+
+ if (s3c24xx_serial_tx_getfifocnt(ourport) > 1) {
+ kt = ktime_set(0, ourport->char_time_nanosec);
+ hrtimer_forward(&(ourport->hr_rs485_tx_timer),
+ ourport->hr_rs485_tx_timer.base->softirq_time,
+ kt);
+ } else {
+ kt = ktime_set(0, ourport->char_time_nanosec / 2);
+ hrtimer_forward(&(ourport->hr_rs485_tx_timer),
+ ourport->hr_rs485_tx_timer.base->softirq_time,
+ kt);
+ }
+
+ /* Timer will be enabled after the interrupt context */
+ ret = HRTIMER_RESTART;
+ }
+
+ return ret;
+}
+
+/* Uart 0 RS-485 timer callback */
+enum hrtimer_restart rs485_hr_timer_callback_uart0(struct hrtimer *timer)
+{
+
+ return rs485_toggle_rts_timer_function(&s3c24xx_serial_ports[0]);
+}
+
+/* Uart 0 RS-485 timer callback */
+enum hrtimer_restart rs485_hr_timer_callback_uart1(struct hrtimer *timer)
+{
+
+ return rs485_toggle_rts_timer_function(&s3c24xx_serial_ports[1]);
+}
+
+/* Uart 0 RS-485 timer callback */
+#if CONFIG_SERIAL_SAMSUNG_UARTS > 2
+enum hrtimer_restart rs485_hr_timer_callback_uart2(struct hrtimer *timer)
+{
+
+ return rs485_toggle_rts_timer_function(&s3c24xx_serial_ports[2]);
+}
+#endif
+
+/* Uart 0 RS-485 timer callback */
+#if CONFIG_SERIAL_SAMSUNG_UARTS > 3
+enum hrtimer_restart rs485_hr_timer_callback_uart3(struct hrtimer *timer)
+{
+
+ return rs485_toggle_rts_timer_function(&s3c24xx_serial_ports[3]);
+}
+#endif
+
+
+/* Callback array*/
+enum hrtimer_restart (*callback_list[CONFIG_SERIAL_SAMSUNG_UARTS])(struct hrtimer *) = {
+ &rs485_hr_timer_callback_uart0,
+ &rs485_hr_timer_callback_uart1,
+
+#if CONFIG_SERIAL_SAMSUNG_UARTS > 2
+ &rs485_hr_timer_callback_uart2,
+#endif
+
+#if CONFIG_SERIAL_SAMSUNG_UARTS > 3
+ &rs485_hr_timer_callback_uart3,
+#endif
+};
+
+#endif
+#endif /* CONFIG_SAMSUNG_HAS_RS485 */
+
+
static void s3c24xx_serial_stop_tx(struct uart_port *port)
{
struct s3c24xx_uart_port *ourport = to_ourport(port);
if (tx_enabled(port)) {
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+ if (ourport->rs485.flags & SER_RS485_ENABLED) {
+#ifdef CONFIG_SAMSUNG_485_LOW_RES_TIMER
+ /* Set a short timer to toggle RTS */
+ mod_timer(&(ourport->rs485_tx_timer),
+ jiffies + usecs_to_jiffies(ourport->char_time_usec * s3c24xx_serial_tx_getfifocnt(ourport)));
+#else
+ ktime_t kt;
+
+ /* Set time struct to one char time. */
+ kt = ktime_set(0, ourport->char_time_nanosec);
+
+ /* Start the high res timer. */
+ hrtimer_start(&(ourport->hr_rs485_tx_timer), kt, HRTIMER_MODE_REL);
+#endif /* CONFIG_SAMSUNG_485_LOW_RES_TIMER */
+
+ s3c24xx_serial_rx_fifo_enable(port, 0);
+
+ }
+#endif /* CONFIG_SAMSUNG_HAS_RS485 */
+
disable_irq_nosync(ourport->tx_irq);
tx_enabled(port) = 0;
- if (port->flags & UPF_CONS_FLOW)
+ if (port->flags & UPF_CONS_FLOW) {
s3c24xx_serial_rx_enable(port);
+ }
}
}
@@ -137,7 +365,42 @@ static void s3c24xx_serial_start_tx(struct uart_port *port)
{
struct s3c24xx_uart_port *ourport = to_ourport(port);
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+ hrtimer_try_to_cancel(&(ourport->hr_rs485_tx_timer));
+#endif
+
if (!tx_enabled(port)) {
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+ /* enable RS-485 */
+ if (ourport->rs485.flags & SER_RS485_ENABLED) {
+ struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
+
+ /* Is transmit GPIO valid */
+ if (cfg->gpio_transmit_en > -1) {
+ /* GPIO Request, Config, Direction, Value, and
+ * Free the pin*/
+ WARN_ON(s3c_gpio_cfgpin(cfg->gpio_transmit_en,
+ S3C_GPIO_OUTPUT));
+ gpio_direction_output(cfg->gpio_transmit_en, 1);
+ gpio_set_value(cfg->gpio_transmit_en, 1);
+ }
+
+ /* Is receive GPIO valid */
+ if ((cfg->gpio_receive_en > -1) &&
+ (!(ourport->rs485.flags &
+ SER_RS485_ALWAYS_LISTEN
+ ))) {
+ /* GPIO Request, Config, Direction, Value, and
+ * Free the pin*/
+ WARN_ON(s3c_gpio_cfgpin(cfg->gpio_receive_en,
+ S3C_GPIO_OUTPUT));
+ gpio_direction_output(cfg->gpio_receive_en, 1);
+ gpio_set_value(cfg->gpio_receive_en, 1);
+ }
+
+ }
+#endif /*CONFIG_SAMSUNG_HAS_RS485 */
+
if (port->flags & UPF_CONS_FLOW)
s3c24xx_serial_rx_disable(port);
@@ -162,18 +425,6 @@ static void s3c24xx_serial_enable_ms(struct uart_port *port)
{
}
-static inline struct s3c24xx_uart_info *s3c24xx_port_to_info(struct uart_port *port)
-{
- return to_ourport(port)->info;
-}
-
-static inline struct s3c2410_uartcfg *s3c24xx_port_to_cfg(struct uart_port *port)
-{
- if (port->dev == NULL)
- return NULL;
-
- return (struct s3c2410_uartcfg *)port->dev->platform_data;
-}
static int s3c24xx_serial_rx_fifocnt(struct s3c24xx_uart_port *ourport,
unsigned long ufstat)
@@ -186,6 +437,99 @@ static int s3c24xx_serial_rx_fifocnt(struct s3c24xx_uart_port *ourport,
return (ufstat & info->rx_fifomask) >> info->rx_fifoshift;
}
+static inline int
+s3c24xx_serial_getsource(struct uart_port *port, struct s3c24xx_uart_clksrc *c)
+{
+ struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
+
+ return (info->get_clksrc)(port, c);
+}
+
+static inline int
+s3c24xx_serial_setsource(struct uart_port *port, struct s3c24xx_uart_clksrc *c)
+{
+ struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
+
+ return (info->set_clksrc)(port, c);
+}
+
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+static void
+samsung_uart_get_options(struct uart_port *port, int *baud,
+ int *parity, int *stop, int *bits)
+{
+ struct s3c24xx_uart_clksrc clksrc;
+ struct clk *clk;
+ unsigned int ulcon;
+ unsigned int ucon;
+ unsigned int ubrdiv;
+ unsigned long rate;
+
+ ulcon = rd_regl(port, S3C2410_ULCON);
+ ucon = rd_regl(port, S3C2410_UCON);
+ ubrdiv = rd_regl(port, S3C2410_UBRDIV);
+
+ dbg("s3c24xx_serial_get_options: port=%p\n"
+ "registers: ulcon=%08x, ucon=%08x, ubdriv=%08x\n",
+ port, ulcon, ucon, ubrdiv);
+
+ if ((ucon & 0xf) != 0) {
+ /* consider the serial port configured if the tx/rx mode set */
+
+ switch (ulcon & S3C2410_LCON_CSMASK) {
+ case S3C2410_LCON_CS5:
+ *bits = 5;
+ break;
+ case S3C2410_LCON_CS6:
+ *bits = 6;
+ break;
+ case S3C2410_LCON_CS7:
+ *bits = 7;
+ break;
+ default:
+ case S3C2410_LCON_CS8:
+ *bits = 8;
+ break;
+ }
+
+ switch (ulcon & S3C2410_LCON_PMASK) {
+ case S3C2410_LCON_PEVEN:
+ *parity = 'e';
+ break;
+
+ case S3C2410_LCON_PODD:
+ *parity = 'o';
+ break;
+
+ case S3C2410_LCON_PNONE:
+ default:
+ *parity = 'n';
+ }
+
+ if (ulcon | S3C2410_LCON_STOPB) {
+ *stop = 2;
+ } else {
+ *stop = 1;
+ }
+
+ /* now calculate the baud rate */
+
+ s3c24xx_serial_getsource(port, &clksrc);
+
+ clk = clk_get(port->dev, clksrc.name);
+ if (!IS_ERR(clk) && clk != NULL)
+ rate = clk_get_rate(clk) / clksrc.divisor;
+ else
+ rate = 1;
+
+
+ *baud = rate / (16 * (ubrdiv + 1));
+ dbg("calculated baud %d\n", *baud);
+ }
+
+}
+#endif /* CONFIG_SAMSUNG_HAS_RS485 */
+
/* ? - where has parity gone?? */
#define S3C2410_UERSTAT_PARITY (0x1000)
@@ -209,6 +553,33 @@ s3c24xx_serial_rx_chars(int irq, void *dev_id)
uerstat = rd_regl(port, S3C2410_UERSTAT);
ch = rd_regb(port, S3C2410_URXH);
+ if (ourport->rs485.flags & SER_RS485_ENABLED) {
+ struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
+
+#ifdef CONFIG_TEST_485
+ /* Is the GPIO valid for the RS485 receive enable*/
+ if (cfg->gpio_receive_en > -1) {
+ /* Request, Set, Free the receive GPIO*/
+ gpio_set_value(cfg->gpio_receive_en, 1);
+ gpio_set_value(cfg->gpio_receive_en, 0);
+ }
+#endif
+
+ if ((SER_RS485_TOGGLE_ON_TOKEN & ourport->rs485.flags) &&
+ (ourport->rs485.toggle_token == ch)) {
+ /* Is the GPIO valid for RS485
+ * transmit enable*/
+ if (cfg->gpio_transmit_en > -1) {
+ /* Set the transmit GPIO line*/
+
+ gpio_set_value(cfg->gpio_transmit_en, 0);
+
+ }
+
+ s3c24xx_serial_rx_fifo_enable(port, 1);
+ }
+ }
+
if (port->flags & UPF_CONS_FLOW) {
int txe = s3c24xx_serial_txempty_nofifo(port);
@@ -488,21 +859,7 @@ static struct s3c24xx_uart_clksrc tmp_clksrc = {
.divisor = 1,
};
-static inline int
-s3c24xx_serial_getsource(struct uart_port *port, struct s3c24xx_uart_clksrc *c)
-{
- struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
-
- return (info->get_clksrc)(port, c);
-}
-static inline int
-s3c24xx_serial_setsource(struct uart_port *port, struct s3c24xx_uart_clksrc *c)
-{
- struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
-
- return (info->set_clksrc)(port, c);
-}
struct baud_calc {
struct s3c24xx_uart_clksrc *clksrc;
@@ -512,6 +869,41 @@ struct baud_calc {
struct clk *src;
};
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+/* Calculate the char_time depending on baudrate, number of bits etc. */
+static void update_char_time(struct uart_port *port)
+{
+
+ int bits = 8;
+ int baud = 9600;
+ int parity = 'n';
+ int stop = 1;
+
+ samsung_uart_get_options(port, &baud, &parity, &stop, &bits);
+
+ /* calc. number of bits / data byte */
+ /* databits + startbit and 1 stopbit */
+ bits++;
+
+ /* 2 stopbits ? */
+ bits += stop;
+
+ /* is parity enabled. */
+ if ('n' != parity) {
+ bits++;
+ }
+
+#ifdef CONFIG_SAMSUNG_485_LOW_RES_TIMER
+ /* calc timeout */
+ to_ourport(port)->char_time_usec = ((1000000 / baud) * bits) + 1;
+#else
+ /* calc timeout */
+ to_ourport(port)->char_time_nanosec = ((1000000000 / baud) * bits) + 1;
+#endif
+}
+
+#endif /*CONFIG_SAMSUNG_HAS_RS485 */
+
static int s3c24xx_serial_calcbaud(struct baud_calc *calc,
struct uart_port *port,
struct s3c24xx_uart_clksrc *clksrc,
@@ -785,7 +1177,7 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
port->ignore_status_mask = 0;
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= S3C2410_UERSTAT_OVERRUN;
- if (termios->c_iflag & IGNBRK && termios->c_iflag & IGNPAR)
+ if ((termios->c_iflag & IGNBRK) && (termios->c_iflag & IGNPAR))
port->ignore_status_mask |= S3C2410_UERSTAT_FRAME;
/*
@@ -795,6 +1187,12 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
port->ignore_status_mask |= RXSTAT_DUMMY_READ;
spin_unlock_irqrestore(&port->lock, flags);
+
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+ /* Update character time. */
+ update_char_time(port);
+#endif /* CONFIG_SAMSUNG_HAS_RS485 */
+
}
static const char *s3c24xx_serial_type(struct uart_port *port)
@@ -830,7 +1228,7 @@ static void s3c24xx_serial_config_port(struct uart_port *port, int flags)
{
struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
- if (flags & UART_CONFIG_TYPE &&
+ if ((flags & UART_CONFIG_TYPE) &&
s3c24xx_serial_request_port(port) == 0)
port->type = info->type;
}
@@ -849,6 +1247,73 @@ s3c24xx_serial_verify_port(struct uart_port *port, struct serial_struct *ser)
return 0;
}
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+/*
+ * Enable RS-485 called by IOCTL.
+ */
+static int
+s3c24xx_serial_enable_rs485(struct uart_port *port, struct serial_rs485 *r)
+{
+ struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
+ struct s3c24xx_uart_port *ourport = to_ourport(port);
+
+ /* Is GPIO valid for transmit enable. */
+ if (cfg->gpio_transmit_en > -1) {
+ /* GPIO Request, Config, Direction, Value, and Free the pin*/
+ gpio_set_value(cfg->gpio_transmit_en, 0);
+ }
+
+ /* Is GPIO valid for receive enable. */
+ if (cfg->gpio_receive_en > -1) {
+ /* GPIO Request, Config, Direction, Value, and Free the pin*/
+ gpio_set_value(cfg->gpio_receive_en, 0);
+ }
+
+ ourport->rs485 = *r;
+
+ /* Maximum delay before RTS equal to 1000 */
+ if (ourport->rs485.delay_rts_before_send >= 1000)
+ ourport->rs485.delay_rts_before_send = 1000;
+
+#if 0
+ dev_info(port., "rts: on send = %i, after = %i, enabled = %i",
+ info->rs485.rts_on_send,
+ info->rs485.rts_after_sent,
+ info->rs485.enabled
+ );
+#endif
+
+ return 0;
+}
+
+
+static int s3c24xx_serial_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg)
+{
+
+ struct serial_rs485 rs485conf;
+
+ switch (cmd) {
+ case TIOCSRS485:
+ if (copy_from_user(&rs485conf, (struct serial_rs485 *) arg,
+ sizeof(rs485conf)))
+ return -EFAULT;
+
+ s3c24xx_serial_enable_rs485(port, &rs485conf);
+ break;
+
+ case TIOCGRS485:
+ if (copy_to_user((struct serial_rs485 *) arg,
+ &(to_ourport(port)->rs485),
+ sizeof(rs485conf)))
+ return -EFAULT;
+ break;
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+#endif /*CONFIG_SAMSUNG_HAS_RS485*/
#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE
@@ -877,6 +1342,9 @@ static struct uart_ops s3c24xx_serial_ops = {
.request_port = s3c24xx_serial_request_port,
.config_port = s3c24xx_serial_config_port,
.verify_port = s3c24xx_serial_verify_port,
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+ .ioctl = s3c24xx_serial_ioctl,
+#endif /* CONFIG_SAMSUNG_HAS_RS485 */
};
@@ -955,9 +1423,16 @@ static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS
static inline int s3c24xx_serial_resetport(struct uart_port *port,
struct s3c2410_uartcfg *cfg)
{
+ int ret;
struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
- return (info->reset_port)(port, cfg);
+ ret = (info->reset_port)(port, cfg);
+
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+ update_char_time(port);
+#endif /* CONFIG_SAMSUNG_HAS_RS485 */
+
+ return ret;
}
@@ -1077,6 +1552,42 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
port->dev = &platdev->dev;
ourport->info = info;
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+
+ dev_info(port->dev, "port TX GPIO (%d)\n", cfg->gpio_transmit_en);
+ dev_info(port->dev, "port TX GPIO (%d)\n", cfg->gpio_receive_en);
+
+ if (cfg->gpio_transmit_en > -1) {
+ /* Setup 485 as default on capable ports.*/
+ ourport->rs485.flags = (SER_RS485_ENABLED | SER_RS485_ALWAYS_LISTEN |
+ (cfg->enable_token ? SER_RS485_TOGGLE_ON_TOKEN : 0));
+ ourport->rs485.toggle_token = cfg->token;
+
+#ifdef CONFIG_SAMSUNG_485_LOW_RES_TIMER
+ dev_info(&(port->dev), "Enable Lo Res Timer\n");
+ setup_timer(&(ourport->rs485_tx_timer),
+ rs485_toggle_rts_timer_function,
+ (unsigned long)port);
+#else
+ dev_info(port->dev, "Enable Hi Res Timer\n");
+
+ /* Initialize HR timer to relative and monotonic mode. */
+ hrtimer_init(&(ourport->hr_rs485_tx_timer),
+ CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+
+ /* register Callback to appropriate UART */
+ ourport->hr_rs485_tx_timer.function =
+ callback_list[ourport->port.line];
+
+#endif
+
+ dev_info(port->dev, "Port (%d) 485 Enabled\n", ourport->port.line);
+ } else {
+ /* disable 485 on ports inacable of mode. */
+ ourport->rs485.flags = 0;
+ }
+#endif /* CONFIG_SAMSUNG_HAS_RS485*/
+
/* copy the info in from provided structure */
ourport->port.fifosize = info->fifosize;
@@ -1137,6 +1648,55 @@ static ssize_t s3c24xx_serial_show_clksrc(struct device *dev,
static DEVICE_ATTR(clock_source, S_IRUGO, s3c24xx_serial_show_clksrc, NULL);
+
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+
+static ssize_t s3c24xx_serial_show_485_status(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret = 0;
+ struct uart_port *port = s3c24xx_dev_to_port(dev);
+ struct s3c24xx_uart_port *ourport = to_ourport(port);
+
+ if (ourport->rs485.flags & SER_RS485_ENABLED) {
+ ret = snprintf(buf, PAGE_SIZE, "[Enabled] Disabled\n");
+ } else {
+ ret = snprintf(buf, PAGE_SIZE, "Enabled [Disabled]\n");
+ }
+
+ return ret;
+}
+
+static ssize_t s3c24xx_serial_set_485_mode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+
+{
+ struct uart_port *port = s3c24xx_dev_to_port(dev);
+ struct s3c24xx_uart_port *ourport = to_ourport(port);
+
+ if (!strncmp(buf, "Enabled", 7)) {
+ ourport->rs485.flags |= SER_RS485_ENABLED;
+ } else if (!strncmp(buf, "Disabled", 8)) {
+ ourport->rs485.flags &= ~SER_RS485_ENABLED;
+ } else {
+ dev_err(port->dev, "unknown string\n");
+
+ return -EINVAL;
+ }
+
+ return count;
+
+}
+
+static DEVICE_ATTR(485_status,
+ S_IRUGO | S_IWUSR,
+ s3c24xx_serial_show_485_status,
+ s3c24xx_serial_set_485_mode);
+
+#endif
+
/* Device driver serial port probe */
static int probe_index;
@@ -1144,8 +1704,10 @@ static int probe_index;
int s3c24xx_serial_probe(struct platform_device *dev,
struct s3c24xx_uart_info *info)
{
- struct s3c24xx_uart_port *ourport;
int ret;
+ struct s3c24xx_uart_port *ourport;
+ struct s3c2410_uartcfg *cfg = s3c24xx_dev_to_cfg(&dev->dev);
+
dbg("s3c24xx_serial_probe(%p, %p) %d\n", dev, info, probe_index);
@@ -1170,6 +1732,33 @@ int s3c24xx_serial_probe(struct platform_device *dev,
if (ret < 0)
dev_err(&dev->dev, "failed to add cpufreq notifier\n");
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+
+ ret = device_create_file(&dev->dev, &dev_attr_485_status);
+ if (ret < 0)
+ printk(KERN_ERR "%s: failed to add 485 status attr.\n", __func__);
+
+
+ if (cfg->gpio_transmit_en > -1) {
+ WARN_ON(gpio_request(cfg->gpio_transmit_en, "RS485TX"));
+ WARN_ON(s3c_gpio_cfgpin(cfg->gpio_transmit_en, S3C_GPIO_OUTPUT));
+ gpio_direction_output(cfg->gpio_transmit_en, 0);
+ gpio_set_value(cfg->gpio_transmit_en, 0);
+
+ dev_info(ourport->port.dev, "Initialize TX(%d) GPIO\n", ourport->port.line);
+
+ if (cfg->gpio_receive_en > -1) {
+ WARN_ON(gpio_request(cfg->gpio_receive_en , "RS485RX"));
+ WARN_ON(s3c_gpio_cfgpin(cfg->gpio_receive_en, S3C_GPIO_OUTPUT));
+ gpio_direction_output(cfg->gpio_receive_en, 0);
+ gpio_set_value(cfg->gpio_receive_en, 0);
+
+ dev_info(ourport->port.dev, "Initialize RX(%d) GPIO\n", ourport->port.line);
+ }
+ }
+#endif
+
+
return 0;
probe_err:
@@ -1181,8 +1770,33 @@ EXPORT_SYMBOL_GPL(s3c24xx_serial_probe);
int __devexit s3c24xx_serial_remove(struct platform_device *dev)
{
struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
+ struct s3c2410_uartcfg *cfg = s3c24xx_dev_to_cfg(&dev->dev);
if (port) {
+
+#ifdef CONFIG_SAMSUNG_HAS_RS485
+ if (cfg->gpio_transmit_en > -1) {
+ gpio_free(cfg->gpio_transmit_en);
+
+ dev_info(port->dev,
+ "Uninitialize TX(%d) GPIO\n", port->line);
+
+ if (cfg->gpio_receive_en > -1) {
+ gpio_free(cfg->gpio_receive_en);
+
+ dev_info(port->dev,
+ "Uninitialize RX(%d) GPIO\n",
+ port->line);
+ }
+ }
+
+ /* Delete timer after device is removed. */
+#ifdef CONFIG_SAMSUNG_485_LOW_RES_TIMER
+ del_timer_sync(&(to_ourport(port)->rs485_tx_timer));
+#else
+ hrtimer_cancel(&(to_ourport(port)->hr_rs485_tx_timer));
+#endif
+#endif /* CONFIG_SAMSUNG_HAS_RS485 */
s3c24xx_serial_cpufreq_deregister(to_ourport(port));
device_remove_file(&dev->dev, &dev_attr_clock_source);
uart_remove_one_port(&s3c24xx_uart_drv, port);
@@ -1308,9 +1922,33 @@ s3c24xx_serial_console_write(struct console *co, const char *s,
uart_console_write(cons_uart, s, count, s3c24xx_serial_console_putchar);
}
+
+/* s3c24xx_serial_init_ports
+ *
+ * initialise the serial ports from the machine provided initialisation
+ * data.
+*/
+
+static int s3c24xx_serial_init_ports(struct s3c24xx_uart_info **info)
+{
+ struct s3c24xx_uart_port *ptr = s3c24xx_serial_ports;
+ struct platform_device **platdev_ptr;
+ int i;
+
+ dbg("s3c24xx_serial_init_ports: initialising ports...\n");
+
+ platdev_ptr = s3c24xx_uart_devs;
+
+ for (i = 0; i < CONFIG_SERIAL_SAMSUNG_UARTS; i++, ptr++, platdev_ptr++) {
+ s3c24xx_serial_init_port(ptr, info[i], *platdev_ptr);
+ }
+
+ return 0;
+}
+
static void __init
s3c24xx_serial_get_options(struct uart_port *port, int *baud,
- int *parity, int *bits)
+ int *parity, int *stop, int *bits)
{
struct s3c24xx_uart_clksrc clksrc;
struct clk *clk;
@@ -1360,6 +1998,12 @@ s3c24xx_serial_get_options(struct uart_port *port, int *baud,
*parity = 'n';
}
+ if (ulcon | S3C2410_LCON_STOPB) {
+ *stop = 2;
+ } else {
+ *stop = 1;
+ }
+
/* now calculate the baud rate */
s3c24xx_serial_getsource(port, &clksrc);
@@ -1377,29 +2021,6 @@ s3c24xx_serial_get_options(struct uart_port *port, int *baud,
}
-/* s3c24xx_serial_init_ports
- *
- * initialise the serial ports from the machine provided initialisation
- * data.
-*/
-
-static int s3c24xx_serial_init_ports(struct s3c24xx_uart_info **info)
-{
- struct s3c24xx_uart_port *ptr = s3c24xx_serial_ports;
- struct platform_device **platdev_ptr;
- int i;
-
- dbg("s3c24xx_serial_init_ports: initialising ports...\n");
-
- platdev_ptr = s3c24xx_uart_devs;
-
- for (i = 0; i < CONFIG_SERIAL_SAMSUNG_UARTS; i++, ptr++, platdev_ptr++) {
- s3c24xx_serial_init_port(ptr, info[i], *platdev_ptr);
- }
-
- return 0;
-}
-
static int __init
s3c24xx_serial_console_setup(struct console *co, char *options)
{
@@ -1408,6 +2029,7 @@ s3c24xx_serial_console_setup(struct console *co, char *options)
int bits = 8;
int parity = 'n';
int flow = 'n';
+ int stop = 1;
dbg("s3c24xx_serial_console_setup: co=%p (%d), %s\n",
co, co->index, options);
@@ -1436,7 +2058,7 @@ s3c24xx_serial_console_setup(struct console *co, char *options)
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
else
- s3c24xx_serial_get_options(port, &baud, &parity, &bits);
+ s3c24xx_serial_get_options(port, &baud, &parity, &stop, &bits);
dbg("s3c24xx_serial_console_setup: baud %d\n", baud);
diff --git a/drivers/tty/serial/samsung.h b/drivers/tty/serial/samsung.h
index a69d9a5..f550dc3 100644
--- a/drivers/tty/serial/samsung.h
+++ b/drivers/tty/serial/samsung.h
@@ -4,6 +4,10 @@
* Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
* http://armlinux.simtec.co.uk/
*
+ * Paul Schilling, Copyright (c) 2011 Ecolab Corp.
+ * Added RS-485 support to the Samsung driver..
+ *
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
@@ -31,6 +35,7 @@ struct s3c24xx_uart_info {
/* uart controls */
int (*reset_port)(struct uart_port *, struct s3c2410_uartcfg *);
+
};
struct s3c24xx_uart_port {
@@ -48,6 +53,16 @@ struct s3c24xx_uart_port {
struct clk *baudclk;
struct uart_port port;
+ struct serial_rs485 rs485; /* RS-485 support */
+
+#ifdef CONFIG_SAMSUNG_485_LOW_RES_TIMER
+ unsigned long char_time_usec; /* The time for 1 char, in micro secs */
+ struct timer_list rs485_tx_timer;
+#else
+ unsigned long char_time_nanosec; /* The time for 1 char, in nano secs */
+ struct hrtimer hr_rs485_tx_timer; /* Timer for RS-485 Receive enable*/
+#endif
+
#ifdef CONFIG_CPU_FREQ
struct notifier_block freq_transition;
#endif
diff --git a/include/linux/serial.h b/include/linux/serial.h
index ef91406..826b1c0 100644
--- a/include/linux/serial.h
+++ b/include/linux/serial.h
@@ -211,9 +211,12 @@ struct serial_rs485 {
#define SER_RS485_RTS_ON_SEND (1 << 1)
#define SER_RS485_RTS_AFTER_SEND (1 << 2)
#define SER_RS485_RTS_BEFORE_SEND (1 << 3)
+#define SER_RS485_ALWAYS_LISTEN (1 << 4)
+#define SER_RS485_TOGGLE_ON_TOKEN (1 << 5)
__u32 delay_rts_before_send; /* Milliseconds */
__u32 delay_rts_after_send; /* Milliseconds */
- __u32 padding[5]; /* Memory is cheap, new structs
+ __u32 toggle_token; /* Token used to toggle to receive */
+ __u32 padding[4]; /* Memory is cheap, new structs
are a royal PITA .. */
};
--
1.7.6.4
^ permalink raw reply related
* Re: [PATCH 1/2] LSM: Do not apply mmap_min_addr check to PROT_NONE mappings
From: Linus Torvalds @ 2011-10-22 3:38 UTC (permalink / raw)
To: Roland McGrath
Cc: Andrew Morton, James Morris, Eric Paris, Stephen Smalley, selinux,
John Johansen, linux-security-module, linux-kernel
In-Reply-To: <20111021213916.914462C0A5@topped-with-meat.com>
So I'm not against this, but I'm wondering what triggers the need for it?
It does make the security checks more complicated, since now
mprotect() suddenly has to care about mmap_min_addr. So I don't think
it's a security enhancement ("attempt to ensure robustness").
But if there is some actual use-case that is shown to be helped,
please document that n the explanations for the changeset.
Linus
On Sat, Oct 22, 2011 at 12:39 AM, Roland McGrath <roland@hack.frob.com> wrote:
> An mmap with PROT_NONE is done specifically to ensure that an address will
> fault. So doing this on addresses below mmap_min_addr is not seeking a
> "dangerous" operation. Conversely, it's an attempt to ensure robustness in
> case mmap_min_addr is less restrictive than the user wants to be.
>
> Since we might let a low mapping exist at all without a check, we add
> another check to prevent mprotect from granting access to such a mapping.
>
> Signed-off-by: Roland McGrath <roland@hack.frob.com>
> ---
> include/linux/security.h | 5 ++-
> security/apparmor/lsm.c | 7 ++++++
> security/capability.c | 6 -----
> security/commoncap.c | 48 ++++++++++++++++++++++++++++++++++++---------
> security/selinux/hooks.c | 8 ++++++-
> 5 files changed, 55 insertions(+), 19 deletions(-)
>
> diff --git a/include/linux/security.h b/include/linux/security.h
> index ebd2a53..aba8071 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -73,6 +73,8 @@ extern int cap_inode_killpriv(struct dentry *dentry);
> extern int cap_file_mmap(struct file *file, unsigned long reqprot,
> unsigned long prot, unsigned long flags,
> unsigned long addr, unsigned long addr_only);
> +extern int cap_file_mprotect(struct vm_area_struct *vma,
> + unsigned long reqprot, unsigned long prot);
> extern int cap_task_fix_setuid(struct cred *new, const struct cred *old, int flags);
> extern int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
> unsigned long arg4, unsigned long arg5);
> @@ -2213,7 +2215,7 @@ static inline int security_file_mprotect(struct vm_area_struct *vma,
> unsigned long reqprot,
> unsigned long prot)
> {
> - return 0;
> + return cap_file_mprotect(vma, reqprot, prot);
> }
>
> static inline int security_file_lock(struct file *file, unsigned int cmd)
> @@ -3044,4 +3046,3 @@ static inline void free_secdata(void *secdata)
> #endif /* CONFIG_SECURITY */
>
> #endif /* ! __LINUX_SECURITY_H */
> -
> diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
> index 3783202..d2a9693 100644
> --- a/security/apparmor/lsm.c
> +++ b/security/apparmor/lsm.c
> @@ -508,6 +508,13 @@ static int apparmor_file_mmap(struct file *file, unsigned long reqprot,
> static int apparmor_file_mprotect(struct vm_area_struct *vma,
> unsigned long reqprot, unsigned long prot)
> {
> + int rc;
> +
> + /* do DAC check */
> + rc = cap_file_mprotect(vma, reqprot, prot);
> + if (rc)
> + return rc;
> +
> return common_mmap(OP_FMPROT, vma->vm_file, prot,
> !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0);
> }
> diff --git a/security/capability.c b/security/capability.c
> index 2984ea4..3c60f07 100644
> --- a/security/capability.c
> +++ b/security/capability.c
> @@ -316,12 +316,6 @@ static int cap_file_ioctl(struct file *file, unsigned int command,
> return 0;
> }
>
> -static int cap_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
> - unsigned long prot)
> -{
> - return 0;
> -}
> -
> static int cap_file_lock(struct file *file, unsigned int cmd)
> {
> return 0;
> diff --git a/security/commoncap.c b/security/commoncap.c
> index a93b3b7..0d4685a 100644
> --- a/security/commoncap.c
> +++ b/security/commoncap.c
> @@ -942,11 +942,26 @@ int cap_vm_enough_memory(struct mm_struct *mm, long pages)
> return __vm_enough_memory(mm, pages, cap_sys_admin);
> }
>
> +static int cap_mmap_min_addr(unsigned long addr)
> +{
> + int ret = 0;
> +
> + if (addr < dac_mmap_min_addr) {
> + ret = cap_capable(current, current_cred(), &init_user_ns,
> + CAP_SYS_RAWIO, SECURITY_CAP_AUDIT);
> + /* set PF_SUPERPRIV if it turns out we allow the low mmap */
> + if (ret == 0)
> + current->flags |= PF_SUPERPRIV;
> + }
> +
> + return ret;
> +}
> +
> /*
> * cap_file_mmap - check if able to map given addr
> * @file: unused
> * @reqprot: unused
> - * @prot: unused
> + * @prot: protection being requested
> * @flags: unused
> * @addr: address attempting to be mapped
> * @addr_only: unused
> @@ -960,14 +975,27 @@ int cap_file_mmap(struct file *file, unsigned long reqprot,
> unsigned long prot, unsigned long flags,
> unsigned long addr, unsigned long addr_only)
> {
> - int ret = 0;
> + if (addr_only || prot != PROT_NONE)
> + return cap_mmap_min_addr(addr);
> + return 0;
> +}
>
> - if (addr < dac_mmap_min_addr) {
> - ret = cap_capable(current, current_cred(), &init_user_ns, CAP_SYS_RAWIO,
> - SECURITY_CAP_AUDIT);
> - /* set PF_SUPERPRIV if it turns out we allow the low mmap */
> - if (ret == 0)
> - current->flags |= PF_SUPERPRIV;
> - }
> - return ret;
> +/*
> + * cap_file_mprotect - check if able to mprotect given addr
> + * @vma: entry being changed
> + * @reqprot: unused
> + * @prot: protection being changed to
> + *
> + * If the process is attempting to change memory below dac_mmap_min_addr to
> + * anything but PROT_NONE, they need CAP_SYS_RAWIO. The other parameters
> + * to this function are unused by the capability security module. Returns
> + * 0 if this mapping should be allowed -EPERM if not.
> + */
> +int cap_file_mprotect(struct vm_area_struct *vma,
> + unsigned long reqprot,
> + unsigned long prot)
> +{
> + if (prot != PROT_NONE)
> + return cap_mmap_min_addr(vma->vm_start);
> + return 0;
> }
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index 266a229..76e6f04 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -3086,13 +3086,19 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
> unsigned long prot)
> {
> const struct cred *cred = current_cred();
> + int rc;
>
> if (selinux_checkreqprot)
> prot = reqprot;
>
> + /* do DAC check on address space usage */
> + rc = cap_file_mprotect(vma, reqprot, prot)
> + if (rc)
> + return rc;
> +
> if (default_noexec &&
> (prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) {
> - int rc = 0;
> + rc = 0;
> if (vma->vm_start >= vma->vm_mm->start_brk &&
> vma->vm_end <= vma->vm_mm->brk) {
> rc = cred_has_perm(cred, cred, PROCESS__EXECHEAP);
>
^ permalink raw reply
* [PATCH 01/14] ATA : vortex86 : fix vortex86dx/sx hardware CRC bug.
From: Paul Schilling @ 2011-10-22 3:34 UTC (permalink / raw)
To: Jeff Garzik, David S. Miller, Jesse Barnes, linux-ide,
linux-kernel, linux-pci
Cc: Paul Schilling, Paul Schilling
In-Reply-To: <Vortex86_PATA>
This fixes a DMA issue related to a CRC bug on
the RDC pata peripherial found on the vortex86sx and vortex86dx.
Signed-off-by: Paul Schilling <paul.s.schilling@gmail.com>
---
drivers/ata/pata_it821x.c | 264 +++++++++++++++++++++++---------------------
drivers/ata/pata_rdc.c | 35 +++++--
drivers/ide/it821x.c | 9 ++-
include/linux/pci_ids.h | 2 +
4 files changed, 174 insertions(+), 136 deletions(-)
diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c
index 62c5d00..eaf9c1e 100644
--- a/drivers/ata/pata_it821x.c
+++ b/drivers/ata/pata_it821x.c
@@ -1,5 +1,5 @@
/*
- * pata_it821x.c - IT821x PATA for new ATA layer
+ * pata_it821x.c - IT821x PATA for new ATA layer
* (C) 2005 Red Hat Inc
* Alan Cox <alan@lxorguk.ukuu.org.uk>
* (C) 2007 Bartlomiej Zolnierkiewicz
@@ -16,7 +16,7 @@
* Based in part on the ITE vendor provided SCSI driver.
*
* Documentation available from IT8212F_V04.pdf
- * http://www.ite.com.tw/EN/products_more.aspx?CategoryID=3&ID=5,91
+ * http://www.ite.com.tw/EN/products_more.aspx?CategoryID=3&ID=5,91
* Some other documents are NDA.
*
* The ITE8212 isn't exactly a standard IDE controller. It has two
@@ -79,22 +79,20 @@
#include <scsi/scsi_host.h>
#include <linux/libata.h>
-
#define DRV_NAME "pata_it821x"
#define DRV_VERSION "0.4.2"
-struct it821x_dev
-{
- unsigned int smart:1, /* Are we in smart raid mode */
- timing10:1; /* Rev 0x10 */
- u8 clock_mode; /* 0, ATA_50 or ATA_66 */
- u8 want[2][2]; /* Mode/Pri log for master slave */
+struct it821x_dev {
+ unsigned int smart:1, /* Are we in smart raid mode */
+ timing10:1; /* Rev 0x10 */
+ u8 clock_mode; /* 0, ATA_50 or ATA_66 */
+ u8 want[2][2]; /* Mode/Pri log for master slave */
/* We need these for switching the clock when DMA goes on/off
The high byte is the 66Mhz timing */
- u16 pio[2]; /* Cached PIO values */
- u16 mwdma[2]; /* Cached MWDMA values */
- u16 udma[2]; /* Cached UDMA values (per drive) */
- u16 last_device; /* Master or slave loaded ? */
+ u16 pio[2]; /* Cached PIO values */
+ u16 mwdma[2]; /* Cached MWDMA values */
+ u16 udma[2]; /* Cached UDMA values (per drive) */
+ u16 last_device; /* Master or slave loaded ? */
};
#define ATA_66 0
@@ -124,7 +122,8 @@ static int it8212_noraid;
* the DMA start/stop sequence as with the old driver.
*/
-static void it821x_program(struct ata_port *ap, struct ata_device *adev, u16 timing)
+static void it821x_program(struct ata_port *ap, struct ata_device *adev,
+ u16 timing)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
struct it821x_dev *itdev = ap->private_data;
@@ -139,7 +138,6 @@ static void it821x_program(struct ata_port *ap, struct ata_device *adev, u16 tim
pci_write_config_byte(pdev, 0x54 + 4 * channel, conf);
}
-
/**
* it821x_program_udma - program the UDMA registers
* @ap: ATA port
@@ -152,7 +150,8 @@ static void it821x_program(struct ata_port *ap, struct ata_device *adev, u16 tim
* here and partly in start_dma.
*/
-static void it821x_program_udma(struct ata_port *ap, struct ata_device *adev, u16 timing)
+static void it821x_program_udma(struct ata_port *ap, struct ata_device *adev,
+ u16 timing)
{
struct it821x_dev *itdev = ap->private_data;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
@@ -227,16 +226,16 @@ static void it821x_clock_strategy(struct ata_port *ap, struct ata_device *adev)
pci_write_config_byte(pdev, 0x50, v);
/*
- * Reprogram the UDMA/PIO of the pair drive for the switch
- * MWDMA will be dealt with by the dma switcher
+ * Reprogram the UDMA/PIO of the pair drive for the switch
+ * MWDMA will be dealt with by the dma switcher
*/
- if (pair && itdev->udma[1-unit] != UDMA_OFF) {
- it821x_program_udma(ap, pair, itdev->udma[1-unit]);
- it821x_program(ap, pair, itdev->pio[1-unit]);
+ if (pair && itdev->udma[1 - unit] != UDMA_OFF) {
+ it821x_program_udma(ap, pair, itdev->udma[1 - unit]);
+ it821x_program(ap, pair, itdev->pio[1 - unit]);
}
/*
- * Reprogram the UDMA/PIO of our drive for the switch.
- * MWDMA will be dealt with by the dma switcher
+ * Reprogram the UDMA/PIO of our drive for the switch.
+ * MWDMA will be dealt with by the dma switcher
*/
if (itdev->udma[unit] != UDMA_OFF) {
it821x_program_udma(ap, adev, itdev->udma[unit]);
@@ -253,11 +252,13 @@ static void it821x_clock_strategy(struct ata_port *ap, struct ata_device *adev)
* shared by PIO and MWDMA and for both channels.
*/
-static void it821x_passthru_set_piomode(struct ata_port *ap, struct ata_device *adev)
+static void it821x_passthru_set_piomode(struct ata_port *ap,
+ struct ata_device *adev)
{
/* Spec says 89 ref driver uses 88 */
- static const u16 pio[] = { 0xAA88, 0xA382, 0xA181, 0x3332, 0x3121 };
- static const u8 pio_want[] = { ATA_66, ATA_66, ATA_66, ATA_66, ATA_ANY };
+ static const u16 pio[] = { 0xAA88, 0xA382, 0xA181, 0x3332, 0x3121 };
+ static const u8 pio_want[] = {
+ ATA_66, ATA_66, ATA_66, ATA_66, ATA_ANY };
struct it821x_dev *itdev = ap->private_data;
int unit = adev->devno;
@@ -283,12 +284,17 @@ static void it821x_passthru_set_piomode(struct ata_port *ap, struct ata_device *
* we switch devices and mode.
*/
-static void it821x_passthru_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+static void it821x_passthru_set_dmamode(struct ata_port *ap,
+ struct ata_device *adev)
{
- static const u16 dma[] = { 0x8866, 0x3222, 0x3121 };
- static const u8 mwdma_want[] = { ATA_ANY, ATA_66, ATA_ANY };
- static const u16 udma[] = { 0x4433, 0x4231, 0x3121, 0x2121, 0x1111, 0x2211, 0x1111 };
- static const u8 udma_want[] = { ATA_ANY, ATA_50, ATA_ANY, ATA_66, ATA_66, ATA_50, ATA_66 };
+ static const u16 dma[] = { 0x8866, 0x3222, 0x3121 };
+ static const u8 mwdma_want[] = { ATA_ANY, ATA_66, ATA_ANY };
+ static const u16 udma[] = {
+ 0x4433, 0x4231, 0x3121,
+ 0x2121, 0x1111, 0x2211, 0x1111 };
+ static const u8 udma_want[] = {
+ ATA_ANY, ATA_50, ATA_ANY,
+ ATA_66, ATA_66, ATA_50, ATA_66 };
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
struct it821x_dev *itdev = ap->private_data;
@@ -309,9 +315,9 @@ static void it821x_passthru_set_dmamode(struct ata_port *ap, struct ata_device *
/* UDMA on. Again revision 0x10 must do the pair */
pci_read_config_byte(pdev, 0x50, &conf);
if (itdev->timing10)
- conf &= channel ? 0x9F: 0xE7;
+ conf &= channel ? 0x9F : 0xE7;
else
- conf &= ~ (1 << (3 + 2 * channel + unit));
+ conf &= ~(1 << (3 + 2 * channel + unit));
pci_write_config_byte(pdev, 0x50, conf);
it821x_clock_strategy(ap, adev);
it821x_program_udma(ap, adev, itdev->udma[unit]);
@@ -326,7 +332,7 @@ static void it821x_passthru_set_dmamode(struct ata_port *ap, struct ata_device *
/* UDMA bits off - Revision 0x10 do them in pairs */
pci_read_config_byte(pdev, 0x50, &conf);
if (itdev->timing10)
- conf |= channel ? 0x60: 0x18;
+ conf |= channel ? 0x60 : 0x18;
else
conf |= 1 << (3 + 2 * channel + unit);
pci_write_config_byte(pdev, 0x50, conf);
@@ -378,7 +384,6 @@ static void it821x_passthru_bmdma_stop(struct ata_queued_cmd *qc)
it821x_program(ap, adev, itdev->pio[unit]);
}
-
/**
* it821x_passthru_dev_select - Select master/slave
* @ap: ATA port
@@ -387,8 +392,7 @@ static void it821x_passthru_bmdma_stop(struct ata_queued_cmd *qc)
* Device selection hook. If necessary perform clock switching
*/
-static void it821x_passthru_dev_select(struct ata_port *ap,
- unsigned int device)
+static void it821x_passthru_dev_select(struct ata_port *ap, unsigned int device)
{
struct it821x_dev *itdev = ap->private_data;
if (itdev && device != itdev->last_device) {
@@ -410,29 +414,29 @@ static void it821x_passthru_dev_select(struct ata_port *ap,
static unsigned int it821x_smart_qc_issue(struct ata_queued_cmd *qc)
{
- switch(qc->tf.command)
- {
+ switch (qc->tf.command) {
/* Commands the firmware supports */
- case ATA_CMD_READ:
- case ATA_CMD_READ_EXT:
- case ATA_CMD_WRITE:
- case ATA_CMD_WRITE_EXT:
- case ATA_CMD_PIO_READ:
- case ATA_CMD_PIO_READ_EXT:
- case ATA_CMD_PIO_WRITE:
- case ATA_CMD_PIO_WRITE_EXT:
- case ATA_CMD_READ_MULTI:
- case ATA_CMD_READ_MULTI_EXT:
- case ATA_CMD_WRITE_MULTI:
- case ATA_CMD_WRITE_MULTI_EXT:
- case ATA_CMD_ID_ATA:
- case ATA_CMD_INIT_DEV_PARAMS:
- case 0xFC: /* Internal 'report rebuild state' */
+ case ATA_CMD_READ:
+ case ATA_CMD_READ_EXT:
+ case ATA_CMD_WRITE:
+ case ATA_CMD_WRITE_EXT:
+ case ATA_CMD_PIO_READ:
+ case ATA_CMD_PIO_READ_EXT:
+ case ATA_CMD_PIO_WRITE:
+ case ATA_CMD_PIO_WRITE_EXT:
+ case ATA_CMD_READ_MULTI:
+ case ATA_CMD_READ_MULTI_EXT:
+ case ATA_CMD_WRITE_MULTI:
+ case ATA_CMD_WRITE_MULTI_EXT:
+ case ATA_CMD_ID_ATA:
+ case ATA_CMD_INIT_DEV_PARAMS:
+ case 0xFC: /* Internal 'report rebuild state' */
/* Arguably should just no-op this one */
- case ATA_CMD_SET_FEATURES:
- return ata_bmdma_qc_issue(qc);
+ case ATA_CMD_SET_FEATURES:
+ return ata_bmdma_qc_issue(qc);
}
- printk(KERN_DEBUG "it821x: can't process command 0x%02X\n", qc->tf.command);
+ printk(KERN_DEBUG "it821x: can't process command 0x%02X\n",
+ qc->tf.command);
return AC_ERR_DEV;
}
@@ -462,7 +466,8 @@ static unsigned int it821x_passthru_qc_issue(struct ata_queued_cmd *qc)
* and respect them.
*/
-static int it821x_smart_set_mode(struct ata_link *link, struct ata_device **unused)
+static int it821x_smart_set_mode(struct ata_link *link,
+ struct ata_device **unused)
{
struct ata_device *dev;
@@ -509,8 +514,7 @@ static void it821x_dev_config(struct ata_device *adev)
if (strstr(model_num, "Integrated Technology Express")) {
/* RAID mode */
ata_dev_info(adev, "%sRAID%d volume",
- adev->id[147] ? "Bootable " : "",
- adev->id[129]);
+ adev->id[147] ? "Bootable " : "", adev->id[129]);
if (adev->id[129] != 1)
pr_cont("(%dK stripe)", adev->id[146]);
pr_cont("\n");
@@ -535,7 +539,7 @@ static void it821x_dev_config(struct ata_device *adev)
*/
static unsigned int it821x_read_id(struct ata_device *adev,
- struct ata_taskfile *tf, u16 *id)
+ struct ata_taskfile *tf, u16 * id)
{
unsigned int err_mask;
unsigned char model_num[ATA_ID_PROD_LEN + 1];
@@ -616,7 +620,7 @@ static void it821x_display_disk(int n, u8 *buf)
if (buf[52] > 4) /* No Disk */
return;
- ata_id_c_string((u16 *)buf, id, 0, 41);
+ ata_id_c_string((u16 *) buf, id, 0, 41);
if (buf[51]) {
mode = ffs(buf[51]);
@@ -635,10 +639,10 @@ static void it821x_display_disk(int n, u8 *buf)
strcpy(mbuf, "PIO");
if (buf[52] == 4)
printk(KERN_INFO "%d: %-6s %-8s %s %s\n",
- n, mbuf, types[buf[52]], id, cbl);
+ n, mbuf, types[buf[52]], id, cbl);
else
printk(KERN_INFO "%d: %-6s %-8s Volume: %1d %s %s\n",
- n, mbuf, types[buf[52]], buf[53], id, cbl);
+ n, mbuf, types[buf[52]], buf[53], id, cbl);
if (buf[125] < 100)
printk(KERN_INFO "%d: Rebuilding: %d%%\n", n, buf[125]);
}
@@ -673,7 +677,7 @@ static u8 *it821x_firmware_command(struct ata_port *ap, u8 cmd, int len)
udelay(1);
/* This should be almost immediate but a little paranoia goes a long
way. */
- while(n++ < 10) {
+ while (n++ < 10) {
status = ioread8(ap->ioaddr.status_addr);
if (status & ATA_ERR) {
kfree(buf);
@@ -681,8 +685,8 @@ static u8 *it821x_firmware_command(struct ata_port *ap, u8 cmd, int len)
return NULL;
}
if (status & ATA_DRQ) {
- ioread16_rep(ap->ioaddr.data_addr, buf, len/2);
- return (u8 *)buf;
+ ioread16_rep(ap->ioaddr.data_addr, buf, len / 2);
+ return (u8 *) buf;
}
mdelay(1);
}
@@ -711,18 +715,13 @@ static void it821x_probe_firmware(struct ata_port *ap)
if (buf != NULL) {
printk(KERN_INFO "pata_it821x: Firmware %02X/%02X/%02X%02X\n",
- buf[505],
- buf[506],
- buf[507],
- buf[508]);
+ buf[505], buf[506], buf[507], buf[508]);
for (i = 0; i < 4; i++)
- it821x_display_disk(i, buf + 128 * i);
+ it821x_display_disk(i, buf + 128 * i);
kfree(buf);
}
}
-
-
/**
* it821x_port_start - port setup
* @ap: ATA port being set up
@@ -772,7 +771,8 @@ static int it821x_port_start(struct ata_port *ap)
itdev->timing10 = 1;
/* Need to disable ATAPI DMA for this case */
if (!itdev->smart)
- printk(KERN_WARNING DRV_NAME": Revision 0x10, workarounds activated.\n");
+ printk(KERN_WARNING DRV_NAME
+ ": Revision 0x10, workarounds activated.\n");
}
return 0;
@@ -802,57 +802,57 @@ static struct scsi_host_template it821x_sht = {
};
static struct ata_port_operations it821x_smart_port_ops = {
- .inherits = &ata_bmdma_port_ops,
+ .inherits = &ata_bmdma_port_ops,
- .check_atapi_dma= it821x_check_atapi_dma,
- .qc_issue = it821x_smart_qc_issue,
+ .check_atapi_dma = it821x_check_atapi_dma,
+ .qc_issue = it821x_smart_qc_issue,
- .cable_detect = ata_cable_80wire,
- .set_mode = it821x_smart_set_mode,
- .dev_config = it821x_dev_config,
- .read_id = it821x_read_id,
+ .cable_detect = ata_cable_80wire,
+ .set_mode = it821x_smart_set_mode,
+ .dev_config = it821x_dev_config,
+ .read_id = it821x_read_id,
- .port_start = it821x_port_start,
+ .port_start = it821x_port_start,
};
static struct ata_port_operations it821x_passthru_port_ops = {
- .inherits = &ata_bmdma_port_ops,
+ .inherits = &ata_bmdma_port_ops,
- .check_atapi_dma= it821x_check_atapi_dma,
- .sff_dev_select = it821x_passthru_dev_select,
- .bmdma_start = it821x_passthru_bmdma_start,
- .bmdma_stop = it821x_passthru_bmdma_stop,
- .qc_issue = it821x_passthru_qc_issue,
+ .check_atapi_dma = it821x_check_atapi_dma,
+ .sff_dev_select = it821x_passthru_dev_select,
+ .bmdma_start = it821x_passthru_bmdma_start,
+ .bmdma_stop = it821x_passthru_bmdma_stop,
+ .qc_issue = it821x_passthru_qc_issue,
- .cable_detect = ata_cable_unknown,
- .set_piomode = it821x_passthru_set_piomode,
- .set_dmamode = it821x_passthru_set_dmamode,
+ .cable_detect = ata_cable_unknown,
+ .set_piomode = it821x_passthru_set_piomode,
+ .set_dmamode = it821x_passthru_set_dmamode,
- .port_start = it821x_port_start,
+ .port_start = it821x_port_start,
};
static struct ata_port_operations it821x_rdc_port_ops = {
- .inherits = &ata_bmdma_port_ops,
+ .inherits = &ata_bmdma_port_ops,
- .check_atapi_dma= it821x_check_atapi_dma,
- .sff_dev_select = it821x_passthru_dev_select,
- .bmdma_start = it821x_passthru_bmdma_start,
- .bmdma_stop = it821x_passthru_bmdma_stop,
- .qc_issue = it821x_passthru_qc_issue,
+ .check_atapi_dma = it821x_check_atapi_dma,
+ .sff_dev_select = it821x_passthru_dev_select,
+ .bmdma_start = it821x_passthru_bmdma_start,
+ .bmdma_stop = it821x_passthru_bmdma_stop,
+ .qc_issue = it821x_passthru_qc_issue,
- .cable_detect = it821x_rdc_cable,
- .set_piomode = it821x_passthru_set_piomode,
- .set_dmamode = it821x_passthru_set_dmamode,
+ .cable_detect = it821x_rdc_cable,
+ .set_piomode = it821x_passthru_set_piomode,
+ .set_dmamode = it821x_passthru_set_dmamode,
- .port_start = it821x_port_start,
+ .port_start = it821x_port_start,
};
static void it821x_disable_raid(struct pci_dev *pdev)
{
/* Neither the RDC nor the IT8211 */
if (pdev->vendor != PCI_VENDOR_ID_ITE ||
- pdev->device != PCI_DEVICE_ID_ITE_8212)
- return;
+ pdev->device != PCI_DEVICE_ID_ITE_8212)
+ return;
/* Reset local CPU, and set BIOS not ready */
pci_write_config_byte(pdev, 0x5E, 0x01);
@@ -864,12 +864,11 @@ static void it821x_disable_raid(struct pci_dev *pdev)
PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
pci_write_config_word(pdev, 0x40, 0xA0F3);
- pci_write_config_dword(pdev,0x4C, 0x02040204);
+ pci_write_config_dword(pdev, 0x4C, 0x02040204);
pci_write_config_byte(pdev, 0x42, 0x36);
pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x20);
}
-
static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
u8 conf;
@@ -898,7 +897,16 @@ static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
static const struct ata_port_info info_rdc_11 = {
.flags = ATA_FLAG_SLAVE_POSS,
.pio_mask = ATA_PIO4,
- .mwdma_mask = ATA_MWDMA2,
+ .mwdma_mask = 0,
+ .udma_mask = 0,
+ /* No UDMA */
+ .port_ops = &it821x_rdc_port_ops
+ };
+ static const struct ata_port_info info_rdc_01 = {
+ .flags = ATA_FLAG_SLAVE_POSS,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = 0,
+ .udma_mask = 0,
/* No UDMA */
.port_ops = &it821x_rdc_port_ops
};
@@ -912,11 +920,16 @@ static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
return rc;
if (pdev->vendor == PCI_VENDOR_ID_RDC) {
- /* Deal with Vortex86SX */
- if (pdev->revision == 0x11)
+ if (((pdev->revision == 0x11) || (pdev->revision == 0x13)) &&
+ (pdev->device == PCI_DEVICE_ID_RDC_D1010)) {
+ /* Deal with Vortex86SX */
ppi[0] = &info_rdc_11;
- else
+ printk(KERN_INFO DRV_NAME
+ ": Detected Vortex86SX/DX Bug.\n");
+ printk(KERN_INFO DRV_NAME ": Disabling UDMA.\n");
+ } else {
ppi[0] = &info_rdc;
+ }
} else {
/* Force the card into bypass mode if so requested */
if (it8212_noraid) {
@@ -926,8 +939,8 @@ static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
pci_read_config_byte(pdev, 0x50, &conf);
conf &= 1;
- printk(KERN_INFO DRV_NAME": controller in %s mode.\n",
- mode[conf]);
+ printk(KERN_INFO DRV_NAME ": controller in %s mode.\n",
+ mode[conf]);
if (conf == 0)
ppi[0] = &info_passthru;
else
@@ -954,21 +967,20 @@ static int it821x_reinit_one(struct pci_dev *pdev)
#endif
static const struct pci_device_id it821x[] = {
- { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8211), },
- { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8212), },
- { PCI_VDEVICE(RDC, PCI_DEVICE_ID_RDC_D1010), },
-
- { },
+ {PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8211),},
+ {PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8212),},
+ {PCI_VDEVICE(RDC, PCI_DEVICE_ID_RDC_D1010),},
+ {},
};
static struct pci_driver it821x_pci_driver = {
- .name = DRV_NAME,
- .id_table = it821x,
- .probe = it821x_init_one,
- .remove = ata_pci_remove_one,
+ .name = DRV_NAME,
+ .id_table = it821x,
+ .probe = it821x_init_one,
+ .remove = ata_pci_remove_one,
#ifdef CONFIG_PM
- .suspend = ata_pci_device_suspend,
- .resume = it821x_reinit_one,
+ .suspend = ata_pci_device_suspend,
+ .resume = it821x_reinit_one,
#endif
};
@@ -983,12 +995,12 @@ static void __exit it821x_exit(void)
}
MODULE_AUTHOR("Alan Cox");
-MODULE_DESCRIPTION("low-level driver for the IT8211/IT8212 IDE RAID controller");
+MODULE_DESCRIPTION
+("low-level driver for the IT8211/IT8212 IDE RAID controller");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, it821x);
MODULE_VERSION(DRV_VERSION);
-
module_param_named(noraid, it8212_noraid, int, S_IRUGO);
MODULE_PARM_DESC(noraid, "Force card into bypass mode");
diff --git a/drivers/ata/pata_rdc.c b/drivers/ata/pata_rdc.c
index 4d318f8..85b1e11 100644
--- a/drivers/ata/pata_rdc.c
+++ b/drivers/ata/pata_rdc.c
@@ -258,7 +258,7 @@ static void rdc_set_dmamode(struct ata_port *ap, struct ata_device *adev)
/* Load the matching timing */
slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << (ap->port_no ? 4 : 0);
pci_write_config_byte(dev, 0x44, slave_data);
- } else { /* Master */
+ } else { /* Master */
master_data &= 0xCCF4; /* Mask out IORDY|TIME1|DMAONLY
and master timing bits */
master_data |= control;
@@ -290,6 +290,16 @@ static struct ata_port_info rdc_port_info = {
.port_ops = &rdc_pata_ops,
};
+static struct ata_port_info vortex_port_info = {
+ .flags = ATA_FLAG_SLAVE_POSS,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = 0,
+ .udma_mask = 0,
+ /* No UDMA */
+ .port_ops = &rdc_pata_ops,
+};
+
+
static struct scsi_host_template rdc_sht = {
ATA_BMDMA_SHT(DRV_NAME),
};
@@ -322,16 +332,25 @@ static int __devinit rdc_init_one(struct pci_dev *pdev,
ata_print_version_once(&pdev->dev, DRV_VERSION);
- port_info[0] = rdc_port_info;
- port_info[1] = rdc_port_info;
-
- port_flags = port_info[0].flags;
-
/* enable device and prepare host */
rc = pcim_enable_device(pdev);
if (rc)
return rc;
+ if ((pdev->revision == 0x01) &&
+ (pdev->device == PCI_DEVICE_ID_RDC_D1011)) {
+ /* Deal with Vortex86DX */
+ port_info[0] = vortex_port_info;
+ port_info[1] = vortex_port_info;
+ printk(KERN_INFO DRV_NAME ": Detected Vortex86DX Bug.\n");
+ printk(KERN_INFO DRV_NAME ": Disabling UDMA.\n");
+ } else {
+ port_info[0] = rdc_port_info;
+ port_info[1] = rdc_port_info;
+ }
+
+ port_flags = port_info[0].flags;
+
hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
if (!hpriv)
return -ENOMEM;
@@ -365,8 +384,8 @@ static void rdc_remove_one(struct pci_dev *pdev)
}
static const struct pci_device_id rdc_pci_tbl[] = {
- { PCI_DEVICE(0x17F3, 0x1011), },
- { PCI_DEVICE(0x17F3, 0x1012), },
+ { PCI_VDEVICE(RDC, PCI_DEVICE_ID_RDC_D1011), },
+ { PCI_VDEVICE(RDC, PCI_DEVICE_ID_RDC_D1012), },
{ } /* terminate list */
};
diff --git a/drivers/ide/it821x.c b/drivers/ide/it821x.c
index 2e3169f..82c6bc7 100644
--- a/drivers/ide/it821x.c
+++ b/drivers/ide/it821x.c
@@ -581,10 +581,14 @@ static void __devinit init_hwif_it821x(ide_hwif_t *hwif)
hwif->ultra_mask = ATA_UDMA6;
hwif->mwdma_mask = ATA_MWDMA2;
- /* Vortex86SX quirk: prevent Ultra-DMA mode to fix BadCRC issue */
+ /* Vortex86SX and Vortex86DX quirk: prevent
+ * Ultra-DMA mode to fix BadCRC issue when
+ * using DMA mode */
if (idev->quirks & QUIRK_VORTEX86) {
- if (dev->revision == 0x11)
+ if (((dev->revision == 0x11) || (dev->revision == 0x13))
+ || (dev->revision == 0x01)) {
hwif->ultra_mask = 0;
+ }
}
}
@@ -680,6 +684,7 @@ static const struct pci_device_id it821x_pci_tbl[] = {
{ PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8211), 0 },
{ PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8212), 0 },
{ PCI_VDEVICE(RDC, PCI_DEVICE_ID_RDC_D1010), QUIRK_VORTEX86 },
+ { PCI_VDEVICE(RDC, PCI_DEVICE_ID_RDC_D1011), QUIRK_VORTEX86 },
{ 0, },
};
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index ae96bbe..237da92 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -2259,6 +2259,8 @@
#define PCI_DEVICE_ID_RDC_R6060 0x6060
#define PCI_DEVICE_ID_RDC_R6061 0x6061
#define PCI_DEVICE_ID_RDC_D1010 0x1010
+#define PCI_DEVICE_ID_RDC_D1011 0x1011
+#define PCI_DEVICE_ID_RDC_D1012 0x1012
#define PCI_VENDOR_ID_LENOVO 0x17aa
--
1.7.6.4
^ permalink raw reply related
* [PATCH 01/14] ATA : vortex86 : fix vortex86dx/sx hardware CRC bug.
From: Paul Schilling @ 2011-10-22 3:34 UTC (permalink / raw)
To: Jeff Garzik, David S. Miller, Jesse Barnes, linux-ide,
linux-kernel, linux-pci@
Cc: Paul Schilling, Paul Schilling
In-Reply-To: <Vortex86_PATA>
This fixes a DMA issue related to a CRC bug on
the RDC pata peripherial found on the vortex86sx and vortex86dx.
Signed-off-by: Paul Schilling <paul.s.schilling@gmail.com>
---
drivers/ata/pata_it821x.c | 264 +++++++++++++++++++++++---------------------
drivers/ata/pata_rdc.c | 35 +++++--
drivers/ide/it821x.c | 9 ++-
include/linux/pci_ids.h | 2 +
4 files changed, 174 insertions(+), 136 deletions(-)
diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c
index 62c5d00..eaf9c1e 100644
--- a/drivers/ata/pata_it821x.c
+++ b/drivers/ata/pata_it821x.c
@@ -1,5 +1,5 @@
/*
- * pata_it821x.c - IT821x PATA for new ATA layer
+ * pata_it821x.c - IT821x PATA for new ATA layer
* (C) 2005 Red Hat Inc
* Alan Cox <alan@lxorguk.ukuu.org.uk>
* (C) 2007 Bartlomiej Zolnierkiewicz
@@ -16,7 +16,7 @@
* Based in part on the ITE vendor provided SCSI driver.
*
* Documentation available from IT8212F_V04.pdf
- * http://www.ite.com.tw/EN/products_more.aspx?CategoryID=3&ID=5,91
+ * http://www.ite.com.tw/EN/products_more.aspx?CategoryID=3&ID=5,91
* Some other documents are NDA.
*
* The ITE8212 isn't exactly a standard IDE controller. It has two
@@ -79,22 +79,20 @@
#include <scsi/scsi_host.h>
#include <linux/libata.h>
-
#define DRV_NAME "pata_it821x"
#define DRV_VERSION "0.4.2"
-struct it821x_dev
-{
- unsigned int smart:1, /* Are we in smart raid mode */
- timing10:1; /* Rev 0x10 */
- u8 clock_mode; /* 0, ATA_50 or ATA_66 */
- u8 want[2][2]; /* Mode/Pri log for master slave */
+struct it821x_dev {
+ unsigned int smart:1, /* Are we in smart raid mode */
+ timing10:1; /* Rev 0x10 */
+ u8 clock_mode; /* 0, ATA_50 or ATA_66 */
+ u8 want[2][2]; /* Mode/Pri log for master slave */
/* We need these for switching the clock when DMA goes on/off
The high byte is the 66Mhz timing */
- u16 pio[2]; /* Cached PIO values */
- u16 mwdma[2]; /* Cached MWDMA values */
- u16 udma[2]; /* Cached UDMA values (per drive) */
- u16 last_device; /* Master or slave loaded ? */
+ u16 pio[2]; /* Cached PIO values */
+ u16 mwdma[2]; /* Cached MWDMA values */
+ u16 udma[2]; /* Cached UDMA values (per drive) */
+ u16 last_device; /* Master or slave loaded ? */
};
#define ATA_66 0
@@ -124,7 +122,8 @@ static int it8212_noraid;
* the DMA start/stop sequence as with the old driver.
*/
-static void it821x_program(struct ata_port *ap, struct ata_device *adev, u16 timing)
+static void it821x_program(struct ata_port *ap, struct ata_device *adev,
+ u16 timing)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
struct it821x_dev *itdev = ap->private_data;
@@ -139,7 +138,6 @@ static void it821x_program(struct ata_port *ap, struct ata_device *adev, u16 tim
pci_write_config_byte(pdev, 0x54 + 4 * channel, conf);
}
-
/**
* it821x_program_udma - program the UDMA registers
* @ap: ATA port
@@ -152,7 +150,8 @@ static void it821x_program(struct ata_port *ap, struct ata_device *adev, u16 tim
* here and partly in start_dma.
*/
-static void it821x_program_udma(struct ata_port *ap, struct ata_device *adev, u16 timing)
+static void it821x_program_udma(struct ata_port *ap, struct ata_device *adev,
+ u16 timing)
{
struct it821x_dev *itdev = ap->private_data;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
@@ -227,16 +226,16 @@ static void it821x_clock_strategy(struct ata_port *ap, struct ata_device *adev)
pci_write_config_byte(pdev, 0x50, v);
/*
- * Reprogram the UDMA/PIO of the pair drive for the switch
- * MWDMA will be dealt with by the dma switcher
+ * Reprogram the UDMA/PIO of the pair drive for the switch
+ * MWDMA will be dealt with by the dma switcher
*/
- if (pair && itdev->udma[1-unit] != UDMA_OFF) {
- it821x_program_udma(ap, pair, itdev->udma[1-unit]);
- it821x_program(ap, pair, itdev->pio[1-unit]);
+ if (pair && itdev->udma[1 - unit] != UDMA_OFF) {
+ it821x_program_udma(ap, pair, itdev->udma[1 - unit]);
+ it821x_program(ap, pair, itdev->pio[1 - unit]);
}
/*
- * Reprogram the UDMA/PIO of our drive for the switch.
- * MWDMA will be dealt with by the dma switcher
+ * Reprogram the UDMA/PIO of our drive for the switch.
+ * MWDMA will be dealt with by the dma switcher
*/
if (itdev->udma[unit] != UDMA_OFF) {
it821x_program_udma(ap, adev, itdev->udma[unit]);
@@ -253,11 +252,13 @@ static void it821x_clock_strategy(struct ata_port *ap, struct ata_device *adev)
* shared by PIO and MWDMA and for both channels.
*/
-static void it821x_passthru_set_piomode(struct ata_port *ap, struct ata_device *adev)
+static void it821x_passthru_set_piomode(struct ata_port *ap,
+ struct ata_device *adev)
{
/* Spec says 89 ref driver uses 88 */
- static const u16 pio[] = { 0xAA88, 0xA382, 0xA181, 0x3332, 0x3121 };
- static const u8 pio_want[] = { ATA_66, ATA_66, ATA_66, ATA_66, ATA_ANY };
+ static const u16 pio[] = { 0xAA88, 0xA382, 0xA181, 0x3332, 0x3121 };
+ static const u8 pio_want[] = {
+ ATA_66, ATA_66, ATA_66, ATA_66, ATA_ANY };
struct it821x_dev *itdev = ap->private_data;
int unit = adev->devno;
@@ -283,12 +284,17 @@ static void it821x_passthru_set_piomode(struct ata_port *ap, struct ata_device *
* we switch devices and mode.
*/
-static void it821x_passthru_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+static void it821x_passthru_set_dmamode(struct ata_port *ap,
+ struct ata_device *adev)
{
- static const u16 dma[] = { 0x8866, 0x3222, 0x3121 };
- static const u8 mwdma_want[] = { ATA_ANY, ATA_66, ATA_ANY };
- static const u16 udma[] = { 0x4433, 0x4231, 0x3121, 0x2121, 0x1111, 0x2211, 0x1111 };
- static const u8 udma_want[] = { ATA_ANY, ATA_50, ATA_ANY, ATA_66, ATA_66, ATA_50, ATA_66 };
+ static const u16 dma[] = { 0x8866, 0x3222, 0x3121 };
+ static const u8 mwdma_want[] = { ATA_ANY, ATA_66, ATA_ANY };
+ static const u16 udma[] = {
+ 0x4433, 0x4231, 0x3121,
+ 0x2121, 0x1111, 0x2211, 0x1111 };
+ static const u8 udma_want[] = {
+ ATA_ANY, ATA_50, ATA_ANY,
+ ATA_66, ATA_66, ATA_50, ATA_66 };
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
struct it821x_dev *itdev = ap->private_data;
@@ -309,9 +315,9 @@ static void it821x_passthru_set_dmamode(struct ata_port *ap, struct ata_device *
/* UDMA on. Again revision 0x10 must do the pair */
pci_read_config_byte(pdev, 0x50, &conf);
if (itdev->timing10)
- conf &= channel ? 0x9F: 0xE7;
+ conf &= channel ? 0x9F : 0xE7;
else
- conf &= ~ (1 << (3 + 2 * channel + unit));
+ conf &= ~(1 << (3 + 2 * channel + unit));
pci_write_config_byte(pdev, 0x50, conf);
it821x_clock_strategy(ap, adev);
it821x_program_udma(ap, adev, itdev->udma[unit]);
@@ -326,7 +332,7 @@ static void it821x_passthru_set_dmamode(struct ata_port *ap, struct ata_device *
/* UDMA bits off - Revision 0x10 do them in pairs */
pci_read_config_byte(pdev, 0x50, &conf);
if (itdev->timing10)
- conf |= channel ? 0x60: 0x18;
+ conf |= channel ? 0x60 : 0x18;
else
conf |= 1 << (3 + 2 * channel + unit);
pci_write_config_byte(pdev, 0x50, conf);
@@ -378,7 +384,6 @@ static void it821x_passthru_bmdma_stop(struct ata_queued_cmd *qc)
it821x_program(ap, adev, itdev->pio[unit]);
}
-
/**
* it821x_passthru_dev_select - Select master/slave
* @ap: ATA port
@@ -387,8 +392,7 @@ static void it821x_passthru_bmdma_stop(struct ata_queued_cmd *qc)
* Device selection hook. If necessary perform clock switching
*/
-static void it821x_passthru_dev_select(struct ata_port *ap,
- unsigned int device)
+static void it821x_passthru_dev_select(struct ata_port *ap, unsigned int device)
{
struct it821x_dev *itdev = ap->private_data;
if (itdev && device != itdev->last_device) {
@@ -410,29 +414,29 @@ static void it821x_passthru_dev_select(struct ata_port *ap,
static unsigned int it821x_smart_qc_issue(struct ata_queued_cmd *qc)
{
- switch(qc->tf.command)
- {
+ switch (qc->tf.command) {
/* Commands the firmware supports */
- case ATA_CMD_READ:
- case ATA_CMD_READ_EXT:
- case ATA_CMD_WRITE:
- case ATA_CMD_WRITE_EXT:
- case ATA_CMD_PIO_READ:
- case ATA_CMD_PIO_READ_EXT:
- case ATA_CMD_PIO_WRITE:
- case ATA_CMD_PIO_WRITE_EXT:
- case ATA_CMD_READ_MULTI:
- case ATA_CMD_READ_MULTI_EXT:
- case ATA_CMD_WRITE_MULTI:
- case ATA_CMD_WRITE_MULTI_EXT:
- case ATA_CMD_ID_ATA:
- case ATA_CMD_INIT_DEV_PARAMS:
- case 0xFC: /* Internal 'report rebuild state' */
+ case ATA_CMD_READ:
+ case ATA_CMD_READ_EXT:
+ case ATA_CMD_WRITE:
+ case ATA_CMD_WRITE_EXT:
+ case ATA_CMD_PIO_READ:
+ case ATA_CMD_PIO_READ_EXT:
+ case ATA_CMD_PIO_WRITE:
+ case ATA_CMD_PIO_WRITE_EXT:
+ case ATA_CMD_READ_MULTI:
+ case ATA_CMD_READ_MULTI_EXT:
+ case ATA_CMD_WRITE_MULTI:
+ case ATA_CMD_WRITE_MULTI_EXT:
+ case ATA_CMD_ID_ATA:
+ case ATA_CMD_INIT_DEV_PARAMS:
+ case 0xFC: /* Internal 'report rebuild state' */
/* Arguably should just no-op this one */
- case ATA_CMD_SET_FEATURES:
- return ata_bmdma_qc_issue(qc);
+ case ATA_CMD_SET_FEATURES:
+ return ata_bmdma_qc_issue(qc);
}
- printk(KERN_DEBUG "it821x: can't process command 0x%02X\n", qc->tf.command);
+ printk(KERN_DEBUG "it821x: can't process command 0x%02X\n",
+ qc->tf.command);
return AC_ERR_DEV;
}
@@ -462,7 +466,8 @@ static unsigned int it821x_passthru_qc_issue(struct ata_queued_cmd *qc)
* and respect them.
*/
-static int it821x_smart_set_mode(struct ata_link *link, struct ata_device **unused)
+static int it821x_smart_set_mode(struct ata_link *link,
+ struct ata_device **unused)
{
struct ata_device *dev;
@@ -509,8 +514,7 @@ static void it821x_dev_config(struct ata_device *adev)
if (strstr(model_num, "Integrated Technology Express")) {
/* RAID mode */
ata_dev_info(adev, "%sRAID%d volume",
- adev->id[147] ? "Bootable " : "",
- adev->id[129]);
+ adev->id[147] ? "Bootable " : "", adev->id[129]);
if (adev->id[129] != 1)
pr_cont("(%dK stripe)", adev->id[146]);
pr_cont("\n");
@@ -535,7 +539,7 @@ static void it821x_dev_config(struct ata_device *adev)
*/
static unsigned int it821x_read_id(struct ata_device *adev,
- struct ata_taskfile *tf, u16 *id)
+ struct ata_taskfile *tf, u16 * id)
{
unsigned int err_mask;
unsigned char model_num[ATA_ID_PROD_LEN + 1];
@@ -616,7 +620,7 @@ static void it821x_display_disk(int n, u8 *buf)
if (buf[52] > 4) /* No Disk */
return;
- ata_id_c_string((u16 *)buf, id, 0, 41);
+ ata_id_c_string((u16 *) buf, id, 0, 41);
if (buf[51]) {
mode = ffs(buf[51]);
@@ -635,10 +639,10 @@ static void it821x_display_disk(int n, u8 *buf)
strcpy(mbuf, "PIO");
if (buf[52] == 4)
printk(KERN_INFO "%d: %-6s %-8s %s %s\n",
- n, mbuf, types[buf[52]], id, cbl);
+ n, mbuf, types[buf[52]], id, cbl);
else
printk(KERN_INFO "%d: %-6s %-8s Volume: %1d %s %s\n",
- n, mbuf, types[buf[52]], buf[53], id, cbl);
+ n, mbuf, types[buf[52]], buf[53], id, cbl);
if (buf[125] < 100)
printk(KERN_INFO "%d: Rebuilding: %d%%\n", n, buf[125]);
}
@@ -673,7 +677,7 @@ static u8 *it821x_firmware_command(struct ata_port *ap, u8 cmd, int len)
udelay(1);
/* This should be almost immediate but a little paranoia goes a long
way. */
- while(n++ < 10) {
+ while (n++ < 10) {
status = ioread8(ap->ioaddr.status_addr);
if (status & ATA_ERR) {
kfree(buf);
@@ -681,8 +685,8 @@ static u8 *it821x_firmware_command(struct ata_port *ap, u8 cmd, int len)
return NULL;
}
if (status & ATA_DRQ) {
- ioread16_rep(ap->ioaddr.data_addr, buf, len/2);
- return (u8 *)buf;
+ ioread16_rep(ap->ioaddr.data_addr, buf, len / 2);
+ return (u8 *) buf;
}
mdelay(1);
}
@@ -711,18 +715,13 @@ static void it821x_probe_firmware(struct ata_port *ap)
if (buf != NULL) {
printk(KERN_INFO "pata_it821x: Firmware %02X/%02X/%02X%02X\n",
- buf[505],
- buf[506],
- buf[507],
- buf[508]);
+ buf[505], buf[506], buf[507], buf[508]);
for (i = 0; i < 4; i++)
- it821x_display_disk(i, buf + 128 * i);
+ it821x_display_disk(i, buf + 128 * i);
kfree(buf);
}
}
-
-
/**
* it821x_port_start - port setup
* @ap: ATA port being set up
@@ -772,7 +771,8 @@ static int it821x_port_start(struct ata_port *ap)
itdev->timing10 = 1;
/* Need to disable ATAPI DMA for this case */
if (!itdev->smart)
- printk(KERN_WARNING DRV_NAME": Revision 0x10, workarounds activated.\n");
+ printk(KERN_WARNING DRV_NAME
+ ": Revision 0x10, workarounds activated.\n");
}
return 0;
@@ -802,57 +802,57 @@ static struct scsi_host_template it821x_sht = {
};
static struct ata_port_operations it821x_smart_port_ops = {
- .inherits = &ata_bmdma_port_ops,
+ .inherits = &ata_bmdma_port_ops,
- .check_atapi_dma= it821x_check_atapi_dma,
- .qc_issue = it821x_smart_qc_issue,
+ .check_atapi_dma = it821x_check_atapi_dma,
+ .qc_issue = it821x_smart_qc_issue,
- .cable_detect = ata_cable_80wire,
- .set_mode = it821x_smart_set_mode,
- .dev_config = it821x_dev_config,
- .read_id = it821x_read_id,
+ .cable_detect = ata_cable_80wire,
+ .set_mode = it821x_smart_set_mode,
+ .dev_config = it821x_dev_config,
+ .read_id = it821x_read_id,
- .port_start = it821x_port_start,
+ .port_start = it821x_port_start,
};
static struct ata_port_operations it821x_passthru_port_ops = {
- .inherits = &ata_bmdma_port_ops,
+ .inherits = &ata_bmdma_port_ops,
- .check_atapi_dma= it821x_check_atapi_dma,
- .sff_dev_select = it821x_passthru_dev_select,
- .bmdma_start = it821x_passthru_bmdma_start,
- .bmdma_stop = it821x_passthru_bmdma_stop,
- .qc_issue = it821x_passthru_qc_issue,
+ .check_atapi_dma = it821x_check_atapi_dma,
+ .sff_dev_select = it821x_passthru_dev_select,
+ .bmdma_start = it821x_passthru_bmdma_start,
+ .bmdma_stop = it821x_passthru_bmdma_stop,
+ .qc_issue = it821x_passthru_qc_issue,
- .cable_detect = ata_cable_unknown,
- .set_piomode = it821x_passthru_set_piomode,
- .set_dmamode = it821x_passthru_set_dmamode,
+ .cable_detect = ata_cable_unknown,
+ .set_piomode = it821x_passthru_set_piomode,
+ .set_dmamode = it821x_passthru_set_dmamode,
- .port_start = it821x_port_start,
+ .port_start = it821x_port_start,
};
static struct ata_port_operations it821x_rdc_port_ops = {
- .inherits = &ata_bmdma_port_ops,
+ .inherits = &ata_bmdma_port_ops,
- .check_atapi_dma= it821x_check_atapi_dma,
- .sff_dev_select = it821x_passthru_dev_select,
- .bmdma_start = it821x_passthru_bmdma_start,
- .bmdma_stop = it821x_passthru_bmdma_stop,
- .qc_issue = it821x_passthru_qc_issue,
+ .check_atapi_dma = it821x_check_atapi_dma,
+ .sff_dev_select = it821x_passthru_dev_select,
+ .bmdma_start = it821x_passthru_bmdma_start,
+ .bmdma_stop = it821x_passthru_bmdma_stop,
+ .qc_issue = it821x_passthru_qc_issue,
- .cable_detect = it821x_rdc_cable,
- .set_piomode = it821x_passthru_set_piomode,
- .set_dmamode = it821x_passthru_set_dmamode,
+ .cable_detect = it821x_rdc_cable,
+ .set_piomode = it821x_passthru_set_piomode,
+ .set_dmamode = it821x_passthru_set_dmamode,
- .port_start = it821x_port_start,
+ .port_start = it821x_port_start,
};
static void it821x_disable_raid(struct pci_dev *pdev)
{
/* Neither the RDC nor the IT8211 */
if (pdev->vendor != PCI_VENDOR_ID_ITE ||
- pdev->device != PCI_DEVICE_ID_ITE_8212)
- return;
+ pdev->device != PCI_DEVICE_ID_ITE_8212)
+ return;
/* Reset local CPU, and set BIOS not ready */
pci_write_config_byte(pdev, 0x5E, 0x01);
@@ -864,12 +864,11 @@ static void it821x_disable_raid(struct pci_dev *pdev)
PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
pci_write_config_word(pdev, 0x40, 0xA0F3);
- pci_write_config_dword(pdev,0x4C, 0x02040204);
+ pci_write_config_dword(pdev, 0x4C, 0x02040204);
pci_write_config_byte(pdev, 0x42, 0x36);
pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x20);
}
-
static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
u8 conf;
@@ -898,7 +897,16 @@ static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
static const struct ata_port_info info_rdc_11 = {
.flags = ATA_FLAG_SLAVE_POSS,
.pio_mask = ATA_PIO4,
- .mwdma_mask = ATA_MWDMA2,
+ .mwdma_mask = 0,
+ .udma_mask = 0,
+ /* No UDMA */
+ .port_ops = &it821x_rdc_port_ops
+ };
+ static const struct ata_port_info info_rdc_01 = {
+ .flags = ATA_FLAG_SLAVE_POSS,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = 0,
+ .udma_mask = 0,
/* No UDMA */
.port_ops = &it821x_rdc_port_ops
};
@@ -912,11 +920,16 @@ static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
return rc;
if (pdev->vendor == PCI_VENDOR_ID_RDC) {
- /* Deal with Vortex86SX */
- if (pdev->revision == 0x11)
+ if (((pdev->revision == 0x11) || (pdev->revision == 0x13)) &&
+ (pdev->device == PCI_DEVICE_ID_RDC_D1010)) {
+ /* Deal with Vortex86SX */
ppi[0] = &info_rdc_11;
- else
+ printk(KERN_INFO DRV_NAME
+ ": Detected Vortex86SX/DX Bug.\n");
+ printk(KERN_INFO DRV_NAME ": Disabling UDMA.\n");
+ } else {
ppi[0] = &info_rdc;
+ }
} else {
/* Force the card into bypass mode if so requested */
if (it8212_noraid) {
@@ -926,8 +939,8 @@ static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
pci_read_config_byte(pdev, 0x50, &conf);
conf &= 1;
- printk(KERN_INFO DRV_NAME": controller in %s mode.\n",
- mode[conf]);
+ printk(KERN_INFO DRV_NAME ": controller in %s mode.\n",
+ mode[conf]);
if (conf == 0)
ppi[0] = &info_passthru;
else
@@ -954,21 +967,20 @@ static int it821x_reinit_one(struct pci_dev *pdev)
#endif
static const struct pci_device_id it821x[] = {
- { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8211), },
- { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8212), },
- { PCI_VDEVICE(RDC, PCI_DEVICE_ID_RDC_D1010), },
-
- { },
+ {PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8211),},
+ {PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8212),},
+ {PCI_VDEVICE(RDC, PCI_DEVICE_ID_RDC_D1010),},
+ {},
};
static struct pci_driver it821x_pci_driver = {
- .name = DRV_NAME,
- .id_table = it821x,
- .probe = it821x_init_one,
- .remove = ata_pci_remove_one,
+ .name = DRV_NAME,
+ .id_table = it821x,
+ .probe = it821x_init_one,
+ .remove = ata_pci_remove_one,
#ifdef CONFIG_PM
- .suspend = ata_pci_device_suspend,
- .resume = it821x_reinit_one,
+ .suspend = ata_pci_device_suspend,
+ .resume = it821x_reinit_one,
#endif
};
@@ -983,12 +995,12 @@ static void __exit it821x_exit(void)
}
MODULE_AUTHOR("Alan Cox");
-MODULE_DESCRIPTION("low-level driver for the IT8211/IT8212 IDE RAID controller");
+MODULE_DESCRIPTION
+("low-level driver for the IT8211/IT8212 IDE RAID controller");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, it821x);
MODULE_VERSION(DRV_VERSION);
-
module_param_named(noraid, it8212_noraid, int, S_IRUGO);
MODULE_PARM_DESC(noraid, "Force card into bypass mode");
diff --git a/drivers/ata/pata_rdc.c b/drivers/ata/pata_rdc.c
index 4d318f8..85b1e11 100644
--- a/drivers/ata/pata_rdc.c
+++ b/drivers/ata/pata_rdc.c
@@ -258,7 +258,7 @@ static void rdc_set_dmamode(struct ata_port *ap, struct ata_device *adev)
/* Load the matching timing */
slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << (ap->port_no ? 4 : 0);
pci_write_config_byte(dev, 0x44, slave_data);
- } else { /* Master */
+ } else { /* Master */
master_data &= 0xCCF4; /* Mask out IORDY|TIME1|DMAONLY
and master timing bits */
master_data |= control;
@@ -290,6 +290,16 @@ static struct ata_port_info rdc_port_info = {
.port_ops = &rdc_pata_ops,
};
+static struct ata_port_info vortex_port_info = {
+ .flags = ATA_FLAG_SLAVE_POSS,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = 0,
+ .udma_mask = 0,
+ /* No UDMA */
+ .port_ops = &rdc_pata_ops,
+};
+
+
static struct scsi_host_template rdc_sht = {
ATA_BMDMA_SHT(DRV_NAME),
};
@@ -322,16 +332,25 @@ static int __devinit rdc_init_one(struct pci_dev *pdev,
ata_print_version_once(&pdev->dev, DRV_VERSION);
- port_info[0] = rdc_port_info;
- port_info[1] = rdc_port_info;
-
- port_flags = port_info[0].flags;
-
/* enable device and prepare host */
rc = pcim_enable_device(pdev);
if (rc)
return rc;
+ if ((pdev->revision == 0x01) &&
+ (pdev->device == PCI_DEVICE_ID_RDC_D1011)) {
+ /* Deal with Vortex86DX */
+ port_info[0] = vortex_port_info;
+ port_info[1] = vortex_port_info;
+ printk(KERN_INFO DRV_NAME ": Detected Vortex86DX Bug.\n");
+ printk(KERN_INFO DRV_NAME ": Disabling UDMA.\n");
+ } else {
+ port_info[0] = rdc_port_info;
+ port_info[1] = rdc_port_info;
+ }
+
+ port_flags = port_info[0].flags;
+
hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
if (!hpriv)
return -ENOMEM;
@@ -365,8 +384,8 @@ static void rdc_remove_one(struct pci_dev *pdev)
}
static const struct pci_device_id rdc_pci_tbl[] = {
- { PCI_DEVICE(0x17F3, 0x1011), },
- { PCI_DEVICE(0x17F3, 0x1012), },
+ { PCI_VDEVICE(RDC, PCI_DEVICE_ID_RDC_D1011), },
+ { PCI_VDEVICE(RDC, PCI_DEVICE_ID_RDC_D1012), },
{ } /* terminate list */
};
diff --git a/drivers/ide/it821x.c b/drivers/ide/it821x.c
index 2e3169f..82c6bc7 100644
--- a/drivers/ide/it821x.c
+++ b/drivers/ide/it821x.c
@@ -581,10 +581,14 @@ static void __devinit init_hwif_it821x(ide_hwif_t *hwif)
hwif->ultra_mask = ATA_UDMA6;
hwif->mwdma_mask = ATA_MWDMA2;
- /* Vortex86SX quirk: prevent Ultra-DMA mode to fix BadCRC issue */
+ /* Vortex86SX and Vortex86DX quirk: prevent
+ * Ultra-DMA mode to fix BadCRC issue when
+ * using DMA mode */
if (idev->quirks & QUIRK_VORTEX86) {
- if (dev->revision == 0x11)
+ if (((dev->revision == 0x11) || (dev->revision == 0x13))
+ || (dev->revision == 0x01)) {
hwif->ultra_mask = 0;
+ }
}
}
@@ -680,6 +684,7 @@ static const struct pci_device_id it821x_pci_tbl[] = {
{ PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8211), 0 },
{ PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8212), 0 },
{ PCI_VDEVICE(RDC, PCI_DEVICE_ID_RDC_D1010), QUIRK_VORTEX86 },
+ { PCI_VDEVICE(RDC, PCI_DEVICE_ID_RDC_D1011), QUIRK_VORTEX86 },
{ 0, },
};
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index ae96bbe..237da92 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -2259,6 +2259,8 @@
#define PCI_DEVICE_ID_RDC_R6060 0x6060
#define PCI_DEVICE_ID_RDC_R6061 0x6061
#define PCI_DEVICE_ID_RDC_D1010 0x1010
+#define PCI_DEVICE_ID_RDC_D1011 0x1011
+#define PCI_DEVICE_ID_RDC_D1012 0x1012
#define PCI_VENDOR_ID_LENOVO 0x17aa
--
1.7.6.4
^ permalink raw reply related
* [U-Boot] NOTIFICATION
From: "Western Union®" <info@westernunion.org> at pegaso.una.edu.ve @ 2011-10-22 3:33 UTC (permalink / raw)
To: u-boot
Western Union?
Welcome to Western Union Money Transfer
PO Box 8252. London. W6 0BX, United Kingdom
Send Money Worldwide
Dear Beneficiary,
There is a package in our office (WESTERN UNION MONEY TRANSFER OFFICE UNITED KINGDOM). The package value amount of 19,000,000.00 Great British Pounds (Nineteen million Great British Pounds ). Directed in Cash credited to file KTU/9023118308/0324, At the owner of this email address . The INTERNATIONAL MONETARY FUNDS (I.M.F), have contacted this office to compensate you for using the Internet. We are unable to complete the transfer directed to your email address.
In order to resolve this problem, please email via Western Union Solicitors Funds Verification By Sending the bellow information:
*Full Name:......................
*Address:.........................
*Sex:................................
*Occupation:....................
*State:..............................
*Country:.........................
*Tell:...............................
NOTE: You are to provide us with the necessary information to enable us create your online-wire account.
Regards,
Dr. Bill Murphy
Tell: +447035964637
Email: western_union at ivac.cn
Western Union?
^ permalink raw reply
* [Buildroot] [Bug 4363] New: Make sure that copied linux and busybox defconfig are writable before modifying
From: bugzilla at busybox.net @ 2011-10-22 3:28 UTC (permalink / raw)
To: buildroot
https://bugs.busybox.net/show_bug.cgi?id=4363
Summary: Make sure that copied linux and busybox defconfig are
writable before modifying
Product: buildroot
Version: unspecified
Platform: PC
OS/Version: Linux
Status: NEW
Severity: normal
Priority: P5
Component: Other
AssignedTo: unassigned at buildroot.uclibc.org
ReportedBy: d_mo1234 at yahoo.com
CC: buildroot at uclibc.org
Estimated Hours: 0.0
Created attachment 3661
--> https://bugs.busybox.net/attachment.cgi?id=3661
patch file
I use buildroot in a source controlled environment, with a custom target
skeleton, custom linux defconfig, and custom busybox defconfig. If the custom
defconfigs are not checked out, then they are read-only. So when linux.mk and
busybox.mk copy their respective customized defconfig to output/build, they get
copied as read-only. Then, buildroot tries to modify these files based on the
.config settings, it fails. (You have to manually open permissions to get the
mods operations to work, and move on.) This problem can be avoided by opening
permissions after the copy.
To this end, a patch file is attached.
--
Configure bugmail: https://bugs.busybox.net/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are on the CC list for the bug.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.