* Re: [PATCH v2] pci: export class IDs from pci_ids.h
From: Michael S. Tsirkin @ 2015-04-05 11:20 UTC (permalink / raw)
To: Greg KH
Cc: Bjorn Helgaas, linux-kernel, Jonathan Corbet, David S. Miller,
Hans Verkuil, Mauro Carvalho Chehab, Alexei Starovoitov,
stephen hemminger, Masahiro Yamada, linux-pci, linux-doc,
linux-api
In-Reply-To: <20150402215921.GA3942@kroah.com>
On Thu, Apr 02, 2015 at 11:59:21PM +0200, Greg KH wrote:
> On Thu, Apr 02, 2015 at 11:28:19PM +0200, Michael S. Tsirkin wrote:
> > On Thu, Apr 02, 2015 at 03:53:47PM -0500, Bjorn Helgaas wrote:
> > > On Mon, Mar 30, 2015 at 01:33:28PM +0200, Michael S. Tsirkin wrote:
> > > > The basic class ID macros in pci_ids.h are pretty useful for userspace
> > > > using the pci sysfs interface, and they aren't fundamentally different
> > > > from the constants in pci_regs.h - both are defined in the
> > > > pci spec.
> > > >
> > > > At the moment userspace is forced to duplicate these macros
> > > > (e.g. QEMU does this, so do seabios, gpxe, and others), it is better to
> > > > expose them in /usr/include/linux/pci_ids.h so everyone can just include
> > > > this header.
> > >
> > > I agree that it would be nice for applications to get these definitions
> > > from a single place, but I'm not sure that include/uapi/linux/pci_ids.h
> > > needs to be that place.
> > >
> > > These constants are just copies of what's in the spec, and I don't think
> > > you're suggesting that the constants are necessary to use a kernel API.
> > >
> > > I know the kernel does provide access to values via sysfs "class" files,
> > > but the kernel is just passing the values through from the hardware.
> > > That's analogous to reading the class with setpci, and I don't think it
> > > leads to a requirement that the kernel export all the information about how
> > > to interpret the class values.
> > >
> > > I haven't looked at libpci or libudev, but it sounds like you think those
> > > are not good solutions. Is that because they don't currently have this
> > > information? People don't want to add dependencies on them?
> > >
> > > Bjorn
> >
> > People don't want to add dependencies on them.
>
> So you want us to create yet-a-third-location for these values?
I propose making this part of base Linux system headers, yes.
BTW it's not a third location actually. It would be a third location in a
library, but there are many other packages that duplicate this code.
Since we have this code around anyway, if we just export it, then
there's hope that with time all this duplicate code will go away, then
when e.g. a new value is added to spec, people will add it to linux and
everyone benefits. As I work on QEMU, I know QEMU will do it,
likely bios and gpxe too, I expect libpci/libudev to be no different.
> Both
> libpci and libudev are on all systems. And it's not a run-time
> dependancy you are talking about here, but a build-time one, which is
> quite different.
Yes: build-time dependencies annoy developers, run-time ones annoy users :)
In a sense build-time dependencies are more annoying as it's harder to
resolve them.
> Having a build-time dependancy on packages that ship
> with all Linux distributions seems acceptable to me.
>
> thanks,
>
> greg k-h
^ permalink raw reply
* Re: [patch -mm] mm, doc: cleanup and clarify munmap behavior for hugetlb memory fix
From: Jonathan Corbet @ 2015-04-04 9:34 UTC (permalink / raw)
To: David Rientjes
Cc: Andrew Morton, Hugh Dickins, Davide Libenzi, Luiz Capitulino,
Shuah Khan, Andrea Arcangeli, Joern Engel, Jianguo Wu,
Eric B Munson, linux-mm, linux-kernel, linux-api, linux-doc
In-Reply-To: <alpine.DEB.2.10.1504021547330.15536@chino.kir.corp.google.com>
On Thu, 2 Apr 2015 15:50:15 -0700 (PDT)
David Rientjes <rientjes@google.com> wrote:
> Don't only specify munmap(2) behavior with respect the hugetlb memory, all
> other syscalls get naturally aligned to the native page size of the
> processor. Rather, pick out munmap(2) as a specific example.
So I was going to apply this to the docs tree, but it doesn't even come
close. What tree was this patch generated against?
Thanks,
jon
^ permalink raw reply
* Re: [PATCH 13/14] twl4030_charger: Increase current carefully while watching voltage.
From: Pavel Machek @ 2015-04-04 7:48 UTC (permalink / raw)
To: NeilBrown
Cc: NeilBrown, Sebastian Reichel, linux-api-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, GTA04 owners,
inux-pm-u79uwXL29TY76Z2rM5mHXA, linux-omap-u79uwXL29TY76Z2rM5mHXA,
Lee Jones
In-Reply-To: <20150330082637.4bf4832d-wvvUuzkyo1EYVZTmpyfIwg@public.gmane.org>
Hi!
> > > The USB Battery Charging spec (BC1.2) suggests a dedicated
> > > charging port can deliver from 0.5 to 5.0A at between 4.75 and 5.25
> > > volts.
> > >
> > > To choose the "correct" current voltage setting requires a trial
> > > and error approach: try to draw current and see if the voltage drops
> > > too low.
> > >
> > > Even with a configured Standard Downstream Port, it may not be possible
> > > to reliably pull 500mA - depending on cable quality and source
> > > quality I have reports of charging failure due to the voltage dropping
> > > too low.
> > >
> > > To address both these concerns, this patch introduce incremental
> > > current setting.
> > > The current pull from VBUS is increased in steps of 20mA every 100ms
> > > until the target is reached or until the measure voltage drops below
> > > 4.75V. If the voltage does go too low, the target current is reduced
> > > by 20mA and kept there.
> >
> > Still nervous. If it is possible to overheat the charger, without
> > tripping internal fuse, then you'll do it.
>
> If it is possible to overheat the charger without tripping an internal fuse,
> then sure the charger is mis-designed - is it not?
>
> Can you suggest an algorithm for determining how much current can safely be
> pulled from a charger that would *not* make you nervous?
Not nervous? No.
Less nervous?
Run detection as you do, but then round down to "known reasonable"
max charging currents?
If you detected 1.1A charger, you are probably overloading 1A
charger. So idea would be to round down to 0.5A, 1A, 1.7A.
> > Idle device. Code will find that it can charge using 1A, backs up to
> > 0.9A. User starts hotspot. Now device will draw 1.4A, overloading the
> > charger and not charging at all...?
>
> The current being measured and controlled is the current flowing in from the
> USB VBUS, not flowing out to the battery.
> So I the code choose 0.9A, that is all that will be drawn.
>
> This is a possible issue similar to this though.
> If the device is idle and the battery is fully charged, then it won't draw
> much current from USB even if we allow it too.
> So the algorithm might decide it is OK to draw 1.7A because at that time the
> device cannot use more than 200mA, and that doesn't cause the voltage to drop.
>
> Then later when user enabled wifi-hotspot, the current needed might go up
> above what the charger can provide.
>
> Maybe I should only increase the limit while the actual current is also
> increasing. Maybe also revisit the setting when the battery starts charging.
Yes, that sounds better.
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
^ permalink raw reply
* Re: [PATCH net-next] tc: cls_bpf: make ingress and egress qdiscs consistent
From: Daniel Borkmann @ 2015-04-04 6:34 UTC (permalink / raw)
To: Alexei Starovoitov, David S. Miller
Cc: Jiri Pirko, Jamal Hadi Salim, linux-api-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <551F2CD4.2080502-uqk4Ao+rVK5Wk0Htik3J/w@public.gmane.org>
On 04/04/2015 02:14 AM, Alexei Starovoitov wrote:
> On 4/3/15 4:48 PM, Daniel Borkmann wrote:
>> On 04/04/2015 01:26 AM, Daniel Borkmann wrote:
>>> On 04/04/2015 01:11 AM, Alexei Starovoitov wrote:
>> ...
>>>> nope. will take it back.
>>>> that doesn't work, since this check cannot be done in ingress_enqueue(),
>>>> because it sees the pointer to first filter only, so both TCQ_F_INGRESS
>>>> flag and CLS_REQUIRES_L2 flag need to be checked inside
>>>
>>> So on a quick glance, we're calling into cls_bpf_classify() in
>>> tp->classify()
>>> (net/sched/cls_api.c +265), so all remaining filters in that list we're
>>> traversing in cls_bpf_classify() are all BPF filters, no?
>>
>> I see, you mean the classifier chain, not the chain of filters within
>> the cls_bpf classifier, ok.
>
> yes. the chain of classifiers can have different types, so we
> cannot check it once in ingress_enqueue().
> As you said we can refactor it later.
Too many indirections. :/ Yes, I'm fine with that, thanks.
^ permalink raw reply
* Re: [PATCH v7 0/5] vfs: Non-blockling buffered fs read (page cache only)
From: Andrew Morton @ 2015-04-04 3:42 UTC (permalink / raw)
To: Christoph Hellwig, Jeremy Allison, Milosz Tanski, linux-kernel,
linux-fsdevel, linux-aio, Mel Gorman, Volker Lendecke, Tejun Heo,
Jeff Moyer, Theodore Ts'o, Al Viro, linux-api,
Michael Kerrisk, linux-arch, Dave Chinner
In-Reply-To: <20150330132625.52b1250527ca3dcda79e349e@linux-foundation.org>
On Mon, 30 Mar 2015 13:26:25 -0700 Andrew Morton <akpm@linux-foundation.org> wrote:
> d) fincore() is more expensive
Actually, I kinda take that back. fincore() will be faster than
preadv2() in the case of a pagecache miss, and slower in the case of a
pagecache hit.
The breakpoint appears to be a hit rate of 30% - if fewer than 30% of
queries find the page in pagecache, fincore() will be faster than
preadv2().
This is because for a pagecache miss, fincore() will be about twice as
fast as preadv2(). For a pagecache hit, fincore()+pread() is 55%
slower than preadv2(). If there are lots of misses, fincore() is
faster overall.
Minimal fincore() implementation is below. It doesn't implement the
page_map!=NULL mode at all and will be slow for large areas - it needs
to be taught about radix_tree_for_each_*(). But it's good enough for
testing.
On a slow machine, in nanoseconds:
null syscall: 528
fincore (miss): 674
fincore (hit): 729
single byte pread: 1026
single byte preadv: 1134
pread() is a bit faster than preadv() and samba uses pread(), so the
implementations are:
if (fincore(fd, NULL, offset, len) == len)
pread();
else
punt();
if (preadv2(fd, ..., offset, len) == len)
...
else
punt();
fincore+pread, pagecache-hit: 1755ns
fincore+pread, pagecache-miss: 674ns
preadv(): 1134ns (preadv2() will be a little faster for misses)
Now, a pagecache hit rate of 30% sounds high so one would think that
fincore+pread is clearly ahead. But the pagecache hit rate in this
code will actually be quite high, because of readahead.
For a large linear read of a file which is perfectly laid out on disk
and is fully *uncached*, the hit rates will be as good as 99.8%,
because readahead is bringing in data in 2MB blobs.
In practice I expect that fincore()+pread() will be slower for linear
reads of medium to large files and faster for small files and seeky
accesses.
How much does all this matter? Not much. On a fast machine a
single-byte pread() takes 240ns. So if your server thread is handling
25000 requests/sec, we're only talking 0.6% overhead.
Note that we can trivially monitor the hit rate with either preadv2()
or fincore()+pread(): just count how many times all the data is there
versus how many times it isn't.
Also, note that we can use *both* fincore() and preadv2() to detect the
problematic page-just-disappeared race:
if (fincore(fd, NULL, offset, len) == len) {
if (preadv2(fd, offset, len) != len)
printf("race just happened");
It would be great if someone could apply the below, modify the
preadv2() callsite as above and determine under what conditions (if
any) the page-stealing race occurs.
arch/x86/syscalls/syscall_64.tbl | 1
include/linux/syscalls.h | 2
mm/Makefile | 2
mm/fincore.c | 65 +++++++++++++++++++++++++++++
4 files changed, 69 insertions(+), 1 deletion(-)
diff -puN arch/x86/syscalls/syscall_64.tbl~fincore arch/x86/syscalls/syscall_64.tbl
--- a/arch/x86/syscalls/syscall_64.tbl~fincore
+++ a/arch/x86/syscalls/syscall_64.tbl
@@ -331,6 +331,7 @@
322 64 execveat stub_execveat
323 64 preadv2 sys_preadv2
324 64 pwritev2 sys_pwritev2
+325 common fincore sys_fincore
#
# x32-specific system call numbers start at 512 to avoid cache impact
diff -puN include/linux/syscalls.h~fincore include/linux/syscalls.h
--- a/include/linux/syscalls.h~fincore
+++ a/include/linux/syscalls.h
@@ -880,6 +880,8 @@ asmlinkage long sys_process_vm_writev(pi
asmlinkage long sys_kcmp(pid_t pid1, pid_t pid2, int type,
unsigned long idx1, unsigned long idx2);
asmlinkage long sys_finit_module(int fd, const char __user *uargs, int flags);
+asmlinkage long sys_fincore(int fd, unsigned char __user *page_map,
+ loff_t offset, size_t len);
asmlinkage long sys_seccomp(unsigned int op, unsigned int flags,
const char __user *uargs);
asmlinkage long sys_getrandom(char __user *buf, size_t count,
diff -puN mm/Makefile~fincore mm/Makefile
--- a/mm/Makefile~fincore
+++ a/mm/Makefile
@@ -19,7 +19,7 @@ obj-y := filemap.o mempool.o oom_kill.
readahead.o swap.o truncate.o vmscan.o shmem.o \
util.o mmzone.o vmstat.o backing-dev.o \
mm_init.o mmu_context.o percpu.o slab_common.o \
- compaction.o vmacache.o \
+ compaction.o vmacache.o fincore.o \
interval_tree.o list_lru.o workingset.o \
debug.o $(mmu-y)
diff -puN /dev/null mm/fincore.c
--- /dev/null
+++ a/mm/fincore.c
@@ -0,0 +1,65 @@
+#include <linux/syscalls.h>
+#include <linux/pagemap.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/hugetlb.h>
+
+SYSCALL_DEFINE4(fincore, int, fd, unsigned char __user *, page_map,
+ loff_t, offset, size_t, len)
+{
+ struct fd f;
+ struct address_space *mapping;
+ loff_t cur_off;
+ loff_t end;
+ pgoff_t pgoff;
+ long ret = 0;
+
+ if (offset < 0 || (ssize_t)len <= 0)
+ return -EINVAL;
+
+ f = fdget(fd);
+
+ if (!f.file)
+ return -EBADF;
+
+ if (is_file_hugepages(f.file)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (!S_ISREG(file_inode(f.file)->i_mode)) {
+ ret = -EBADF;
+ goto out;
+ }
+
+ end = min_t(loff_t, offset + len, i_size_read(file_inode(f.file)));
+ pgoff = offset >> PAGE_CACHE_SHIFT;
+ mapping = f.file->f_mapping;
+
+ /*
+ * We probably need to do somethnig here to reduce the chance of the
+ * pages being reclaimed between fincore() and read(). eg,
+ * SetPageReferenced(page) or mark_page_accessed(page) or
+ * activate_page(page).
+ */
+ for (cur_off = offset; cur_off < end ; ) {
+ struct page *page;
+ loff_t end_of_coverage;
+
+ page = find_get_page(mapping, pgoff);
+ if (!page || !PageUptodate(page))
+ break;
+ page_cache_release(page);
+
+ pgoff++;
+ end_of_coverage = min_t(loff_t, pgoff << PAGE_CACHE_SHIFT, end);
+ ret += end_of_coverage - cur_off;
+ cur_off = (cur_off + PAGE_CACHE_SIZE) & PAGE_CACHE_MASK;
+ }
+
+out:
+ fdput(f);
+ return ret;
+}
_
^ permalink raw reply
* Re: [PATCH 0/5] Enhancements to twl4030 phy to support better charging - V2
From: NeilBrown @ 2015-04-04 0:28 UTC (permalink / raw)
To: Kishon Vijay Abraham I
Cc: NeilBrown, Tony Lindgren, linux-api-u79uwXL29TY76Z2rM5mHXA,
GTA04 owners, linux-kernel-u79uwXL29TY76Z2rM5mHXA, Pavel Machek,
cw00.choi-Sze3O3UU22JBDgjK7y7TUQ,
myungjoo.ham-Sze3O3UU22JBDgjK7y7TUQ
In-Reply-To: <551E97CE.4000501-l0cyMroinI0@public.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 7109 bytes --]
On Fri, 3 Apr 2015 19:08:22 +0530 Kishon Vijay Abraham I <kishon-l0cyMroinI0@public.gmane.org>
wrote:
> +Extcon MAINTAINERS
>
> Hi,
>
> On Wednesday 01 April 2015 10:11 AM, NeilBrown wrote:
> > On Thu, 26 Mar 2015 05:29:42 +0530 Kishon Vijay Abraham I <kishon-Bv2c3lPp1Ag@public.gmane.orgm>
> > wrote:
> >
> >> Hi NeilBrown,
> >>
> >> On Thursday 26 March 2015 02:52 AM, NeilBrown wrote:
> >>> On Thu, 26 Mar 2015 02:46:32 +0530 Kishon Vijay Abraham I <kishon@ti.com>
> >>> wrote:
> >>>
> >>>> Hi,
> >>>>
> >>>> On Monday 23 March 2015 04:05 AM, NeilBrown wrote:
> >>>>> Hi Kishon,
> >>>>> I wonder if you could queue the following for the next merge window.
> >>>>> They allow the twl4030 phy to provide more information to the
> >>>>> twl4030 battery charger.
> >>>>> There are only minimal changes since the first version, particularly
> >>>>> documentation has been improved.
> >>>>
> >>>> There are quite a few things in this series which use the USB PHY library
> >>>> interface which is kindof deprecated. We should try and use the Generic PHY
> >>>> library for all of them. It would also be better to add features to the
> >>>> PHY framework if the we can't achieve something with the existing PHY
> >>>> framework.
> >>>
> >>> Hi,
> >>> are you able to more specific at all? What is the "USB PHY library"?
> >>> Where exactly is the "PHY framework"?
> >>
> >> There is a USB PHY library that exists in drivers/usb/phy/phy.c and there is
> >> a Generic PHY framework that is present in drivers/phy/phy-core.c. twl4030
> >> actually supports both the framework.
> >>
> >> In your patch whatever uses struct usb_phy uses the old USB PHY library and
> >> whatever uses struct phy uses the generic PHY framework. (Actually your patch
> >> does not use the PHY framework at all). We want to deprecate using the USB PHY
> >> library and make everyone use the generic PHY framework. Adding features
> >> to a driver using the USB PHY library will make the transition to generic PHY
> >> framework a bit more difficult.
> >>
> >> Now all the features that is supported in the USB PHY library may not be
> >> supported by the PHY framework. So we should start extending the PHY framework
> >> instead of using the USB PHY library.
> >>
> >> One think I noticed in your driver is using atomic notifier chain. IMO extcon
> >> framework should be used in twl4030 USB driver to notify the controller driver
> >> instead of using USB PHY notifier. For all other things we have to see if it
> >> can be added in the PHY framework.
> >
> > I've had a look at the code with these issues in mind, and there is one issue
> > that I'm not sure about.
> >
> > In phy-twl4030-usb, the usb_phy is used to hold a reference to the
> > 'struct otg', and for passing cable state changes to the notifier.
>
> right now we directly call omap_musb_mailbox no? we don't use notifiers right?
Correct, and omap_musb_set_mailbox uses the notifier chain.
phy-twl4030-usb does
ATOMIC_INIT_NOTIFIER_HEAD(&twl->phy.notifier);
That is the only place the current phy code interacts with the notifier chain.
> >
> > The former probably has to stay until musb can keep a reference to the otg,
> > separate form the usb_phy. The latter can be changed to use extcon - to
> > some extent. I actually have patches to do that from a couple of years back,
> > but I never proceeded with them.
> >
> > The problem is that one thing that needs to be communicated to the charger is
> > the max current that was negotiated by a "Standard Downstream Port".
> > This could be 500mA from a powered hum, or much less from an unpowered hub.
> > (Currently the usb gadget code does negotiated between different
> > possibilities, but it could and hopefully will one day).
> >
> > With the notifier chain there is an easy way to communicate the allowed
> > current once it is negotiated. e.g. ab8500_usb_set_power() does this.
> >
> > 'struct phy' has no equivalent of the 'set_power' callback which 'struct
> > usb_phy' provides, and extcon has no mechanism (that I can see) for
> > communicating a number - just binary cable states.
>
> Chanwoo Choi, Can this be modified so that we can communicate numbers like in
> the case of EXTCON_CHARGE_DOWNSTREAM?
> >
> > Presumably a 'set_power' method could be added to 'struct phy' so the
> > usb-core can communicate the number to the phy, but it is not clear to me how
> > the 'phy' can communicate it to the charger.
>
> Should the PHY be involved in all this? We can make the gadget driver
> directly communicate the value to the charger no?
> > The 'phy' could provide an API to request the current negotiated max current,
> > but there still needs to be a way to let the charger know that this has
> > changed.
> > That could in theory be done via extcon, by having a secondary
> > 'USB_connected' cable type, but it isn't really a cable type and pretending
> > that it is seems wrong.
>
> I think EXTCON_CHARGE_DOWNSTREAM was created for that purpose. Chanwoo?
>
EXTCON_CHARGE_DOWNSTREAM is something quite different.
There are roughly three ways that the USB gadget can determine what sort of
thing has been plugged in to it and what current it can draw.
- it can look at the resistance between the ID pin and GROUND. This is a
physical property of the cable and it makes a lot of sense of EXTCON
to report different cables based on different resistances.
- it can look at the voltage provided on different pins. If it detects a
certain voltage on D- when it asserts a voltage on D+, it can know
that it is a Charging Downstream Port (EXTCON_CHARGE_DOWNSTREAM). This
might be a property of the cable (shorting D- to D+ can achieve this) or
might be a property of the attached device. It makes some sense for
EXTCON to report cable type based on this sort of information.
- it can wait for the connected host to initiate a USB session and select a
particular profile. That profile will include a "MaxPower" field. When
the host selects that profile, the gadget knows it is allowed to draw that
much power ("current" really, measured in mA).
So EXTCON_CHARGE_DOWNSTREAM fits into the second category. My question is
about the third category.
I need this "MaxPower" number to be communicated from the USB core to the
charger driver, presumably via the "phy" driver.
With "usb_phy", there is a ->set_power() callback to communicate from
usb-core to phy, and a notifier chain to communicate from phy to charger.
With "phy" there is nothing.
extcon _could_ be used to communicate the MaxPower, but I'm not sure it makes
sense. It is a property of the power available on the cable, not a property
of the cable itself, or something that can be deduced from the properties of
the cable.
I guess I could get musb_gadget_vbus_draw(), or usb_phy_set_power(), to call
the notifier chain directly. But if usb_phy is being deprecated, that isn't
a long-term solution.
Thanks,
NeilBrown
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 811 bytes --]
^ permalink raw reply
* Re: [PATCH net-next] tc: cls_bpf: make ingress and egress qdiscs consistent
From: Alexei Starovoitov @ 2015-04-04 0:14 UTC (permalink / raw)
To: Daniel Borkmann, David S. Miller
Cc: Jiri Pirko, Jamal Hadi Salim, linux-api, netdev
In-Reply-To: <551F26BE.1010607@iogearbox.net>
On 4/3/15 4:48 PM, Daniel Borkmann wrote:
> On 04/04/2015 01:26 AM, Daniel Borkmann wrote:
>> On 04/04/2015 01:11 AM, Alexei Starovoitov wrote:
> ...
>>> nope. will take it back.
>>> that doesn't work, since this check cannot be done in ingress_enqueue(),
>>> because it sees the pointer to first filter only, so both TCQ_F_INGRESS
>>> flag and CLS_REQUIRES_L2 flag need to be checked inside
>>
>> So on a quick glance, we're calling into cls_bpf_classify() in
>> tp->classify()
>> (net/sched/cls_api.c +265), so all remaining filters in that list we're
>> traversing in cls_bpf_classify() are all BPF filters, no?
>
> I see, you mean the classifier chain, not the chain of filters within
> the cls_bpf classifier, ok.
yes. the chain of classifiers can have different types, so we
cannot check it once in ingress_enqueue().
As you said we can refactor it later.
^ permalink raw reply
* Re: [PATCH net-next] tc: cls_bpf: make ingress and egress qdiscs consistent
From: Daniel Borkmann @ 2015-04-03 23:48 UTC (permalink / raw)
To: Alexei Starovoitov, David S. Miller
Cc: Jiri Pirko, Jamal Hadi Salim, linux-api, netdev
In-Reply-To: <551F21A0.1030503@iogearbox.net>
On 04/04/2015 01:26 AM, Daniel Borkmann wrote:
> On 04/04/2015 01:11 AM, Alexei Starovoitov wrote:
...
>> nope. will take it back.
>> that doesn't work, since this check cannot be done in ingress_enqueue(),
>> because it sees the pointer to first filter only, so both TCQ_F_INGRESS
>> flag and CLS_REQUIRES_L2 flag need to be checked inside
>
> So on a quick glance, we're calling into cls_bpf_classify() in tp->classify()
> (net/sched/cls_api.c +265), so all remaining filters in that list we're
> traversing in cls_bpf_classify() are all BPF filters, no?
I see, you mean the classifier chain, not the chain of filters within
the cls_bpf classifier, ok.
> Have to grab some sleep for now, will be on travel tomorrow. Anyway, worst
> case it could still be refactored later.
^ permalink raw reply
* Re: [PATCH net-next] tc: cls_bpf: make ingress and egress qdiscs consistent
From: Daniel Borkmann @ 2015-04-03 23:26 UTC (permalink / raw)
To: Alexei Starovoitov, David S. Miller
Cc: Jiri Pirko, Jamal Hadi Salim, linux-api-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <551F1E13.8050508-uqk4Ao+rVK5Wk0Htik3J/w@public.gmane.org>
On 04/04/2015 01:11 AM, Alexei Starovoitov wrote:
> On 4/3/15 4:04 PM, Alexei Starovoitov wrote:
>> On 4/3/15 3:54 PM, Daniel Borkmann wrote:
...
>>> I see the point regarding the user option. So, why not adding a flag
>>> to tcf_proto_ops a la `.flags = CLS_REQUIRES_L2` that gets propagated
>>> to tcf_proto, and only ingress_enqueue() would need to test if the
>>> classifier imposes that requirement, so it can push/pull.
>>
>> ok. that sounds better, but neither tcf_proto nor tcf_proto_ops have
>> 'flags' field today... well, I guess it's time to add flags there.
I don't think it would be a big problem.
>> Probably add 'flags' to tcf_proto_ops only and do fl->ops->flags in
>> ingress_enqueue()?
Something along that line, yeah.
>> Will respin.
>
> nope. will take it back.
> that doesn't work, since this check cannot be done in ingress_enqueue(),
> because it sees the pointer to first filter only, so both TCQ_F_INGRESS
> flag and CLS_REQUIRES_L2 flag need to be checked inside
So on a quick glance, we're calling into cls_bpf_classify() in tp->classify()
(net/sched/cls_api.c +265), so all remaining filters in that list we're
traversing in cls_bpf_classify() are all BPF filters, no?
Have to grab some sleep for now, will be on travel tomorrow. Anyway, worst
case it could still be refactored later.
^ permalink raw reply
* Re: [PATCH net-next] tc: cls_bpf: make ingress and egress qdiscs consistent
From: Alexei Starovoitov @ 2015-04-03 23:11 UTC (permalink / raw)
To: Daniel Borkmann, David S. Miller
Cc: Jiri Pirko, Jamal Hadi Salim, linux-api, netdev
In-Reply-To: <551F1C9B.6070908@plumgrid.com>
On 4/3/15 4:04 PM, Alexei Starovoitov wrote:
> On 4/3/15 3:54 PM, Daniel Borkmann wrote:
>> On 04/04/2015 12:17 AM, Alexei Starovoitov wrote:
>> ...
>>> 1. there shouldn't be a choice at all for bpf. Because not pulling l2
>>> means it's bug.
>>
>> Yep, correct. You would also loose context for a possible dissection,
>> at best you only have skb->protocol.
>>
>>> 2. adding a flag means adding it to iproute2 with default off and making
>>> users forgetting it from time to time and have no way of knowing why
>>> their programs all of a sudden stopped working.
>>>
>>> classic falls under the same rules. It doesn't make sense at all to run
>>> a program on packet without L2 header. It's very odd both for classic
>>> and extended programs.
>>
>> Yep.
>>
>>> Two 'if' conditions in critical path is bogus argument, since these
>>> checks would be there in ingress as well. Same critical path.
>>
>> Why bogus? There would be no such test on the normal egress path,
>> where this is irrelevant. I wasn't talking about ingress here.
>>
>> I see the point regarding the user option. So, why not adding a flag
>> to tcf_proto_ops a la `.flags = CLS_REQUIRES_L2` that gets propagated
>> to tcf_proto, and only ingress_enqueue() would need to test if the
>> classifier imposes that requirement, so it can push/pull.
>
> ok. that sounds better, but neither tcf_proto nor tcf_proto_ops have
> 'flags' field today... well, I guess it's time to add flags there.
> Probably add 'flags' to tcf_proto_ops only and do fl->ops->flags in
> ingress_enqueue()?
>
> Will respin.
nope. will take it back.
that doesn't work, since this check cannot be done in ingress_enqueue(),
because it sees the pointer to first filter only, so both TCQ_F_INGRESS
flag and CLS_REQUIRES_L2 flag need to be checked inside
tc_classify_compat() which is a lot worse than my current patch.
So I prefer this patch still :)
^ permalink raw reply
* Re: [PATCH net-next] tc: cls_bpf: make ingress and egress qdiscs consistent
From: Alexei Starovoitov @ 2015-04-03 23:04 UTC (permalink / raw)
To: Daniel Borkmann, David S. Miller
Cc: Jiri Pirko, Jamal Hadi Salim, linux-api-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <551F1A14.7080205-FeC+5ew28dpmcu3hnIyYJQ@public.gmane.org>
On 4/3/15 3:54 PM, Daniel Borkmann wrote:
> On 04/04/2015 12:17 AM, Alexei Starovoitov wrote:
> ...
>> 1. there shouldn't be a choice at all for bpf. Because not pulling l2
>> means it's bug.
>
> Yep, correct. You would also loose context for a possible dissection,
> at best you only have skb->protocol.
>
>> 2. adding a flag means adding it to iproute2 with default off and making
>> users forgetting it from time to time and have no way of knowing why
>> their programs all of a sudden stopped working.
>>
>> classic falls under the same rules. It doesn't make sense at all to run
>> a program on packet without L2 header. It's very odd both for classic
>> and extended programs.
>
> Yep.
>
>> Two 'if' conditions in critical path is bogus argument, since these
>> checks would be there in ingress as well. Same critical path.
>
> Why bogus? There would be no such test on the normal egress path,
> where this is irrelevant. I wasn't talking about ingress here.
>
> I see the point regarding the user option. So, why not adding a flag
> to tcf_proto_ops a la `.flags = CLS_REQUIRES_L2` that gets propagated
> to tcf_proto, and only ingress_enqueue() would need to test if the
> classifier imposes that requirement, so it can push/pull.
ok. that sounds better, but neither tcf_proto nor tcf_proto_ops have
'flags' field today... well, I guess it's time to add flags there.
Probably add 'flags' to tcf_proto_ops only and do fl->ops->flags in
ingress_enqueue()?
Will respin.
^ permalink raw reply
* Re: [PATCH net-next] tc: cls_bpf: make ingress and egress qdiscs consistent
From: Daniel Borkmann @ 2015-04-03 22:54 UTC (permalink / raw)
To: Alexei Starovoitov, David S. Miller
Cc: Jiri Pirko, Jamal Hadi Salim, linux-api, netdev
In-Reply-To: <551F1177.7090902@plumgrid.com>
On 04/04/2015 12:17 AM, Alexei Starovoitov wrote:
...
> 1. there shouldn't be a choice at all for bpf. Because not pulling l2
> means it's bug.
Yep, correct. You would also loose context for a possible dissection,
at best you only have skb->protocol.
> 2. adding a flag means adding it to iproute2 with default off and making
> users forgetting it from time to time and have no way of knowing why
> their programs all of a sudden stopped working.
>
> classic falls under the same rules. It doesn't make sense at all to run
> a program on packet without L2 header. It's very odd both for classic
> and extended programs.
Yep.
> Two 'if' conditions in critical path is bogus argument, since these
> checks would be there in ingress as well. Same critical path.
Why bogus? There would be no such test on the normal egress path,
where this is irrelevant. I wasn't talking about ingress here.
I see the point regarding the user option. So, why not adding a flag
to tcf_proto_ops a la `.flags = CLS_REQUIRES_L2` that gets propagated
to tcf_proto, and only ingress_enqueue() would need to test if the
classifier imposes that requirement, so it can push/pull.
^ permalink raw reply
* Re: [PATCH net-next] tc: cls_bpf: make ingress and egress qdiscs consistent
From: Alexei Starovoitov @ 2015-04-03 22:17 UTC (permalink / raw)
To: Daniel Borkmann, David S. Miller
Cc: Jiri Pirko, Jamal Hadi Salim, linux-api-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <551F0FE2.8000502-FeC+5ew28dpmcu3hnIyYJQ@public.gmane.org>
On 4/3/15 3:10 PM, Daniel Borkmann wrote:
> On 04/03/2015 11:52 PM, Alexei Starovoitov wrote:
>> On 4/3/15 2:46 PM, Daniel Borkmann wrote:
>>> On 04/03/2015 11:16 PM, Alexei Starovoitov wrote:
>>>> BPF programs attached to ingress and egress qdiscs see inconsistent
>>>> skb->data.
>>>> For ingress L2 header is already pulled, whereas for egress it's
>>>> present.
>>>> That makes writing programs more difficult.
>>>> Make them consistent by pushing L2 before running the programs and
>>>> pulling
>>>> it back afterwards.
>>>> Similar approach is taken by skb_defer_rx_timestamp() which does
>>>> push/pull
>>>> before calling ptp_classify_raw()->BPF_PROG_RUN().
>>>>
>>>> Signed-off-by: Alexei Starovoitov <ast-uqk4Ao+rVK5Wk0Htik3J/w@public.gmane.org>
>>>
>>> Thanks for looking into this. This ends up going via ingress_enqueue(),
>>
>> yes.
>>
>>> right? Maybe it would be better to add a new netlink attribute for
>>> ingress qdisc there that sets a flag in ingress_qdisc_data to pull the
>>> header space before calling tc_classify() and restore it later on?
>>> So, it would be configurable from tc. Would that work?
>>
>> you mean a flag that will affect all classifiers? I'm not sure other
>> classifiers care. Noone complained for years. I think it would be
>> overdesign. Here the fix is trivial, which is my preference.
>
> But the 'defect' is actually on the ingress qdisc side, right, not
> the classifier itself ... so if we do this in the classifier, we add
> two extra branches to the output path, which would never be taken.
>
> Plus, other classifiers wanting to look into ethernet headers would
> then also need to pull from /within/ their classifier as well. What
> about classic BPF users?
>
> I don't think fixing this in ingress qdisc is overdesign, but rather
> the better place to fix it. ;)
Strongly disagree.
1. there shouldn't be a choice at all for bpf. Because not pulling l2
means it's bug.
2. adding a flag means adding it to iproute2 with default off and making
users forgetting it from time to time and have no way of knowing why
their programs all of a sudden stopped working.
classic falls under the same rules. It doesn't make sense at all to run
a program on packet without L2 header. It's very odd both for classic
and extended programs.
Two 'if' conditions in critical path is bogus argument, since these
checks would be there in ingress as well. Same critical path.
^ permalink raw reply
* Re: [PATCH v5 08/15] clockevents/drivers: Add STM32 Timer driver
From: Andy Shevchenko @ 2015-04-03 22:14 UTC (permalink / raw)
To: Maxime Coquelin
Cc: Uwe Kleine-König, Andreas Färber, Geert Uytterhoeven,
Rob Herring, Philipp Zabel, Linus Walleij, Arnd Bergmann,
Stefan Agner, Peter Meerwald, Paul Bolle, Peter Hurley,
cw00.choi-Sze3O3UU22JBDgjK7y7TUQ, Russell King, Daniel Lezcano,
Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
Kumar Gala, Thomas Gleixner, Greg Kroah-Hartman, Jiri Slaby
In-Reply-To: <CAHp75VfPn_+sg_1iR_CdR2KuTyWcR+SKFsuHCbCkCKB0Oeqgfg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
On Sat, Apr 4, 2015 at 1:09 AM, Andy Shevchenko
<andy.shevchenko-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> On Fri, Apr 3, 2015 at 8:01 PM, Maxime Coquelin
> <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
>> STM32 MCUs feature 16 and 32 bits general purpose timers with prescalers.
>> The drivers detects whether the time is 16 or 32 bits, and applies a
>> 1024 prescaler value if it is 16 bits.
[]
>> + pr_err("failed to get clock for clockevent (%d)\n", ret);
>
> Why not dev_err(); ?
Understood, because it's device tree with lack of something like of_err();
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* Re: [PATCH net-next] tc: cls_bpf: make ingress and egress qdiscs consistent
From: Daniel Borkmann @ 2015-04-03 22:10 UTC (permalink / raw)
To: Alexei Starovoitov, David S. Miller
Cc: Jiri Pirko, Jamal Hadi Salim, linux-api-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <551F0B96.2090403-uqk4Ao+rVK5Wk0Htik3J/w@public.gmane.org>
On 04/03/2015 11:52 PM, Alexei Starovoitov wrote:
> On 4/3/15 2:46 PM, Daniel Borkmann wrote:
>> On 04/03/2015 11:16 PM, Alexei Starovoitov wrote:
>>> BPF programs attached to ingress and egress qdiscs see inconsistent
>>> skb->data.
>>> For ingress L2 header is already pulled, whereas for egress it's present.
>>> That makes writing programs more difficult.
>>> Make them consistent by pushing L2 before running the programs and
>>> pulling
>>> it back afterwards.
>>> Similar approach is taken by skb_defer_rx_timestamp() which does
>>> push/pull
>>> before calling ptp_classify_raw()->BPF_PROG_RUN().
>>>
>>> Signed-off-by: Alexei Starovoitov <ast-uqk4Ao+rVK5Wk0Htik3J/w@public.gmane.org>
>>
>> Thanks for looking into this. This ends up going via ingress_enqueue(),
>
> yes.
>
>> right? Maybe it would be better to add a new netlink attribute for
>> ingress qdisc there that sets a flag in ingress_qdisc_data to pull the
>> header space before calling tc_classify() and restore it later on?
>> So, it would be configurable from tc. Would that work?
>
> you mean a flag that will affect all classifiers? I'm not sure other
> classifiers care. Noone complained for years. I think it would be
> overdesign. Here the fix is trivial, which is my preference.
But the 'defect' is actually on the ingress qdisc side, right, not
the classifier itself ... so if we do this in the classifier, we add
two extra branches to the output path, which would never be taken.
Plus, other classifiers wanting to look into ethernet headers would
then also need to pull from /within/ their classifier as well. What
about classic BPF users?
I don't think fixing this in ingress qdisc is overdesign, but rather
the better place to fix it. ;)
^ permalink raw reply
* Re: [PATCH v5 08/15] clockevents/drivers: Add STM32 Timer driver
From: Andy Shevchenko @ 2015-04-03 22:09 UTC (permalink / raw)
To: Maxime Coquelin
Cc: Uwe Kleine-König, Andreas Färber, Geert Uytterhoeven,
Rob Herring, Philipp Zabel, Linus Walleij, Arnd Bergmann,
Stefan Agner, Peter Meerwald, Paul Bolle, Peter Hurley, cw00.choi,
Russell King, Daniel Lezcano, Jonathan Corbet, Pawel Moll,
Mark Rutland, Ian Campbell, Kumar Gala, Thomas Gleixner,
Greg Kroah-Hartman, Jiri Slaby
In-Reply-To: <1428080481-18591-9-git-send-email-mcoquelin.stm32@gmail.com>
On Fri, Apr 3, 2015 at 8:01 PM, Maxime Coquelin
<mcoquelin.stm32@gmail.com> wrote:
> STM32 MCUs feature 16 and 32 bits general purpose timers with prescalers.
> The drivers detects whether the time is 16 or 32 bits, and applies a
> 1024 prescaler value if it is 16 bits.
>
Few comments below.
> Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
> Tested-by: Chanwoo Choi <cw00.choi@samsung.com>
> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> ---
> drivers/clocksource/Kconfig | 8 ++
> drivers/clocksource/Makefile | 1 +
> drivers/clocksource/timer-stm32.c | 184 ++++++++++++++++++++++++++++++++++++++
> 3 files changed, 193 insertions(+)
> create mode 100644 drivers/clocksource/timer-stm32.c
>
> diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
> index b82e58b..519304b 100644
> --- a/drivers/clocksource/Kconfig
> +++ b/drivers/clocksource/Kconfig
> @@ -101,6 +101,14 @@ config CLKSRC_EFM32
> Support to use the timers of EFM32 SoCs as clock source and clock
> event device.
>
> +config CLKSRC_STM32
> + bool "Clocksource for STM32 SoCs" if !ARCH_STM32
> + depends on OF && ARM && (ARCH_STM32 || COMPILE_TEST)
> + select CLKSRC_MMIO
> + default ARCH_STM32
> + help
> + Support to use the timers of STM32 SoCs as clock event device.
> +
> config ARM_ARCH_TIMER
> bool
> select CLKSRC_OF if OF
> diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
> index 1c9a643..525dafe 100644
> --- a/drivers/clocksource/Makefile
> +++ b/drivers/clocksource/Makefile
> @@ -35,6 +35,7 @@ obj-$(CONFIG_ARCH_NSPIRE) += zevio-timer.o
> obj-$(CONFIG_ARCH_BCM_MOBILE) += bcm_kona_timer.o
> obj-$(CONFIG_CADENCE_TTC_TIMER) += cadence_ttc_timer.o
> obj-$(CONFIG_CLKSRC_EFM32) += time-efm32.o
> +obj-$(CONFIG_CLKSRC_STM32) += timer-stm32.o
> obj-$(CONFIG_CLKSRC_EXYNOS_MCT) += exynos_mct.o
> obj-$(CONFIG_CLKSRC_SAMSUNG_PWM) += samsung_pwm_timer.o
> obj-$(CONFIG_FSL_FTM_TIMER) += fsl_ftm_timer.o
> diff --git a/drivers/clocksource/timer-stm32.c b/drivers/clocksource/timer-stm32.c
> new file mode 100644
> index 0000000..fad2e2e
> --- /dev/null
> +++ b/drivers/clocksource/timer-stm32.c
> @@ -0,0 +1,184 @@
> +/*
> + * Copyright (C) Maxime Coquelin 2015
> + * Author: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> + * License terms: GNU General Public License (GPL), version 2
> + *
> + * Inspired by time-efm32.c from Uwe Kleine-Koenig
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/clocksource.h>
> +#include <linux/clockchips.h>
> +#include <linux/irq.h>
> +#include <linux/interrupt.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/clk.h>
> +#include <linux/reset.h>
> +
> +#define TIM_CR1 0x00
> +#define TIM_DIER 0x0c
> +#define TIM_SR 0x10
> +#define TIM_EGR 0x14
> +#define TIM_PSC 0x28
> +#define TIM_ARR 0x2c
> +
> +#define TIM_CR1_CEN BIT(0)
> +#define TIM_CR1_OPM BIT(3)
> +#define TIM_CR1_ARPE BIT(7)
> +
> +#define TIM_DIER_UIE BIT(0)
> +
> +#define TIM_SR_UIF BIT(0)
> +
> +#define TIM_EGR_UG BIT(0)
> +
> +struct stm32_clock_event_ddata {
> + struct clock_event_device evtdev;
> + unsigned periodic_top;
> + void __iomem *base;
> +};
> +
> +static void stm32_clock_event_set_mode(enum clock_event_mode mode,
> + struct clock_event_device *evtdev)
> +{
> + struct stm32_clock_event_ddata *data =
> + container_of(evtdev, struct stm32_clock_event_ddata, evtdev);
> + void *base = data->base;
> +
> + switch (mode) {
> + case CLOCK_EVT_MODE_PERIODIC:
> + writel_relaxed(data->periodic_top, base + TIM_ARR);
> + writel_relaxed(TIM_CR1_ARPE | TIM_CR1_CEN, base + TIM_CR1);
> + break;
> +
> + case CLOCK_EVT_MODE_ONESHOT:
> + default:
> + writel_relaxed(0, base + TIM_CR1);
> + break;
> + }
> +}
> +
> +static int stm32_clock_event_set_next_event(unsigned long evt,
> + struct clock_event_device *evtdev)
> +{
> + struct stm32_clock_event_ddata *data =
> + container_of(evtdev, struct stm32_clock_event_ddata, evtdev);
> +
> + writel_relaxed(evt, data->base + TIM_ARR);
> + writel_relaxed(TIM_CR1_ARPE | TIM_CR1_OPM | TIM_CR1_CEN,
> + data->base + TIM_CR1);
> +
> + return 0;
> +}
> +
> +static irqreturn_t stm32_clock_event_handler(int irq, void *dev_id)
> +{
> + struct stm32_clock_event_ddata *data = dev_id;
> +
> + writel_relaxed(0, data->base + TIM_SR);
> +
> + data->evtdev.event_handler(&data->evtdev);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static struct stm32_clock_event_ddata clock_event_ddata = {
> + .evtdev = {
> + .name = "stm32 clockevent",
> + .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
> + .set_mode = stm32_clock_event_set_mode,
> + .set_next_event = stm32_clock_event_set_next_event,
> + .rating = 200,
> + },
> +};
> +
> +static void __init stm32_clockevent_init(struct device_node *np)
> +{
> + struct stm32_clock_event_ddata *data = &clock_event_ddata;
> + struct clk *clk;
> + struct reset_control *rstc;
> + unsigned long rate, max_delta;
> + int irq, ret, bits, prescaler = 1;
> +
> + clk = of_clk_get(np, 0);
> + if (IS_ERR(clk)) {
> + ret = PTR_ERR(clk);
> + pr_err("failed to get clock for clockevent (%d)\n", ret);
Why not dev_err(); ?
> + goto err_clk_get;
> + }
> +
> + ret = clk_prepare_enable(clk);
> + if (ret) {
> + pr_err("failed to enable timer clock for clockevent (%d)\n",
> + ret);
Ditto.
> + goto err_clk_enable;
> + }
> +
> + rate = clk_get_rate(clk);
> +
> + rstc = of_reset_control_get(np, NULL);
> + if (!IS_ERR(rstc)) {
> + reset_control_assert(rstc);
> + reset_control_deassert(rstc);
> + }
> +
> + data->base = of_iomap(np, 0);
> + if (!data->base) {
> + pr_err("failed to map registers for clockevent\n");
Ditto.
> + goto err_iomap;
> + }
> +
> + irq = irq_of_parse_and_map(np, 0);
> + if (!irq) {
> + pr_err("%s: failed to get irq.\n", np->full_name);
Ditto.
> + goto err_get_irq;
> + }
> +
> + /* Detect whether the timer is 16 or 32 bits */
> + writel_relaxed(~0UL, data->base + TIM_ARR);
> + max_delta = readl_relaxed(data->base + TIM_ARR);
> + if (max_delta == ~0UL) {
> + prescaler = 1;
> + bits = 32;
> + } else {
> + prescaler = 1024;
> + bits = 16;
> + }
> + writel_relaxed(0, data->base + TIM_ARR);
> +
> + writel_relaxed(prescaler - 1, data->base + TIM_PSC);
> + writel_relaxed(TIM_EGR_UG, data->base + TIM_EGR);
> + writel_relaxed(TIM_DIER_UIE, data->base + TIM_DIER);
> + writel_relaxed(0, data->base + TIM_SR);
> +
> + data->periodic_top = DIV_ROUND_CLOSEST(rate, prescaler * HZ);
> +
> + clockevents_config_and_register(&data->evtdev,
> + DIV_ROUND_CLOSEST(rate, prescaler),
> + 0x1, max_delta);
> +
> + ret = request_irq(irq, stm32_clock_event_handler, IRQF_TIMER,
> + "stm32 clockevent", data);
> + if (ret) {
> + pr_err("%s: failed to request irq.\n", np->full_name);
Ditto.
> + goto err_get_irq;
> + }
> +
> + pr_info("%s: STM32 clockevent driver initialized (%d bits)\n",
> + np->full_name, bits);
dev_info(); ?
> +
> + return;
> +
> +err_get_irq:
> + iounmap(data->base);
> +err_iomap:
> + clk_disable_unprepare(clk);
> +err_clk_enable:
> + clk_put(clk);
> +err_clk_get:
> + return;
> +}
> +
> +CLOCKSOURCE_OF_DECLARE(stm32, "st,stm32-timer", stm32_clockevent_init);
> --
> 1.9.1
>
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* Re: [PATCH v5 10/15] serial: stm32-usart: Add STM32 USART Driver
From: Andy Shevchenko @ 2015-04-03 22:04 UTC (permalink / raw)
To: Maxime Coquelin
Cc: Uwe Kleine-König, Andreas Färber, Geert Uytterhoeven,
Rob Herring, Philipp Zabel, Linus Walleij, Arnd Bergmann,
Stefan Agner, Peter Meerwald, Paul Bolle, Peter Hurley, cw00.choi,
Russell King, Daniel Lezcano, Jonathan Corbet, Pawel Moll,
Mark Rutland, Ian Campbell, Kumar Gala, Thomas Gleixner,
Greg Kroah-Hartman, Jiri Slaby
In-Reply-To: <1428080481-18591-11-git-send-email-mcoquelin.stm32@gmail.com>
On Fri, Apr 3, 2015 at 8:01 PM, Maxime Coquelin
<mcoquelin.stm32@gmail.com> wrote:
> This drivers adds support to the STM32 USART controller, which is a
> standard serial driver.
>
Few minor comments.
> Tested-by: Chanwoo Choi <cw00.choi@samsung.com>
> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> ---
> drivers/tty/serial/Kconfig | 17 +
> drivers/tty/serial/Makefile | 1 +
> drivers/tty/serial/stm32-usart.c | 736 +++++++++++++++++++++++++++++++++++++++
> include/uapi/linux/serial_core.h | 3 +
> 4 files changed, 757 insertions(+)
> create mode 100644 drivers/tty/serial/stm32-usart.c
>
> diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
> index d2501f0..880cb4f 100644
> --- a/drivers/tty/serial/Kconfig
> +++ b/drivers/tty/serial/Kconfig
> @@ -1611,6 +1611,23 @@ config SERIAL_SPRD_CONSOLE
> with "earlycon" on the kernel command line. The console is
> enabled when early_param is processed.
>
> +config SERIAL_STM32
> + tristate "STMicroelectronics STM32 serial port support"
> + select SERIAL_CORE
> + depends on ARM || COMPILE_TEST
> + help
> + This driver is for the on-chip Serial Controller on
> + STMicroelectronics STM32 MCUs.
> + USART supports Rx & Tx functionality.
> + It support all industry standard baud rates.
> +
> + If unsure, say N.
> +
> +config SERIAL_STM32_CONSOLE
> + bool "Support for console on STM32"
> + depends on SERIAL_STM32=y
> + select SERIAL_CORE_CONSOLE
> +
> endmenu
>
> config SERIAL_MCTRL_GPIO
> diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
> index 599be4b..67c5023 100644
> --- a/drivers/tty/serial/Makefile
> +++ b/drivers/tty/serial/Makefile
> @@ -95,6 +95,7 @@ obj-$(CONFIG_SERIAL_FSL_LPUART) += fsl_lpuart.o
> obj-$(CONFIG_SERIAL_CONEXANT_DIGICOLOR) += digicolor-usart.o
> obj-$(CONFIG_SERIAL_MEN_Z135) += men_z135_uart.o
> obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o
> +obj-$(CONFIG_SERIAL_STM32) += stm32-usart.o
>
> # GPIOLIB helpers for modem control lines
> obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o
> diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
> new file mode 100644
> index 0000000..61e0e19
> --- /dev/null
> +++ b/drivers/tty/serial/stm32-usart.c
> @@ -0,0 +1,736 @@
> +/*
> + * Copyright (C) Maxime Coquelin 2015
> + * Author: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> + * License terms: GNU General Public License (GPL), version 2
> + *
> + * Inspired by st-asc.c from STMicroelectronics (c)
> + */
> +
> +#if defined(CONFIG_SERIAL_STM32_USART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
> +#define SUPPORT_SYSRQ
> +#endif
> +
> +#include <linux/module.h>
> +#include <linux/serial.h>
> +#include <linux/console.h>
> +#include <linux/sysrq.h>
> +#include <linux/platform_device.h>
> +#include <linux/io.h>
> +#include <linux/irq.h>
> +#include <linux/tty.h>
> +#include <linux/tty_flip.h>
> +#include <linux/delay.h>
> +#include <linux/spinlock.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/of.h>
> +#include <linux/of_platform.h>
> +#include <linux/serial_core.h>
> +#include <linux/clk.h>
> +
> +#define DRIVER_NAME "stm32-usart"
> +
> +/* Register offsets */
> +#define USART_SR 0x00
> +#define USART_DR 0x04
> +#define USART_BRR 0x08
> +#define USART_CR1 0x0c
> +#define USART_CR2 0x10
> +#define USART_CR3 0x14
> +#define USART_GTPR 0x18
> +
> +/* USART_SR */
> +#define USART_SR_PE BIT(0)
> +#define USART_SR_FE BIT(1)
> +#define USART_SR_NF BIT(2)
> +#define USART_SR_ORE BIT(3)
> +#define USART_SR_IDLE BIT(4)
> +#define USART_SR_RXNE BIT(5)
> +#define USART_SR_TC BIT(6)
> +#define USART_SR_TXE BIT(7)
> +#define USART_SR_LBD BIT(8)
> +#define USART_SR_CTS BIT(9)
> +#define USART_SR_ERR_MASK (USART_SR_LBD | USART_SR_ORE | \
> + USART_SR_FE | USART_SR_PE)
> +/* Dummy bits */
> +#define USART_SR_DUMMY_RX BIT(16)
> +
> +/* USART_DR */
> +#define USART_DR_MASK GENMASK(8, 0)
> +
> +/* USART_BRR */
> +#define USART_BRR_DIV_F_MASK GENMASK(3, 0)
> +#define USART_BRR_DIV_M_MASK GENMASK(15, 4)
> +#define USART_BRR_DIV_M_SHIFT 4
> +
> +/* USART_CR1 */
> +#define USART_CR1_SBK BIT(0)
> +#define USART_CR1_RWU BIT(1)
> +#define USART_CR1_RE BIT(2)
> +#define USART_CR1_TE BIT(3)
> +#define USART_CR1_IDLEIE BIT(4)
> +#define USART_CR1_RXNEIE BIT(5)
> +#define USART_CR1_TCIE BIT(6)
> +#define USART_CR1_TXEIE BIT(7)
> +#define USART_CR1_PEIE BIT(8)
> +#define USART_CR1_PS BIT(9)
> +#define USART_CR1_PCE BIT(10)
> +#define USART_CR1_WAKE BIT(11)
> +#define USART_CR1_M BIT(12)
> +#define USART_CR1_UE BIT(13)
> +#define USART_CR1_OVER8 BIT(15)
> +#define USART_CR1_IE_MASK GENMASK(8, 4)
> +
> +/* USART_CR2 */
> +#define USART_CR2_ADD_MASK GENMASK(3, 0)
> +#define USART_CR2_LBDL BIT(5)
> +#define USART_CR2_LBDIE BIT(6)
> +#define USART_CR2_LBCL BIT(8)
> +#define USART_CR2_CPHA BIT(9)
> +#define USART_CR2_CPOL BIT(10)
> +#define USART_CR2_CLKEN BIT(11)
> +#define USART_CR2_STOP_2B BIT(13)
> +#define USART_CR2_STOP_MASK GENMASK(13, 12)
> +#define USART_CR2_LINEN BIT(14)
> +
> +/* USART_CR3 */
> +#define USART_CR3_EIE BIT(0)
> +#define USART_CR3_IREN BIT(1)
> +#define USART_CR3_IRLP BIT(2)
> +#define USART_CR3_HDSEL BIT(3)
> +#define USART_CR3_NACK BIT(4)
> +#define USART_CR3_SCEN BIT(5)
> +#define USART_CR3_DMAR BIT(6)
> +#define USART_CR3_DMAT BIT(7)
> +#define USART_CR3_RTSE BIT(8)
> +#define USART_CR3_CTSE BIT(9)
> +#define USART_CR3_CTSIE BIT(10)
> +#define USART_CR3_ONEBIT BIT(11)
> +
> +/* USART_GTPR */
> +#define USART_GTPR_PSC_MASK GENMASK(7, 0)
> +#define USART_GTPR_GT_MASK GENMASK(15, 8)
> +
> +#define DRIVER_NAME "stm32-usart"
> +#define STM32_SERIAL_NAME "ttyS"
> +#define STM32_MAX_PORTS 6
> +
> +struct stm32_port {
> + struct uart_port port;
> + struct clk *clk;
> + bool hw_flow_control;
> +};
> +
> +static struct stm32_port stm32_ports[STM32_MAX_PORTS];
> +static struct uart_driver stm32_usart_driver;
> +
> +static void stm32_stop_tx(struct uart_port *port);
> +
> +static inline struct stm32_port *to_stm32_port(struct uart_port *port)
> +{
> + return container_of(port, struct stm32_port, port);
> +}
> +
> +static void stm32_set_bits(struct uart_port *port, u32 reg, u32 bits)
> +{
> + u32 val;
> +
> + val = readl_relaxed(port->membase + reg);
> + val |= bits;
> + writel_relaxed(val, port->membase + reg);
> +}
> +
> +static void stm32_clr_bits(struct uart_port *port, u32 reg, u32 bits)
> +{
> + u32 val;
> +
> + val = readl_relaxed(port->membase + reg);
> + val &= ~bits;
> + writel_relaxed(val, port->membase + reg);
> +}
> +
> +static void stm32_receive_chars(struct uart_port *port)
> +{
> + struct tty_port *tport = &port->state->port;
> + unsigned long c;
> + u32 sr;
> + char flag;
> +
> + if (port->irq_wake)
> + pm_wakeup_event(tport->tty->dev, 0);
> +
> + while ((sr = readl_relaxed(port->membase + USART_SR)) & USART_SR_RXNE) {
> + sr |= USART_SR_DUMMY_RX;
> + c = readl_relaxed(port->membase + USART_DR);
> + flag = TTY_NORMAL;
> + port->icount.rx++;
> +
> + if (sr & USART_SR_ERR_MASK) {
> + if (sr & USART_SR_LBD) {
> + port->icount.brk++;
> + if (uart_handle_break(port))
> + continue;
> + } else if (sr & USART_SR_ORE) {
> + port->icount.overrun++;
> + } else if (sr & USART_SR_PE) {
> + port->icount.parity++;
> + } else if (sr & USART_SR_FE) {
> + port->icount.frame++;
> + }
> +
> + sr &= port->read_status_mask;
> +
> + if (sr & USART_SR_LBD)
> + flag = TTY_BREAK;
> + else if (sr & USART_SR_PE)
> + flag = TTY_PARITY;
> + else if (sr & USART_SR_FE)
> + flag = TTY_FRAME;
> + }
> +
> + if (uart_handle_sysrq_char(port, c))
> + continue;
> + uart_insert_char(port, sr, USART_SR_ORE, c, flag);
> + }
> +
> + spin_unlock(&port->lock);
> + tty_flip_buffer_push(tport);
> + spin_lock(&port->lock);
> +}
> +
> +static void stm32_transmit_chars(struct uart_port *port)
> +{
> + struct circ_buf *xmit = &port->state->xmit;
> +
> + if (port->x_char) {
> + writel_relaxed(port->x_char, port->membase + USART_DR);
> + port->x_char = 0;
> + port->icount.tx++;
> + return;
> + }
> +
> + if (uart_tx_stopped(port)) {
> + stm32_stop_tx(port);
> + return;
> + }
> +
> + if (uart_circ_empty(xmit)) {
> + stm32_stop_tx(port);
> + return;
> + }
> +
> + writel_relaxed(xmit->buf[xmit->tail], port->membase + USART_DR);
> + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
> + port->icount.tx++;
> +
> + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
> + uart_write_wakeup(port);
> +
> + if (uart_circ_empty(xmit))
> + stm32_stop_tx(port);
> +}
> +
> +static irqreturn_t stm32_interrupt(int irq, void *ptr)
> +{
> + struct uart_port *port = ptr;
> + u32 sr;
> +
> + spin_lock(&port->lock);
> +
> + sr = readl_relaxed(port->membase + USART_SR);
> +
> + if (sr & USART_SR_RXNE)
> + stm32_receive_chars(port);
> +
> + if (sr & USART_SR_TXE)
> + stm32_transmit_chars(port);
> +
> + spin_unlock(&port->lock);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static unsigned int stm32_tx_empty(struct uart_port *port)
> +{
> + return readl_relaxed(port->membase + USART_SR) & USART_SR_TXE;
> +}
> +
> +static void stm32_set_mctrl(struct uart_port *port, unsigned int mctrl)
> +{
> + if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS))
> + stm32_set_bits(port, USART_CR3, USART_CR3_RTSE);
> + else
> + stm32_clr_bits(port, USART_CR3, USART_CR3_RTSE);
> +}
> +
> +static unsigned int stm32_get_mctrl(struct uart_port *port)
> +{
> + /* This routine is used to get signals of: DCD, DSR, RI, and CTS */
> + return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
> +}
> +
> +/* Transmit stop */
> +static void stm32_stop_tx(struct uart_port *port)
> +{
> + stm32_clr_bits(port, USART_CR1, USART_CR1_TXEIE);
> +}
> +
> +
Unneeded empty line.
> +/* There are probably characters waiting to be transmitted. */
> +static void stm32_start_tx(struct uart_port *port)
> +{
> + struct circ_buf *xmit = &port->state->xmit;
> +
> + if (uart_circ_empty(xmit))
> + return;
> +
> + stm32_set_bits(port, USART_CR1, USART_CR1_TXEIE | USART_CR1_TE);
> +}
> +
> +/* Throttle the remote when input buffer is about to overflow. */
> +static void stm32_throttle(struct uart_port *port)
> +{
> + unsigned long flags;
> +
> + spin_lock_irqsave(&port->lock, flags);
> + stm32_clr_bits(port, USART_CR1, USART_CR1_RXNEIE);
> + spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +/* Unthrottle the remote, the input buffer can now accept data. */
> +static void stm32_unthrottle(struct uart_port *port)
> +{
> + unsigned long flags;
> +
> + spin_lock_irqsave(&port->lock, flags);
> + stm32_set_bits(port, USART_CR1, USART_CR1_RXNEIE);
> + spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +/* Receive stop */
> +static void stm32_stop_rx(struct uart_port *port)
> +{
> + stm32_clr_bits(port, USART_CR1, USART_CR1_RXNEIE);
> +}
> +
> +/* Handle breaks - ignored by us */
> +static void stm32_break_ctl(struct uart_port *port, int break_state)
> +{
> +}
> +
> +static int stm32_startup(struct uart_port *port)
> +{
> + const char *name = to_platform_device(port->dev)->name;
> + u32 val;
> +
> + if (request_irq(port->irq, stm32_interrupt, IRQF_NO_SUSPEND,
> + name, port)) {
I think you have to propogate returned value, thus
ret = request_irq();
if (ret < 0)
return ret;
> + dev_err(port->dev, "cannot allocate irq %d\n", port->irq);
> + return -ENODEV;
> + }
> +
> + val = USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
> + stm32_set_bits(port, USART_CR1, val);
> +
> + return 0;
> +}
> +
> +static void stm32_shutdown(struct uart_port *port)
> +{
> + u32 val;
> +
> + val = USART_CR1_TXEIE | USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
> + stm32_set_bits(port, USART_CR1, val);
> +
> + free_irq(port->irq, port);
> +}
> +
> +static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
> + struct ktermios *old)
> +{
> + struct stm32_port *stm32_port = to_stm32_port(port);
> + unsigned int baud;
> + u32 usartdiv, mantissa, fraction, oversampling;
> + tcflag_t cflag = termios->c_cflag;
> + u32 cr1, cr2, cr3;
> + unsigned long flags;
> +
> + if (!stm32_port->hw_flow_control)
> + cflag &= ~CRTSCTS;
> +
> + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 8);
> +
> + spin_lock_irqsave(&port->lock, flags);
> +
> + /* Stop serial port and reset value */
> + writel_relaxed(0, port->membase + USART_CR1);
> +
> + cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_RXNEIE;
> +
> + if (cflag & CSTOPB)
> + cr2 = USART_CR2_STOP_2B;
> +
> + if (cflag & PARENB) {
> + cr1 |= USART_CR1_PCE;
> + if ((cflag & CSIZE) == CS8)
> + cr1 |= USART_CR1_M;
> + }
> +
> + if (cflag & PARODD)
> + cr1 |= USART_CR1_PS;
> +
> + port->status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS);
> + if (cflag & CRTSCTS) {
> + port->status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS;
> + cr3 = USART_CR3_CTSE;
> + }
> +
> + usartdiv = DIV_ROUND_CLOSEST(port->uartclk, baud);
> +
> + /*
> + * The USART supports 16 or 8 times oversampling.
> + * By default we prefer 16 times oversampling, so that the receiver
> + * has a better tolerance to clock deviations.
> + * 8 times oversampling is only used to achieve higher speeds.
> + */
> + if (usartdiv < 16) {
> + oversampling = 8;
> + stm32_set_bits(port, USART_CR1, USART_CR1_OVER8);
> + } else {
> + oversampling = 16;
> + stm32_clr_bits(port, USART_CR1, USART_CR1_OVER8);
> + }
> +
> + mantissa = (usartdiv / oversampling) << USART_BRR_DIV_M_SHIFT;
> + fraction = usartdiv % oversampling;
> + writel_relaxed(mantissa | fraction, port->membase + USART_BRR);
> +
> + uart_update_timeout(port, cflag, baud);
> +
> + port->read_status_mask = USART_SR_ORE;
> + if (termios->c_iflag & INPCK)
> + port->read_status_mask |= USART_SR_PE | USART_SR_FE;
> + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
> + port->read_status_mask |= USART_SR_LBD;
> +
> + /* Characters to ignore */
> + port->ignore_status_mask = 0;
> + if (termios->c_iflag & IGNPAR)
> + port->ignore_status_mask = USART_SR_PE | USART_SR_FE;
> + if (termios->c_iflag & IGNBRK) {
> + port->ignore_status_mask |= USART_SR_LBD;
> + /*
> + * If we're ignoring parity and break indicators,
> + * ignore overruns too (for real raw support).
> + */
> + if (termios->c_iflag & IGNPAR)
> + port->ignore_status_mask |= USART_SR_ORE;
> + }
> +
> + /* Ignore all characters if CREAD is not set */
> + if ((termios->c_cflag & CREAD) == 0)
> + port->ignore_status_mask |= USART_SR_DUMMY_RX;
> +
> + writel_relaxed(cr3, port->membase + USART_CR3);
> + writel_relaxed(cr2, port->membase + USART_CR2);
> + writel_relaxed(cr1, port->membase + USART_CR1);
> +
> + spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static const char *stm32_type(struct uart_port *port)
> +{
> + return (port->type == PORT_STM32) ? DRIVER_NAME : NULL;
> +}
> +
> +static void stm32_release_port(struct uart_port *port)
> +{
> +}
Doesn't core handle NULL-functions? If it does, remove such from the driver.
> +
> +static int stm32_request_port(struct uart_port *port)
> +{
> + return 0;
> +}
Ditto.
> +
> +static void stm32_config_port(struct uart_port *port, int flags)
> +{
> + if (flags & UART_CONFIG_TYPE)
> + port->type = PORT_STM32;
> +}
> +
> +static int
> +stm32_verify_port(struct uart_port *port, struct serial_struct *ser)
> +{
> + /* No user changeable parameters */
> + return -EINVAL;
> +}
> +
> +static void stm32_pm(struct uart_port *port, unsigned int state,
> + unsigned int oldstate)
> +{
> + struct stm32_port *stm32port = container_of(port,
> + struct stm32_port, port);
> + unsigned long flags = 0;
> +
> + switch (state) {
> + case UART_PM_STATE_ON:
> + clk_prepare_enable(stm32port->clk);
> + break;
> + case UART_PM_STATE_OFF:
> + spin_lock_irqsave(&port->lock, flags);
> + stm32_clr_bits(port, USART_CR1, USART_CR1_UE);
> + spin_unlock_irqrestore(&port->lock, flags);
> + clk_disable_unprepare(stm32port->clk);
> + break;
> + }
> +}
> +
> +static struct uart_ops stm32_uart_ops = {
> + .tx_empty = stm32_tx_empty,
> + .set_mctrl = stm32_set_mctrl,
> + .get_mctrl = stm32_get_mctrl,
> + .stop_tx = stm32_stop_tx,
> + .start_tx = stm32_start_tx,
> + .throttle = stm32_throttle,
> + .unthrottle = stm32_unthrottle,
> + .stop_rx = stm32_stop_rx,
> + .break_ctl = stm32_break_ctl,
> + .startup = stm32_startup,
> + .shutdown = stm32_shutdown,
> + .set_termios = stm32_set_termios,
> + .pm = stm32_pm,
> + .type = stm32_type,
> + .release_port = stm32_release_port,
> + .request_port = stm32_request_port,
> + .config_port = stm32_config_port,
> + .verify_port = stm32_verify_port,
> +};
> +
> +static int stm32_init_port(struct stm32_port *stm32port,
> + struct platform_device *pdev)
> +{
> + struct uart_port *port = &stm32port->port;
> + struct resource *res;
> + int ret;
> +
> + port->iotype = UPIO_MEM;
> + port->flags = UPF_BOOT_AUTOCONF;
> + port->ops = &stm32_uart_ops;
> + port->dev = &pdev->dev;
> + port->irq = platform_get_irq(pdev, 0);
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + port->membase = devm_ioremap_resource(&pdev->dev, res);
> + if (IS_ERR(port->membase))
> + return PTR_ERR(port->membase);
> + port->mapbase = res->start;
> +
> + spin_lock_init(&port->lock);
> +
> + stm32port->clk = devm_clk_get(&pdev->dev, NULL);
> + if (IS_ERR(stm32port->clk))
> + return PTR_ERR(stm32port->clk);
> +
> + /* Ensure that clk rate is correct by enabling the clk */
> + ret = clk_prepare_enable(stm32port->clk);
> + if (ret)
> + return ret;
> +
> + stm32port->port.uartclk = clk_get_rate(stm32port->clk);
> + if (!stm32port->port.uartclk)
> + ret = -EINVAL;
> +
> + clk_disable_unprepare(stm32port->clk);
> +
> + return ret;
> +}
> +
> +static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev)
> +{
> + struct device_node *np = pdev->dev.of_node;
> + int id;
> +
> + if (!np)
> + return NULL;
> +
> + id = of_alias_get_id(np, "serial");
> + if (id < 0)
> + id = 0;
> +
> + if (WARN_ON(id >= STM32_MAX_PORTS))
> + return NULL;
> +
> + stm32_ports[id].hw_flow_control = of_property_read_bool(np,
> + "st,hw-flow-control");
> + stm32_ports[id].port.line = id;
> + return &stm32_ports[id];
> +}
> +
> +#ifdef CONFIG_OF
> +static const struct of_device_id stm32_match[] = {
> + { .compatible = "st,stm32-usart", },
> + { .compatible = "st,stm32-uart", },
> + {},
> +};
> +
> +MODULE_DEVICE_TABLE(of, stm32_match);
> +#endif
> +
> +static int stm32_serial_probe(struct platform_device *pdev)
> +{
> + int ret;
> + struct stm32_port *stm32port;
> +
> + stm32port = stm32_of_get_stm32_port(pdev);
> + if (!stm32port)
> + return -ENODEV;
> +
> + ret = stm32_init_port(stm32port, pdev);
> + if (ret)
> + return ret;
> +
> + ret = uart_add_one_port(&stm32_usart_driver, &stm32port->port);
> + if (ret)
> + return ret;
> +
> + platform_set_drvdata(pdev, &stm32port->port);
> +
> + return 0;
> +}
> +
> +static int stm32_serial_remove(struct platform_device *pdev)
> +{
> + struct uart_port *port = platform_get_drvdata(pdev);
> +
> + return uart_remove_one_port(&stm32_usart_driver, port);
> +}
> +
> +
> +#ifdef CONFIG_SERIAL_STM32_CONSOLE
> +static void stm32_console_putchar(struct uart_port *port, int ch)
> +{
> + while (!(readl_relaxed(port->membase + USART_SR) & USART_SR_TXE))
> + cpu_relax();
> +
> + writel_relaxed(ch, port->membase + USART_DR);
> +}
> +
> +static void stm32_console_write(struct console *co, const char *s, unsigned cnt)
> +{
> + struct uart_port *port = &stm32_ports[co->index].port;
> + unsigned long flags;
> + u32 old_cr1, new_cr1;
> + int locked = 1;
> +
> + if (oops_in_progress) {
> + locked = spin_trylock_irqsave(&port->lock, flags);
> + } else {
> + locked = 1;
> + spin_lock_irqsave(&port->lock, flags);
> + }
> +
> + /* Save and disable interrupts */
> + old_cr1 = readl_relaxed(port->membase + USART_CR1);
> + new_cr1 = old_cr1 & ~USART_CR1_IE_MASK;
> + writel_relaxed(new_cr1, port->membase + USART_CR1);
> +
> + uart_console_write(port, s, cnt, stm32_console_putchar);
> +
> + /* Restore interrupt state */
> + writel_relaxed(old_cr1, port->membase + USART_CR1);
> +
> + if (locked)
> + spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static int stm32_console_setup(struct console *co, char *options)
> +{
> + struct stm32_port *stm32port;
> + int baud = 9600;
> + int bits = 8;
> + int parity = 'n';
> + int flow = 'n';
> +
> + if (co->index >= STM32_MAX_PORTS)
> + return -ENODEV;
> +
> + stm32port = &stm32_ports[co->index];
> +
> + /*
> + * This driver does not support early console initialization
> + * (use ARM early printk support instead), so we only expect
> + * this to be called during the uart port registration when the
> + * driver gets probed and the port should be mapped at that point.
> + */
> + if (stm32port->port.mapbase == 0 || stm32port->port.membase == NULL)
> + return -ENXIO;
> +
> + if (options)
> + uart_parse_options(options, &baud, &parity, &bits, &flow);
> +
> + return uart_set_options(&stm32port->port, co, baud, parity, bits, flow);
> +}
> +
> +static struct console stm32_console = {
> + .name = STM32_SERIAL_NAME,
> + .device = uart_console_device,
> + .write = stm32_console_write,
> + .setup = stm32_console_setup,
> + .flags = CON_PRINTBUFFER,
> + .index = -1,
> + .data = &stm32_usart_driver,
> +};
> +
> +#define STM32_SERIAL_CONSOLE (&stm32_console)
> +
> +#else
> +#define STM32_SERIAL_CONSOLE NULL
> +#endif /* CONFIG_SERIAL_STM32_CONSOLE */
> +
> +static struct uart_driver stm32_usart_driver = {
> + .driver_name = DRIVER_NAME,
> + .dev_name = STM32_SERIAL_NAME,
> + .major = 0,
> + .minor = 0,
> + .nr = STM32_MAX_PORTS,
> + .cons = STM32_SERIAL_CONSOLE,
> +};
> +
> +static struct platform_driver stm32_serial_driver = {
> + .probe = stm32_serial_probe,
> + .remove = stm32_serial_remove,
> + .driver = {
> + .name = DRIVER_NAME,
> + .of_match_table = of_match_ptr(stm32_match),
> + },
> +};
> +
> +static int __init usart_init(void)
> +{
> + static char banner[] __initdata = "STM32 USART driver initialized";
> + int ret;
> +
> + pr_info("%s\n", banner);
> +
> + ret = uart_register_driver(&stm32_usart_driver);
> + if (ret)
> + return ret;
> +
> + ret = platform_driver_register(&stm32_serial_driver);
> + if (ret)
> + uart_unregister_driver(&stm32_usart_driver);
> +
> + return ret;
> +}
> +
> +static void __exit usart_exit(void)
> +{
> + platform_driver_unregister(&stm32_serial_driver);
> + uart_unregister_driver(&stm32_usart_driver);
> +}
> +
> +module_init(usart_init);
> +module_exit(usart_exit);
> +
> +MODULE_ALIAS("platform:" DRIVER_NAME);
> +MODULE_DESCRIPTION("STMicroelectronics STM32 serial port driver");
> +MODULE_LICENSE("GPL v2");
> diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
> index b212281..93ba148 100644
> --- a/include/uapi/linux/serial_core.h
> +++ b/include/uapi/linux/serial_core.h
> @@ -258,4 +258,7 @@
> /* Cris v10 / v32 SoC */
> #define PORT_CRIS 112
>
> +/* STM32 USART */
> +#define PORT_STM32 113
> +
> #endif /* _UAPILINUX_SERIAL_CORE_H */
> --
> 1.9.1
>
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* Re: [PATCH net-next] tc: cls_bpf: make ingress and egress qdiscs consistent
From: Alexei Starovoitov @ 2015-04-03 21:52 UTC (permalink / raw)
To: Daniel Borkmann, David S. Miller
Cc: Jiri Pirko, Jamal Hadi Salim, linux-api-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <551F0A1B.3000100-FeC+5ew28dpmcu3hnIyYJQ@public.gmane.org>
On 4/3/15 2:46 PM, Daniel Borkmann wrote:
> On 04/03/2015 11:16 PM, Alexei Starovoitov wrote:
>> BPF programs attached to ingress and egress qdiscs see inconsistent
>> skb->data.
>> For ingress L2 header is already pulled, whereas for egress it's present.
>> That makes writing programs more difficult.
>> Make them consistent by pushing L2 before running the programs and
>> pulling
>> it back afterwards.
>> Similar approach is taken by skb_defer_rx_timestamp() which does
>> push/pull
>> before calling ptp_classify_raw()->BPF_PROG_RUN().
>>
>> Signed-off-by: Alexei Starovoitov <ast-uqk4Ao+rVK5Wk0Htik3J/w@public.gmane.org>
>
> Thanks for looking into this. This ends up going via ingress_enqueue(),
yes.
> right? Maybe it would be better to add a new netlink attribute for
> ingress qdisc there that sets a flag in ingress_qdisc_data to pull the
> header space before calling tc_classify() and restore it later on?
> So, it would be configurable from tc. Would that work?
you mean a flag that will affect all classifiers? I'm not sure other
classifiers care. Noone complained for years. I think it would be
overdesign. Here the fix is trivial, which is my preference.
^ permalink raw reply
* Re: [PATCH net-next] tc: cls_bpf: make ingress and egress qdiscs consistent
From: Daniel Borkmann @ 2015-04-03 21:46 UTC (permalink / raw)
To: Alexei Starovoitov, David S. Miller
Cc: Jiri Pirko, Jamal Hadi Salim, linux-api-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1428095784-7091-1-git-send-email-ast-uqk4Ao+rVK5Wk0Htik3J/w@public.gmane.org>
On 04/03/2015 11:16 PM, Alexei Starovoitov wrote:
> BPF programs attached to ingress and egress qdiscs see inconsistent skb->data.
> For ingress L2 header is already pulled, whereas for egress it's present.
> That makes writing programs more difficult.
> Make them consistent by pushing L2 before running the programs and pulling
> it back afterwards.
> Similar approach is taken by skb_defer_rx_timestamp() which does push/pull
> before calling ptp_classify_raw()->BPF_PROG_RUN().
>
> Signed-off-by: Alexei Starovoitov <ast-uqk4Ao+rVK5Wk0Htik3J/w@public.gmane.org>
Thanks for looking into this. This ends up going via ingress_enqueue(),
right? Maybe it would be better to add a new netlink attribute for
ingress qdisc there that sets a flag in ingress_qdisc_data to pull the
header space before calling tc_classify() and restore it later on?
So, it would be configurable from tc. Would that work?
^ permalink raw reply
* [PATCH net-next] tc: cls_bpf: make ingress and egress qdiscs consistent
From: Alexei Starovoitov @ 2015-04-03 21:16 UTC (permalink / raw)
To: David S. Miller
Cc: Daniel Borkmann, Jiri Pirko, Jamal Hadi Salim, linux-api, netdev
BPF programs attached to ingress and egress qdiscs see inconsistent skb->data.
For ingress L2 header is already pulled, whereas for egress it's present.
That makes writing programs more difficult.
Make them consistent by pushing L2 before running the programs and pulling
it back afterwards.
Similar approach is taken by skb_defer_rx_timestamp() which does push/pull
before calling ptp_classify_raw()->BPF_PROG_RUN().
Signed-off-by: Alexei Starovoitov <ast@plumgrid.com>
---
Looks like noone has tried bpf with ingress qdisc before, otherwise this
problem would have been found sooner.
This patch is probably not needed for 'net', since tc+bpf infra only starting
to come alive.
net/sched/cls_bpf.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/net/sched/cls_bpf.c b/net/sched/cls_bpf.c
index 5c4171c5d2bd..b1cefd2037c9 100644
--- a/net/sched/cls_bpf.c
+++ b/net/sched/cls_bpf.c
@@ -66,6 +66,12 @@ static int cls_bpf_classify(struct sk_buff *skb, const struct tcf_proto *tp,
struct cls_bpf_prog *prog;
int ret = -1;
+ if (tp->q->flags & TCQ_F_INGRESS) {
+ if (skb_headroom(skb) < ETH_HLEN)
+ return -1;
+ __skb_push(skb, ETH_HLEN);
+ }
+
/* Needed here for accessing maps. */
rcu_read_lock();
list_for_each_entry_rcu(prog, &head->plist, link) {
@@ -86,6 +92,9 @@ static int cls_bpf_classify(struct sk_buff *skb, const struct tcf_proto *tp,
}
rcu_read_unlock();
+ if (tp->q->flags & TCQ_F_INGRESS)
+ __skb_pull(skb, ETH_HLEN);
+
return ret;
}
--
1.7.9.5
^ permalink raw reply related
* Re: [PATCH v5 10/15] serial: stm32-usart: Add STM32 USART Driver
From: Joe Perches @ 2015-04-03 17:43 UTC (permalink / raw)
To: Maxime Coquelin
Cc: u.kleine-koenig-bIcnvbaLZ9MEGnE8C9+IrQ, afaerber-l3A5Bk7waGM,
geert-Td1EMuHUCqxL1ZNQvxDV9g, Rob Herring, Philipp Zabel,
Linus Walleij, Arnd Bergmann, stefan-XLVq0VzYD2Y,
pmeerw-jW+XmwGofnusTnJN9+BGXg, pebolle-IWqWACnzNjzz+pZb47iToQ,
peter-WaGBZJeGNqdsbIuE7sb01tBPR1lH4CV8,
andy.shevchenko-Re5JQEeQqe8AvxtiuMwx3w,
cw00.choi-Sze3O3UU22JBDgjK7y7TUQ, Russell King, Daniel Lezcano,
Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
Kumar Gala, Thomas Gleixner, Greg Kroah-Hartman, Jiri Slaby,
Andrew Morton, David S. Miller, Mauro Carvalho Chehab, Antti
In-Reply-To: <1428080481-18591-11-git-send-email-mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
On Fri, 2015-04-03 at 19:01 +0200, Maxime Coquelin wrote:
> This drivers adds support to the STM32 USART controller, which is a
> standard serial driver.
trivia:
> diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
[]
> +static struct uart_ops stm32_uart_ops = {
could be const
and it could be updated in a separate patch later too.
^ permalink raw reply
* Re: [PATCH v5 10/15] serial: stm32-usart: Add STM32 USART Driver
From: Peter Hurley @ 2015-04-03 17:29 UTC (permalink / raw)
To: Maxime Coquelin, Greg Kroah-Hartman
Cc: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle,
andy.shevchenko, cw00.choi, Russell King, Daniel Lezcano,
Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
Kumar Gala, Thomas Gleixner, Jiri Slaby, Andrew Morton,
David S. Miller, Mauro Carvalho Chehab, Joe Perches,
Antti Palosaari, Tejun Heo
In-Reply-To: <1428080481-18591-11-git-send-email-mcoquelin.stm32@gmail.com>
On 04/03/2015 01:01 PM, Maxime Coquelin wrote:
> This drivers adds support to the STM32 USART controller, which is a
> standard serial driver.
Reviewed-by: Peter Hurley <peter@hurleysoftware.com>
PS - I saw Rob's comment about 'hw-flow-ctrl' vs 'auto-flow-control'
and I'm ok with either so feel free to and my review comment to a v6
if that's the only change.
^ permalink raw reply
* Re: [PATCH v5 09/15] dt-bindings: Document the STM32 USART bindings
From: Rob Herring @ 2015-04-03 17:14 UTC (permalink / raw)
To: Maxime Coquelin
Cc: Uwe Kleine-König, Andreas Färber, Geert Uytterhoeven,
Rob Herring, Philipp Zabel, Linus Walleij, Arnd Bergmann,
Stefan Agner, Peter Meerwald, Paul Bolle, Peter Hurley,
Andy Shevchenko, Chanwoo Choi, Russell King, Daniel Lezcano,
Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
Kumar Gala, Thomas Gleixner, Greg Kroah-Hartman
In-Reply-To: <1428080481-18591-10-git-send-email-mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
On Fri, Apr 3, 2015 at 12:01 PM, Maxime Coquelin
<mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> This adds documentation of device tree bindings for the
> STM32 USART
>
> Tested-by: Chanwoo Choi <cw00.choi-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Signed-off-by: Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> ---
> .../devicetree/bindings/serial/st,stm32-usart.txt | 32 ++++++++++++++++++++++
> 1 file changed, 32 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/serial/st,stm32-usart.txt
>
> diff --git a/Documentation/devicetree/bindings/serial/st,stm32-usart.txt b/Documentation/devicetree/bindings/serial/st,stm32-usart.txt
> new file mode 100644
> index 0000000..090a3a4
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/serial/st,stm32-usart.txt
> @@ -0,0 +1,32 @@
> +* STMicroelectronics STM32 USART
> +
> +Required properties:
> +- compatible: Can be either "st,stm32-usart" or "st,stm32-uart" depending on
> +whether the device supports synchronous mode.
> +- reg: The address and length of the peripheral registers space
> +- interrupts: The interrupt line of the USART instance
> +- clocks: The input clock of the USART instance
> +
> +Optional properties:
> +- pinctrl: The reference on the pins configuration
> +- st,hw-flow-ctrl: bool flag to enable hardware flow control.
We already have "auto-flow-control" for 8250. Does that work for you?
> +
> +Examples:
> +usart4: serial@40004c00 {
> + compatible = "st,stm32-uart";
> + reg = <0x40004c00 0x400>;
> + interrupts = <52>;
> + clocks = <&clk_pclk1>;
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_usart4>;
> +};
> +
> +usart2: serial@40004400 {
> + compatible = "st,stm32-usart", "st,stm32-uart";
> + reg = <0x40004400 0x400>;
> + interrupts = <38>;
> + clocks = <&clk_pclk1>;
> + st,hw-flow-ctrl;
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_usart2 &pinctrl_usart2_rtscts>;
> +};
> --
> 1.9.1
>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v5 07/15] dt-bindings: Document the STM32 timer bindings
From: Rob Herring @ 2015-04-03 17:10 UTC (permalink / raw)
To: Maxime Coquelin
Cc: Uwe Kleine-König, Andreas Färber, Geert Uytterhoeven,
Rob Herring, Philipp Zabel, Linus Walleij, Arnd Bergmann,
Stefan Agner, Peter Meerwald, Paul Bolle, Peter Hurley,
Andy Shevchenko, Chanwoo Choi, Russell King, Daniel Lezcano,
Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
Kumar Gala, Thomas Gleixner, Greg Kroah-Hartman
In-Reply-To: <1428080481-18591-8-git-send-email-mcoquelin.stm32@gmail.com>
On Fri, Apr 3, 2015 at 12:01 PM, Maxime Coquelin
<mcoquelin.stm32@gmail.com> wrote:
> This adds documentation of device tree bindings for the
> STM32 timer.
>
> Tested-by: Chanwoo Choi <cw00.choi@samsung.com>
> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
One minor thing below, otherwise:
Acked-by: Rob Herring <robh@kernel.org>
> ---
> .../devicetree/bindings/timer/st,stm32-timer.txt | 22 ++++++++++++++++++++++
> 1 file changed, 22 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/timer/st,stm32-timer.txt
>
> diff --git a/Documentation/devicetree/bindings/timer/st,stm32-timer.txt b/Documentation/devicetree/bindings/timer/st,stm32-timer.txt
> new file mode 100644
> index 0000000..d3fdeb0
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/timer/st,stm32-timer.txt
> @@ -0,0 +1,22 @@
> +. STMicroelectronics STM32 timer
> +
> +The STM32 MCUs family has several general-purpose 16 and 32 bits timers.
> +
> +Required properties:
> +- compatible : Should be st,stm32-timer"
Missing quote
> +- reg : Address and length of the register set
> +- clocks : Reference on the timer input clock
> +- interrupts : Reference to the timer interrupt
> +
> +Optional properties:
> +- resets: Reference to a reset controller asserting the timer
> +
> +Example:
> +
> +timer5: timer@40000c00 {
> + compatible = "st,stm32-timer";
> + reg = <0x40000c00 0x400>;
> + interrupts = <50>;
> + resets = <&rrc 259>;
> + clocks = <&clk_pmtr1>;
> +};
> --
> 1.9.1
>
^ permalink raw reply
* Re: [PATCH v5 03/15] dt-bindings: Document the ARM System timer bindings
From: Rob Herring @ 2015-04-03 17:09 UTC (permalink / raw)
To: Maxime Coquelin
Cc: Uwe Kleine-König, Andreas Färber, Geert Uytterhoeven,
Rob Herring, Philipp Zabel, Linus Walleij, Arnd Bergmann,
Stefan Agner, Peter Meerwald, Paul Bolle, Peter Hurley,
Andy Shevchenko, Chanwoo Choi, Russell King, Daniel Lezcano,
Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
Kumar Gala, Thomas Gleixner, Greg Kroah-Hartman
In-Reply-To: <1428080481-18591-4-git-send-email-mcoquelin.stm32@gmail.com>
On Fri, Apr 3, 2015 at 12:01 PM, Maxime Coquelin
<mcoquelin.stm32@gmail.com> wrote:
> This adds documentation of device tree bindings for the
> ARM System timer.
>
> Tested-by: Chanwoo Choi <cw00.choi@samsung.com>
> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
Acked-by: Rob Herring <robh@kernel.org>
> ---
> .../devicetree/bindings/arm/armv7m_systick.txt | 26 ++++++++++++++++++++++
> 1 file changed, 26 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/arm/armv7m_systick.txt
>
> diff --git a/Documentation/devicetree/bindings/arm/armv7m_systick.txt b/Documentation/devicetree/bindings/arm/armv7m_systick.txt
> new file mode 100644
> index 0000000..7cf4a24
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/arm/armv7m_systick.txt
> @@ -0,0 +1,26 @@
> +* ARMv7M System Timer
> +
> +ARMv7-M includes a system timer, known as SysTick. Current driver only
> +implements the clocksource feature.
> +
> +Required properties:
> +- compatible : Should be "arm,armv7m-systick"
> +- reg : The address range of the timer
> +
> +Required clocking property, have to be one of:
> +- clocks : The input clock of the timer
> +- clock-frequency : The rate in HZ in input of the ARM SysTick
> +
> +Examples:
> +
> +systick: timer@e000e010 {
> + compatible = "arm,armv7m-systick";
> + reg = <0xe000e010 0x10>;
> + clocks = <&clk_systick>;
> +};
> +
> +systick: timer@e000e010 {
> + compatible = "arm,armv7m-systick";
> + reg = <0xe000e010 0x10>;
> + clock-frequency = <90000000>;
> +};
> --
> 1.9.1
>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox