* Re: [PATCH v3] Add virtio-input driver.
From: Dmitry Torokhov @ 2015-03-24 17:28 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: virtio-dev, open list:ABI/API, open list, virtualization,
David Herrmann
In-Reply-To: <20150324180532-mutt-send-email-mst@redhat.com>
On Tue, Mar 24, 2015 at 06:22:36PM +0100, Michael S. Tsirkin wrote:
> On Tue, Mar 24, 2015 at 09:23:37AM -0700, Dmitry Torokhov wrote:
> > On Tue, Mar 24, 2015 at 11:36:31AM +0100, Michael S. Tsirkin wrote:
> > > On Tue, Mar 24, 2015 at 08:32:01AM +0100, Gerd Hoffmann wrote:
> > > > virtio-input is basically evdev-events-over-virtio, so this driver isn't
> > > > much more than reading configuration from config space and forwarding
> > > > incoming events to the linux input layer.
> > > >
> > > > Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> > >
> > > Looks pretty neat overall. I think I still see some
> > > small issues, but it's getting there.
> > >
> > > > ---
> > > > MAINTAINERS | 6 +
> > > > drivers/virtio/Kconfig | 10 ++
> > > > drivers/virtio/Makefile | 1 +
> > > > drivers/virtio/virtio_input.c | 313 ++++++++++++++++++++++++++++++++++++++
> > > > include/uapi/linux/Kbuild | 1 +
> > > > include/uapi/linux/virtio_ids.h | 1 +
> > > > include/uapi/linux/virtio_input.h | 76 +++++++++
> > > > 7 files changed, 408 insertions(+)
> > > > create mode 100644 drivers/virtio/virtio_input.c
> > > > create mode 100644 include/uapi/linux/virtio_input.h
> > > >
> > > > diff --git a/MAINTAINERS b/MAINTAINERS
> > > > index 358eb01..6f233dd 100644
> > > > --- a/MAINTAINERS
> > > > +++ b/MAINTAINERS
> > > > @@ -10442,6 +10442,12 @@ S: Maintained
> > > > F: drivers/vhost/
> > > > F: include/uapi/linux/vhost.h
> > > >
> > > > +VIRTIO INPUT DRIVER
> > > > +M: Gerd Hoffmann <kraxel@redhat.com>
> > > > +S: Maintained
> > > > +F: drivers/virtio/virtio_input.c
> > > > +F: include/uapi/linux/virtio_input.h
> > > > +
> > > > VIA RHINE NETWORK DRIVER
> > > > M: Roger Luethi <rl@hellgate.ch>
> > > > S: Maintained
> > > > diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig
> > > > index b546da5..cab9f3f 100644
> > > > --- a/drivers/virtio/Kconfig
> > > > +++ b/drivers/virtio/Kconfig
> > > > @@ -48,6 +48,16 @@ config VIRTIO_BALLOON
> > > >
> > > > If unsure, say M.
> > > >
> > > > +config VIRTIO_INPUT
> > > > + tristate "Virtio input driver"
> > > > + depends on VIRTIO
> > > > + depends on INPUT
> > > > + ---help---
> > > > + This driver supports virtio input devices such as
> > > > + keyboards, mice and tablets.
> > > > +
> > > > + If unsure, say M.
> > > > +
> > > > config VIRTIO_MMIO
> > > > tristate "Platform bus driver for memory mapped virtio devices"
> > > > depends on HAS_IOMEM
> > > > diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile
> > > > index d85565b..41e30e3 100644
> > > > --- a/drivers/virtio/Makefile
> > > > +++ b/drivers/virtio/Makefile
> > > > @@ -4,3 +4,4 @@ obj-$(CONFIG_VIRTIO_PCI) += virtio_pci.o
> > > > virtio_pci-y := virtio_pci_modern.o virtio_pci_common.o
> > > > virtio_pci-$(CONFIG_VIRTIO_PCI_LEGACY) += virtio_pci_legacy.o
> > > > obj-$(CONFIG_VIRTIO_BALLOON) += virtio_balloon.o
> > > > +obj-$(CONFIG_VIRTIO_INPUT) += virtio_input.o
> > > > diff --git a/drivers/virtio/virtio_input.c b/drivers/virtio/virtio_input.c
> > > > new file mode 100644
> > > > index 0000000..cf112b2
> > > > --- /dev/null
> > > > +++ b/drivers/virtio/virtio_input.c
> > > > @@ -0,0 +1,313 @@
> > > > +#include <linux/module.h>
> > > > +#include <linux/virtio.h>
> > > > +#include <linux/input.h>
> > > > +
> > > > +#include <uapi/linux/virtio_ids.h>
> > > > +#include <uapi/linux/virtio_input.h>
> > > > +
> > > > +struct virtio_input {
> > > > + struct virtio_device *vdev;
> > > > + struct input_dev *idev;
> > > > + char name[64];
> > > > + char serial[64];
> > > > + char phys[64];
> > > > + struct virtqueue *evt, *sts;
> > > > + struct virtio_input_event evts[64];
> > > > + spinlock_t lock;
> > > > +};
> > > > +
> > > > +static void virtinput_queue_evtbuf(struct virtio_input *vi,
> > > > + struct virtio_input_event *evtbuf)
> > > > +{
> > > > + struct scatterlist sg[1];
> > > > +
> > > > + sg_init_one(sg, evtbuf, sizeof(*evtbuf));
> > > > + virtqueue_add_inbuf(vi->evt, sg, 1, evtbuf, GFP_ATOMIC);
> > > > +}
> > > > +
> > > > +static void virtinput_recv_events(struct virtqueue *vq)
> > > > +{
> > > > + struct virtio_input *vi = vq->vdev->priv;
> > > > + struct virtio_input_event *event;
> > > > + unsigned long flags;
> > > > + unsigned int len;
> > > > +
> > > > + spin_lock_irqsave(&vi->lock, flags);
> > > > + while ((event = virtqueue_get_buf(vi->evt, &len)) != NULL) {
> > > > + input_event(vi->idev,
> > > > + le16_to_cpu(event->type),
> > > > + le16_to_cpu(event->code),
> > > > + le32_to_cpu(event->value));
> > >
> > > What happens if input layer gets an
> > > unexpected event code or value?
> > > Or does something prevent it?
> > >
> > >
> > >
> > > > + virtinput_queue_evtbuf(vi, event);
> > > > + }
> > > > + virtqueue_kick(vq);
> > > > + spin_unlock_irqrestore(&vi->lock, flags);
> > > > +}
> > > > +
> > > > +static int virtinput_send_status(struct virtio_input *vi,
> > > > + u16 type, u16 code, s32 value)
> > > > +{
> > > > + struct virtio_input_event *stsbuf;
> > > > + struct scatterlist sg[1];
> > > > + unsigned long flags;
> > > > + int rc;
> > > > +
> > > > + stsbuf = kzalloc(sizeof(*stsbuf), GFP_ATOMIC);
> > > > + if (!stsbuf)
> > > > + return -ENOMEM;
> > > > +
> > > > + stsbuf->type = cpu_to_le16(type);
> > > > + stsbuf->code = cpu_to_le16(code);
> > > > + stsbuf->value = cpu_to_le32(value);
> > > > + sg_init_one(sg, stsbuf, sizeof(*stsbuf));
> > > > +
> > > > + spin_lock_irqsave(&vi->lock, flags);
> > > > + rc = virtqueue_add_outbuf(vi->sts, sg, 1, stsbuf, GFP_ATOMIC);
> > > > + virtqueue_kick(vi->sts);
> > > > + spin_unlock_irqrestore(&vi->lock, flags);
> >
> > I think locking is wrong here. This is basically input_dev->event()
> > which is called with input_dev->event_lock spinlock held, and it is
> > taking vi->lock. OTOH virtinput_recv_events() takes vi->lock and then
> > calls input_event(), which will try taking input_dev->event_lock. It is
> > bound to deadlock at some point.
> >
> > I guess the easiest way would be to drop vi->lock() after fetching
> > virtio event and before calling input_event().
>
> Or just always use event_lock for event vq, leave vq->lock for
> status vq only.
>
> > > > +
> > > > + if (rc != 0)
> > > > + kfree(stsbuf);
> > > > + return rc;
> > >
> > > This means that caller will get errors if it happens to call
> > > send_status at a rate that's faster than host's consumption of them.
> > > To me this looks wrong.
> > > Poking at input layer, it seems to simply discard errors.
> > > Is it always safe to discard status updates?
> > > If yes, some kind of comment to clarify the logic would
> > > make sense IMHO.
> > >
> > >
> > >
> > > > +}
> > > > +
> > > > +static void virtinput_recv_status(struct virtqueue *vq)
> > > > +{
> > > > + struct virtio_input *vi = vq->vdev->priv;
> > > > + struct virtio_input_event *stsbuf;
> > > > + unsigned long flags;
> > > > + unsigned int len;
> > > > +
> > > > + spin_lock_irqsave(&vi->lock, flags);
> > > > + while ((stsbuf = virtqueue_get_buf(vi->sts, &len)) != NULL)
> > > > + kfree(stsbuf);
> > > > + spin_unlock_irqrestore(&vi->lock, flags);
> > > > +}
> > > > +
> > > > +static int virtinput_status(struct input_dev *idev, unsigned int type,
> > > > + unsigned int code, int value)
> > > > +{
> > > > + struct virtio_input *vi = input_get_drvdata(idev);
> > > > +
> > > > + return virtinput_send_status(vi, type, code, value);
> > > > +}
> > > > +
> > > > +static size_t virtinput_cfg_select(struct virtio_input *vi,
> > > > + u8 select, u8 subsel)
> > > > +{
> > > > + u8 size;
> > > > +
> > > > + virtio_cwrite(vi->vdev, struct virtio_input_config, select, &select);
> > > > + virtio_cwrite(vi->vdev, struct virtio_input_config, subsel, &subsel);
> > > > + virtio_cread(vi->vdev, struct virtio_input_config, size, &size);
> > > > + return size;
> > > > +}
> > > > +
> > > > +static void virtinput_cfg_bits(struct virtio_input *vi, int select, int subsel,
> > > > + unsigned long *bits, unsigned int bitcount)
> > > > +{
> > > > + unsigned int bit;
> > > > + size_t bytes;
> > > > + u8 *virtio_bits;
> > > > +
> > > > + bytes = virtinput_cfg_select(vi, select, subsel);
> > > > + if (!bytes)
> > > > + return;
> > >
> > > How about limiting bytes to sizeof struct virtio_input_config->u?
> > >
> > > > + if (bitcount > bytes*8)
> > > > + bitcount = bytes*8;
> > >
> > > Space around * pls.
> > >
> > > > +
> > > > + /*
> > > > + * Bitmap in virtio config space is a simple stream of bytes,
> > > > + * with the first byte carrying bits 0-7, second bits 8-15 and
> > > > + * so on.
> > > > + */
> > > > + virtio_bits = kzalloc(bytes, GFP_KERNEL);
> > > > + if (!virtio_bits)
> > > > + return;
> > > > + virtio_cread_bytes(vi->vdev, offsetof(struct virtio_input_config, u),
> > > > + virtio_bits, bytes);
> > > > + for (bit = 0; bit < bitcount; bit++) {
> > > > + if (virtio_bits[bit / 8] & (1 << (bit % 8)))
> > > > + __set_bit(bit, bits);
> > > > + }
> > > > + kfree(virtio_bits);
> > > > +
> > > > + if (select == VIRTIO_INPUT_CFG_EV_BITS)
> > > > + __set_bit(subsel, vi->idev->evbit);
> > > > +}
> > > > +
> > > > +static void virtinput_cfg_abs(struct virtio_input *vi, int abs)
> > > > +{
> > > > + u32 mi, ma, re, fu, fl;
> > > > +
> > > > + virtinput_cfg_select(vi, VIRTIO_INPUT_CFG_ABS_INFO, abs);
> > > > + virtio_cread(vi->vdev, struct virtio_input_config, u.abs.min, &mi);
> > > > + virtio_cread(vi->vdev, struct virtio_input_config, u.abs.max, &ma);
> > > > + virtio_cread(vi->vdev, struct virtio_input_config, u.abs.res, &re);
> > > > + virtio_cread(vi->vdev, struct virtio_input_config, u.abs.fuzz, &fu);
> > > > + virtio_cread(vi->vdev, struct virtio_input_config, u.abs.flat, &fl);
> > > > + input_set_abs_params(vi->idev, abs, mi, ma, fu, fl);
> > > > + input_abs_set_res(vi->idev, abs, re);
> > > > +}
> > > > +
> > > > +static int virtinput_init_vqs(struct virtio_input *vi)
> > > > +{
> > > > + struct virtqueue *vqs[2];
> > > > + vq_callback_t *cbs[] = { virtinput_recv_events,
> > > > + virtinput_recv_status };
> > > > + static const char * names[] = { "events", "status" };
> > >
> > > No space between * and names expected
> > >
> > > > + int i, err, size;
> > > > +
> > > > + err = vi->vdev->config->find_vqs(vi->vdev, 2, vqs, cbs, names);
> > > > + if (err)
> > > > + return err;
> > > > + vi->evt = vqs[0];
> > > > + vi->sts = vqs[1];
> > > > +
> > > > + size = virtqueue_get_vring_size(vi->evt);
> > > > + if (size > ARRAY_SIZE(vi->evts))
> > > > + size = ARRAY_SIZE(vi->evts);
> > > > + for (i = 0; i < size; i++)
> > > > + virtinput_queue_evtbuf(vi, &vi->evts[i]);
> > > > + virtqueue_kick(vi->evt);
> > > > +
> > > > + return 0;
> > > > +}
> > > > +
> > > > +static int virtinput_probe(struct virtio_device *vdev)
> > > > +{
> > > > + struct virtio_input *vi;
> > > > + size_t size;
> > > > + int abs, err;
> > > > +
> > > > + if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1))
> > > > + return -ENODEV;
> > > > +
> > > > + vi = kzalloc(sizeof(*vi), GFP_KERNEL);
> > > > + if (!vi)
> > > > + return -ENOMEM;
> > > > +
> > > > + vdev->priv = vi;
> > > > + vi->vdev = vdev;
> > > > + spin_lock_init(&vi->lock);
> > > > +
> > > > + err = virtinput_init_vqs(vi);
> > > > + if (err)
> > > > + goto err_init_vq;
> > > > +
> > > > + vi->idev = input_allocate_device();
> > > > + if (!vi->idev) {
> > > > + err = -ENOMEM;
> > > > + goto err_input_alloc;
> > > > + }
> > > > + input_set_drvdata(vi->idev, vi);
> > > > +
> > > > + size = virtinput_cfg_select(vi, VIRTIO_INPUT_CFG_ID_NAME, 0);
> > > > + virtio_cread_bytes(vi->vdev, offsetof(struct virtio_input_config, u),
> > > > + vi->name, min(size, sizeof(vi->name)));
> > > > + size = virtinput_cfg_select(vi, VIRTIO_INPUT_CFG_ID_SERIAL, 0);
> > > > + virtio_cread_bytes(vi->vdev, offsetof(struct virtio_input_config, u),
> > > > + vi->serial, min(size, sizeof(vi->serial)));
> > > > + snprintf(vi->phys, sizeof(vi->phys),
> > > > + "virtio%d/input0", vdev->index);
> > > > + vi->idev->name = vi->name;
> > > > + vi->idev->phys = vi->phys;
> > > > + vi->idev->uniq = vi->serial;
> > > > +
> > > > + size = virtinput_cfg_select(vi, VIRTIO_INPUT_CFG_ID_DEVIDS, 0);
> > > > + if (size >= 8) {
> > >
> > > What does 8 mean here? Should be sizeof virtio_input_devids?
> > >
> > > > + virtio_cread(vi->vdev, struct virtio_input_config,
> > > > + u.ids.bustype, &vi->idev->id.bustype);
> > > > + virtio_cread(vi->vdev, struct virtio_input_config,
> > > > + u.ids.vendor, &vi->idev->id.vendor);
> > > > + virtio_cread(vi->vdev, struct virtio_input_config,
> > > > + u.ids.product, &vi->idev->id.product);
> > > > + virtio_cread(vi->vdev, struct virtio_input_config,
> > > > + u.ids.version, &vi->idev->id.version);
> > > > + } else {
> > > > + vi->idev->id.bustype = BUS_VIRTUAL;
> > > > + }
> > > > +
> > > > + virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_PROP_BITS, 0,
> > > > + vi->idev->propbit, INPUT_PROP_CNT);
> > > > + size = virtinput_cfg_select(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_REP);
> > > > + if (size)
> > > > + __set_bit(EV_REP, vi->idev->evbit);
> > > > +
> > > > + vi->idev->dev.parent = &vdev->dev;
> > > > + vi->idev->event = virtinput_status;
> > > > +
> > > > + /* device -> kernel */
> > > > + virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_KEY,
> > > > + vi->idev->keybit, KEY_CNT);
> > > > + virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_REL,
> > > > + vi->idev->relbit, REL_CNT);
> > > > + virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_ABS,
> > > > + vi->idev->absbit, ABS_CNT);
> > > > + virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_MSC,
> > > > + vi->idev->mscbit, MSC_CNT);
> > > > + virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_SW,
> > > > + vi->idev->swbit, SW_CNT);
> > > > +
> > > > + /* kernel -> device */
> > > > + virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_LED,
> > > > + vi->idev->ledbit, LED_CNT);
> > > > + virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_SND,
> > > > + vi->idev->sndbit, SND_CNT);
> > > > +
> > > > + if (test_bit(EV_ABS, vi->idev->evbit)) {
> > > > + for (abs = 0; abs < ABS_CNT; abs++) {
> > > > + if (!test_bit(abs, vi->idev->absbit))
> > > > + continue;
> > > > + virtinput_cfg_abs(vi, abs);
> > > > + }
> > > > + }
> > > > + virtio_device_ready(vdev);
> > > > +
> > > At this point you can already get interrupts.
> > > This will cause events to be forwarded.
> > > I'm guessing this is ok since you called
> > > input_allocate_device, but worth checking,
> > > and maybe adding a comment.
> >
> > Yes, it is OK to send events though yet unregistered input device, as
> > long as it was allocated with input_allocate_device().
> >
> > >
> > > > + err = input_register_device(vi->idev);
> > > > + if (err)
> > > > + goto err_input_register;
> > > > +
> > > > + return 0;
> > > > +
> > > > +err_input_register:
> > >
> > > > + input_free_device(vi->idev);
> > >
> > > At this point you can already get interrupts
> > > since you called virtio_device_ready, and
> > > getting events from a freed device likely won't
> > > DTRT.
> >
> > Right. I guess you want to mark the virtio device ready only after
> > registering input device.
>
> No that's broken since you can get events after this
> point, and you won't be able to forward them.
Who cares? What makes these events needed compared to ones sent 1 ms
earlier before we had input device registered?
But I guess if you can call virtio_device_ready/virtio_device_broken
several times then the best option is putting them into input_dev->open
and input_dev->close callbacks.
Thanks.
--
Dmitry
^ permalink raw reply
* Re: [PATCH 13/14] kdbus: add walk-through user space example
From: Jiri Slaby @ 2015-03-24 17:37 UTC (permalink / raw)
To: David Herrmann
Cc: Greg Kroah-Hartman, Arnd Bergmann, Eric W. Biederman,
One Thousand Gnomes, Tom Gundersen, Jiri Kosina, Andy Lutomirski,
Linux API, linux-kernel, Daniel Mack, Djalal Harouni,
Michal Marek, linux-kbuild
In-Reply-To: <CANq1E4QmOg0Xjx9d=fDQmuaAO1aBwQAbdwz_7ucyo6LVvFLzUA@mail.gmail.com>
Ccing kbuild fellows (see the very bottom).
On 03/24/2015, 06:15 PM, David Herrmann wrote:
> Hi
>
> On Tue, Mar 24, 2015 at 5:46 PM, Jiri Slaby <jslaby@suse.cz> wrote:
>> On 03/09/2015, 02:09 PM, Greg Kroah-Hartman wrote:
>>> --- /dev/null
>>> +++ b/samples/kdbus/Makefile
>>> @@ -0,0 +1,10 @@
>>> +# kbuild trick to avoid linker error. Can be omitted if a module is built.
>>> +obj- := dummy.o
>>> +
>>> +hostprogs-y += kdbus-workers
>>> +
>>> +always := $(hostprogs-y)
>>
>> Errr, no. Not only it causes build failures (even with KDBUS=n), it
>> definitely should not be built for everyone.
>
> It's only built if CONFIG_SAMPLES is set, right?
Yes, but I build other samples selected with separate CONFIG_ options
like CONFIG_SAMPLE_LIVEPATCH. So this guy should have its own CONFIG_
option too, because I (and likely others) don't want to build it. All of
the samples should be protected at least by their respective kernel
CONFIG_ option IMO.
> What build-failures does it cause? linux/kdbus.h is not optional based
> on CONFIG_KDBUS, so the samples should build just fine. Can you tell
> me what kind of errors you get? The kbuild-robots didn't report
> anything so far.
The output is this:
In file included from samples/kdbus/kdbus-workers.c:79:0:
/home/latest/linux/samples/kdbus/kdbus-api.h:5:25: fatal error:
linux/kdbus.h: No such file or directory
#include <linux/kdbus.h>
^
compilation terminated.
I now know that I have to install_headers *if* I want to build the
sample. But I don't want to build it in the first place. (So the config
option above should be all we need.)
>> And why is it a host prog? It's a sample prog for the kernel I am
>> building, i.e. for the destination arch, like all the other samples.
>
> It's modeled after the other user-space examples in ./samples/, which
> all use hostprogs (see samples/{bpf,hidraw,seccomp,uhid}/Makefile). I
> have no idea how to build programs that run on the target
> architecture. Documentation/kbuild/makefiles.txt doesn't list it,
> which is, I guess, the reason why everyone used hostprogs so far. And
> given that autotools calls the target architecture "--host", I
> actually thought this is what hostprogs does.. apparently that's not
> the case, sorry.
Oh, it's cut&paste, I see. This does not look correct though. The hack
inclusive. Host progs are intended to be run on the host where the
kernel is built. During the compilation or such (like x/menuconfig).
Quite misleading naming if you are used to the autotools one.
thanks,
--
js
suse labs
^ permalink raw reply
* Re: [PATCH v3 10/15] serial: stm32-usart: Add STM32 USART Driver
From: Peter Hurley @ 2015-03-24 17:44 UTC (permalink / raw)
To: Maxime Coquelin
Cc: Andy Shevchenko, Uwe Kleine-König, Andreas Färber,
Geert Uytterhoeven, Rob Herring, Philipp Zabel, Linus Walleij,
Arnd Bergmann, Stefan Agner, Peter Meerwald, Paul Bolle,
Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
Greg Kroah-Hartman, Jiri Slaby
In-Reply-To: <CALszF6Dg7t9+F9NG+xREPQeaAj7T6D1GuGabkr8EvOAAdtg7yA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
Hi Maxime,
On 03/24/2015 01:21 PM, Maxime Coquelin wrote:
> Hi Peter,
>
> 2015-03-19 18:35 GMT+01:00 Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>:
>> 2015-03-19 15:58 GMT+01:00 Peter Hurley <peter-WaGBZJeGNqdsbIuE7sb01tBPR1lH4CV8@public.gmane.org>:
>>> On 03/19/2015 09:55 AM, Maxime Coquelin wrote:
>>>>>>>> +static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
>>>>>>>> + struct ktermios *old)
>>> [...]
>>>>>>>> + usardiv = (port->uartclk * 25) / (baud * 4);
>>>>>>>> + mantissa = (usardiv / 100) << USART_BRR_DIV_M_SHIFT;
>>>>>>>> + fraction = DIV_ROUND_CLOSEST((usardiv % 100) * 16, 100);
>>>>>>>> + if (fraction & ~USART_BRR_DIV_F_MASK) {
>>>>>>>> + fraction = 0;
>>>>>>>> + mantissa += (1 << USART_BRR_DIV_M_SHIFT);
>>>>>>>> + }
>>> [...]
>>>> Really, I would prefer keeping this fractional divider as it is
>>>> implemented today.
>>>
>>> You have to admit that's basically an unintelligible mess;
>>> how would anyone ever be able to refactor and replace that with a
>>> common divider implementation?
>>>
>>> At the very least, please comment on the formula and format.
>>
>> Ok, I will refactor the implementation, and comment it.
>
> The implementation was indeed a mess.
> I found some time to refactor the code, and also added support for 8
> times oversampling (16 by default).
> It will allow to achieve higher speeds, with the side effect of being
> less tolerant to clock deviations.
>
> What do you think about the code below?
>
>
> 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)
Thanks! Way better :)
Much more obvious this is a fixed-point divisor.
Regards,
Peter Hurley
^ permalink raw reply
* Re: [PATCH 13/14] kdbus: add walk-through user space example
From: Michal Marek @ 2015-03-24 18:22 UTC (permalink / raw)
To: Jiri Slaby, David Herrmann
Cc: Greg Kroah-Hartman, Arnd Bergmann, Eric W. Biederman,
One Thousand Gnomes, Tom Gundersen, Jiri Kosina, Andy Lutomirski,
Linux API, linux-kernel, Daniel Mack, Djalal Harouni,
linux-kbuild
In-Reply-To: <5511A0D6.5030606@suse.cz>
Dne 24.3.2015 v 18:37 Jiri Slaby napsal(a):
> On 03/24/2015, 06:15 PM, David Herrmann wrote:
>> On Tue, Mar 24, 2015 at 5:46 PM, Jiri Slaby <jslaby@suse.cz> wrote:
>>> Errr, no. Not only it causes build failures (even with KDBUS=n), it
>>> definitely should not be built for everyone.
>>
>> It's only built if CONFIG_SAMPLES is set, right?
>
> Yes, but I build other samples selected with separate CONFIG_ options
> like CONFIG_SAMPLE_LIVEPATCH. So this guy should have its own CONFIG_
> option too, because I (and likely others) don't want to build it. All of
Definitely.
>> It's modeled after the other user-space examples in ./samples/, which
>> all use hostprogs (see samples/{bpf,hidraw,seccomp,uhid}/Makefile). I
>> have no idea how to build programs that run on the target
>> architecture. Documentation/kbuild/makefiles.txt doesn't list it,
>> which is, I guess, the reason why everyone used hostprogs so far. And
>> given that autotools calls the target architecture "--host", I
>> actually thought this is what hostprogs does.. apparently that's not
>> the case, sorry.
>
> Oh, it's cut&paste, I see. This does not look correct though. The hack
> inclusive. Host progs are intended to be run on the host where the
> kernel is built. During the compilation or such (like x/menuconfig).
> Quite misleading naming if you are used to the autotools one.
when cross compiling, we are a bit between a rock and a hard place with
the sample userspace programs:
- The target toolchain might not have libc support
- The host toolchain might be lacking recent kernel headers (therefore
the need to do make headers_install)
- It's not clean whether the samples are meant to be ran on the build
host or target.
There has been some work by Sam Ravnborg to introduce uapiprogs-y to for
sample userspace programs, but for now, please use hostprogs-y,
-Iusr/include and make each sample opt-in.
Michal
^ permalink raw reply
* Re: [PATCH v3 10/15] serial: stm32-usart: Add STM32 USART Driver
From: Peter Hurley @ 2015-03-24 18:23 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,
Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo
In-Reply-To: <1426197361-19290-11-git-send-email-maxime.coquelin-qxv4g6HH51o@public.gmane.org>
Hi Maxime,
On 03/12/2015 05:55 PM, Maxime Coquelin wrote:
> From: Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
>
> This drivers adds support to the STM32 USART controller, which is a
> standard serial driver.
Comments below.
> Signed-off-by: Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> ---
> drivers/tty/serial/Kconfig | 17 +
> drivers/tty/serial/Makefile | 1 +
> drivers/tty/serial/stm32-usart.c | 695 +++++++++++++++++++++++++++++++++++++++
> include/uapi/linux/serial_core.h | 3 +
> 4 files changed, 716 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..61bb065
> --- /dev/null
> +++ b/drivers/tty/serial/stm32-usart.c
> @@ -0,0 +1,695 @@
> +/*
> + * Copyright (C) Maxime Coquelin 2015
> + * Author: Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> + * 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;
> +};
> +
> +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 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)
> +{
> + /*
> + * This routine is used for seting signals of: DTR, DCD, CTS/RTS
> + * We use USART's hardware for CTS/RTS, so don't need any for that.
If this means that you're enabling autoflow control, then you still need
to respond to the state of TIOCM_RTS, so that both serial core and userspace
can halt input flow.
If the hardware doesn't support separate RTS enable/disable control,
then you need to disable autoRTS when TIOCM_RTS is clear, and re-enable
it when raised.
> + * Some boards have DTR and DCD implemented using PIO pins,
> + * code to do this should be hooked in here.
> + */
> +}
> +
> +static unsigned int stm32_get_mctrl(struct uart_port *port)
> +{
> + /*
> + * This routine is used for geting signals of: DTR, DCD, DSR, RI,
> + * and CTS/RTS
> + */
> + return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
> +}
> +
> +/* 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);
> +}
> +
> +/* Transmit stop */
> +static void stm32_stop_tx(struct uart_port *port)
> +{
> + stm32_clr_bits(port, USART_CR1, USART_CR1_TXEIE);
> +}
> +
> +/* 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)
> +{
> + /* Nothing here yet .. */
> +}
> +
> +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)) {
> + 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)
> +{
> + unsigned int baud;
> + u32 usardiv, mantissa, fraction;
> + tcflag_t cflag;
> + u32 cr1, cr2, cr3;
> + unsigned long flags;
> +
> + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
> + cflag = termios->c_cflag;
> +
> + 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;
> +
> + if (cflag & CRTSCTS)
> + cr3 = USART_CR3_RTSE | USART_CR3_CTSE;
If this means autoflow control, then you need to define
throttle()/unthrottle() methods, otherwise the serial core won't
be able to throttle the remote when input buffers are about
to overflow.
And you should only enable the autoCTS and let the serial
core enable autoRTS through set_mctrl(TIOCM_RTS).
Just let me know if you need more info about how to do this.
> +
> + usardiv = (port->uartclk * 25) / (baud * 4);
> + mantissa = (usardiv / 100) << USART_BRR_DIV_M_SHIFT;
> + fraction = DIV_ROUND_CLOSEST((usardiv % 100) * 16, 100);
> + if (fraction & ~USART_BRR_DIV_F_MASK) {
> + fraction = 0;
> + mantissa += (1 << USART_BRR_DIV_M_SHIFT);
> + }
> +
> + 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)
> +{
> +}
> +
> +static int stm32_request_port(struct uart_port *port)
> +{
> + return 0;
> +}
> +
> +static void stm32_config_port(struct uart_port *port, int flags)
> +{
> + if ((flags & UART_CONFIG_TYPE))
Single parens.
> + 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,
> + .start_tx = stm32_start_tx,
> + .stop_tx = stm32_stop_tx,
> + .stop_rx = stm32_stop_rx,
> + .break_ctl = stm32_break_ctl,
> + .startup = stm32_startup,
> + .shutdown = stm32_shutdown,
> + .set_termios = stm32_set_termios,
> + .type = stm32_type,
> + .release_port = stm32_release_port,
> + .request_port = stm32_request_port,
> + .config_port = stm32_config_port,
> + .verify_port = stm32_verify_port,
> + .pm = stm32_pm,
> +};
> +
> +static int stm32_init_port(struct stm32_port *stm32port,
> + struct platform_device *pdev)
> +{
> + struct uart_port *port = &stm32port->port;
> + struct resource *res;
> +
> + 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 (WARN_ON(IS_ERR(stm32port->clk)))
Do you really need a stack trace here? Could this be dev_err() instead?
> + return -EINVAL;
> +
> + /* ensure that clk rate is correct by enabling the clk */
> + clk_prepare_enable(stm32port->clk);
> + stm32port->port.uartclk = clk_get_rate(stm32port->clk);
> + WARN_ON(stm32port->port.uartclk == 0);
Or here?
> + clk_disable_unprepare(stm32port->clk);
> +
> + return 0;
> +}
> +
> +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, STM32_SERIAL_NAME);
> +
> + if (id < 0)
> + id = 0;
> +
> + if (WARN_ON(id >= STM32_MAX_PORTS))
Or here?
> + return NULL;
> +
> + 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", },
> + {},
> +};
> +
> +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 = {
> + .owner = THIS_MODULE,
> + .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,
> + .owner = THIS_MODULE,
> + .of_match_table = of_match_ptr(stm32_match),
> + },
> +};
> +
> +static int __init usart_init(void)
> +{
> + int ret;
> + static char banner[] __initdata =
> + KERN_INFO "STM32 USART driver initialized\n";
> +
> + printk(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");
> diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
> index b212281..e22dee5 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 110
Already taken.
You'll want to make sure v4 applies cleanly to Greg's tty-next branch.
Regards,
Peter Hurley
> +
> #endif /* _UAPILINUX_SERIAL_CORE_H */
>
^ permalink raw reply
* Re: [PATCH v2 1/7] eeprom: Add a simple EEPROM framework for eeprom providers
From: Srinivas Kandagatla @ 2015-03-24 18:34 UTC (permalink / raw)
To: Mark Brown
Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Pawel Moll,
Kumar Gala, linux-api, linux-kernel, devicetree, Stephen Boyd,
Arnd Bergmann, Greg Kroah-Hartman, linux-arm-msm
In-Reply-To: <20150324172346.GW17265@sirena.org.uk>
On 24/03/15 17:23, Mark Brown wrote:
> On Tue, Mar 24, 2015 at 09:18:14AM +0000, Srinivas Kandagatla wrote:
>
>> I did try your suggestion, by which I could remove the regmap from config.
>> One thing I did not like was eeprom-core getting size/stride info directly
>> from providers and regmap from regmap apis. I was wondering if we could take
>> a step further and introduce new regmap helpers like
>
>> regmap_get_size(regmap)
>
> This is already there.
Sorry, I can't see any such api atleast in v4.0-rc5 and linux-next? Are
you referring to another api which does the same job?
>
>> regmap_get_stride(regmap)
>
>> Which would be give eeprom-core the size and stride info, doing this way
>> would cut down regmap related things from eeprom_config structure to minimal
>> and also the source of information would come from just regmap apis.
>
> Documentation/SubmittingPatches...
>
Am not sure what you meant here, Am guessing that you asked me to keep
the respective maintainers in the loop and follow the guide, when I
resend the patch?
--srini
^ permalink raw reply
* Re: [PATCH 13/14] kdbus: add walk-through user space example
From: Daniel Mack @ 2015-03-24 18:51 UTC (permalink / raw)
To: Michal Marek, Jiri Slaby, David Herrmann
Cc: Greg Kroah-Hartman, Arnd Bergmann, Eric W. Biederman,
One Thousand Gnomes, Tom Gundersen, Jiri Kosina, Andy Lutomirski,
Linux API, linux-kernel, Djalal Harouni, linux-kbuild
In-Reply-To: <5511AB80.3020102@suse.cz>
[-- Attachment #1: Type: text/plain, Size: 1242 bytes --]
On 03/24/2015 07:22 PM, Michal Marek wrote:
> Dne 24.3.2015 v 18:37 Jiri Slaby napsal(a):
>> Oh, it's cut&paste, I see. This does not look correct though. The hack
>> inclusive. Host progs are intended to be run on the host where the
>> kernel is built. During the compilation or such (like x/menuconfig).
>> Quite misleading naming if you are used to the autotools one.
>
> when cross compiling, we are a bit between a rock and a hard place with
> the sample userspace programs:
> - The target toolchain might not have libc support
> - The host toolchain might be lacking recent kernel headers (therefore
> the need to do make headers_install)
> - It's not clean whether the samples are meant to be ran on the build
> host or target.
Exactly. I just checked in a cross-compiled source tree, and none of the
compiled standalone executables from samples/ or Documentation/ are
actually built for the target platform. Only the samples which come as
kernel modules are.
> There has been some work by Sam Ravnborg to introduce uapiprogs-y to for
> sample userspace programs, but for now, please use hostprogs-y,
> -Iusr/include and make each sample opt-in.
Alright then. Does the attached patch fix your problem, Jiri?
Thanks,
Daniel
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-kdbus-sample-build-kdbus-workers-conditionally.patch --]
[-- Type: text/x-diff; name="0001-kdbus-sample-build-kdbus-workers-conditionally.patch", Size: 1468 bytes --]
From 56309ab0717720fb086ec3209f1b1fa719072f61 Mon Sep 17 00:00:00 2001
From: Daniel Mack <daniel@zonque.org>
Date: Tue, 24 Mar 2015 19:41:56 +0100
Subject: [PATCH] kdbus: sample: build kdbus-workers conditionally
Give the kdbus sample its own config switch and only build it if it's
explicitly switched on.
Reported-by: Jiri Slaby <jslaby@suse.cz>
Signed-off-by: Daniel Mack <daniel@zonque.org>
---
samples/Kconfig | 7 +++++++
samples/kdbus/Makefile | 2 +-
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/samples/Kconfig b/samples/Kconfig
index 224ebb4..a4c6b2f 100644
--- a/samples/Kconfig
+++ b/samples/Kconfig
@@ -55,6 +55,13 @@ config SAMPLE_KDB
Build an example of how to dynamically add the hello
command to the kdb shell.
+config SAMPLE_KDBUS
+ bool "Build kdbus API example"
+ depends on KDBUS
+ help
+ Build an example of how the kdbus API can be used from
+ userspace.
+
config SAMPLE_RPMSG_CLIENT
tristate "Build rpmsg client sample -- loadable modules only"
depends on RPMSG && m
diff --git a/samples/kdbus/Makefile b/samples/kdbus/Makefile
index d009025..9e40c68 100644
--- a/samples/kdbus/Makefile
+++ b/samples/kdbus/Makefile
@@ -1,7 +1,7 @@
# kbuild trick to avoid linker error. Can be omitted if a module is built.
obj- := dummy.o
-hostprogs-y += kdbus-workers
+hostprogs-$(CONFIG_SAMPLE_KDBUS) += kdbus-workers
always := $(hostprogs-y)
--
2.3.3
^ permalink raw reply related
* Re: [PATCH v2 1/7] eeprom: Add a simple EEPROM framework for eeprom providers
From: Mark Brown @ 2015-03-24 19:02 UTC (permalink / raw)
To: Srinivas Kandagatla
Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Pawel Moll,
Kumar Gala, linux-api, linux-kernel, devicetree, Stephen Boyd,
Arnd Bergmann, Greg Kroah-Hartman, linux-arm-msm
In-Reply-To: <5511AE38.3000108@linaro.org>
[-- Attachment #1: Type: text/plain, Size: 824 bytes --]
On Tue, Mar 24, 2015 at 06:34:32PM +0000, Srinivas Kandagatla wrote:
> On 24/03/15 17:23, Mark Brown wrote:
> >>regmap_get_size(regmap)
> >This is already there.
> Sorry, I can't see any such api atleast in v4.0-rc5 and linux-next? Are you
> referring to another api which does the same job?
regmap_get_val_bytes()
> >>Which would be give eeprom-core the size and stride info, doing this way
> >>would cut down regmap related things from eeprom_config structure to minimal
> >>and also the source of information would come from just regmap apis.
> >Documentation/SubmittingPatches...
> Am not sure what you meant here, Am guessing that you asked me to keep the
> respective maintainers in the loop and follow the guide, when I resend the
> patch?
I'm saying that you should send patches if you want to add features.
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]
^ permalink raw reply
* Re: [PATCH v2 1/7] eeprom: Add a simple EEPROM framework for eeprom providers
From: Srinivas Kandagatla @ 2015-03-24 19:26 UTC (permalink / raw)
To: Mark Brown
Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Pawel Moll,
Kumar Gala, linux-api, linux-kernel, devicetree, Stephen Boyd,
Arnd Bergmann, Greg Kroah-Hartman, linux-arm-msm
In-Reply-To: <20150324190226.GB17265@sirena.org.uk>
On 24/03/15 19:02, Mark Brown wrote:
> On Tue, Mar 24, 2015 at 06:34:32PM +0000, Srinivas Kandagatla wrote:
>> >On 24/03/15 17:23, Mark Brown wrote:
>>>> > >>regmap_get_size(regmap)
>>> > >This is already there.
>> >Sorry, I can't see any such api atleast in v4.0-rc5 and linux-next? Are you
>> >referring to another api which does the same job?
> regmap_get_val_bytes()
>
This would return value bytes, but I wanted is the regmap->max_register
value which would be used for sanity checks in eeprom-core.
--srini
^ permalink raw reply
* Re: [PATCH] Add virtio gpu driver.
From: Paul Bolle @ 2015-03-24 20:47 UTC (permalink / raw)
To: Gerd Hoffmann
Cc: virtio-dev-sDuHXQ4OtrM4h7I2RyI4rWD2FQJk+8+b, Dave Airlie,
Dave Airlie, David Airlie, Rusty Russell, Michael S. Tsirkin,
open list, open list:DRM DRIVERS, open list:VIRTIO CORE, NET...,
open list:ABI/API
In-Reply-To: <1427213239-8775-1-git-send-email-kraxel-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Just a license nit.
On Tue, 2015-03-24 at 17:07 +0100, Gerd Hoffmann wrote:
> --- /dev/null
> +++ b/drivers/gpu/drm/virtio/virtgpu_drv.c
> @@ -0,0 +1,132 @@
> +/*
> + * 2011 Red Hat, Inc.
> + * All Rights Reserved.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
I wouldn't know (without further, well, research) which license this is.
> +MODULE_LICENSE("GPL");
But I'm pretty sure it's not GPL v2 or later. So I think the license
mentioned in the comment at the top of this file and the license "ident"
used in this macro do not match.
Paul Bolle
^ permalink raw reply
* Re: [PATCH v2 1/7] eeprom: Add a simple EEPROM framework for eeprom providers
From: Mark Brown @ 2015-03-24 20:55 UTC (permalink / raw)
To: Srinivas Kandagatla
Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Pawel Moll,
Kumar Gala, linux-api, linux-kernel, devicetree, Stephen Boyd,
Arnd Bergmann, Greg Kroah-Hartman, linux-arm-msm
In-Reply-To: <5511BA75.3020305@linaro.org>
[-- Attachment #1: Type: text/plain, Size: 804 bytes --]
On Tue, Mar 24, 2015 at 07:26:45PM +0000, Srinivas Kandagatla wrote:
> On 24/03/15 19:02, Mark Brown wrote:
> >On Tue, Mar 24, 2015 at 06:34:32PM +0000, Srinivas Kandagatla wrote:
> >>>On 24/03/15 17:23, Mark Brown wrote:
> >>>>> >>regmap_get_size(regmap)
> >>>> >This is already there.
> >>>Sorry, I can't see any such api atleast in v4.0-rc5 and linux-next? Are you
> >>>referring to another api which does the same job?
> >regmap_get_val_bytes()
> This would return value bytes, but I wanted is the regmap->max_register
> value which would be used for sanity checks in eeprom-core.
Then you *really* want to pick a better name then, I'd never have
inferred that meaning from "size" (consider sparse register maps for
example). Like I said, send patches (preferrably showing the users as
well).
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]
^ permalink raw reply
* Re: [PATCH] audit.h: remove the macro AUDIT_ARCH_ARMEB definition
From: Paul Moore @ 2015-03-24 21:16 UTC (permalink / raw)
To: Li RongQing
Cc: Eric Paris, linux-audit-H+wXaHxf7aLQT0dZR+AlfA,
linux-api-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <CAJFZqHxfq0DSjKn-uqhT+pAeJ9u8ym2Mr=wsqvPyX7sCicPGZA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
On Sun, Mar 22, 2015 at 8:55 PM, Li RongQing <roy.qing.li-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> On Mon, Mar 23, 2015 at 8:51 AM, Li RongQing <roy.qing.li-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
>> On Fri, Mar 20, 2015 at 9:29 PM, Paul Moore <paul-r2n+y4ga6xFZroRs9YW3xA@public.gmane.org> wrote:
>>> On Fri, Mar 20, 2015 at 12:55 AM, <roy.qing.li-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
>>>> From: Li RongQing <roy.qing.li-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
>>>>
>>>> After 2f9783669 [ARM: 7412/1: audit: use only AUDIT_ARCH_ARM regardless
>>>> of endianness], no kernel user uses this macro;
>>>>
>>>> Keeping this macro, only makes the compiling old version audit [before
>>>> changeset 931 Improve ARM and AARCH64 support] success, but the audit
>>>> program can not work with the kernel after 2f9783669 still,
>>>> since no syscall entry is enabled for AUDIT_ARCH_ARMEB in kernel.
>>>>
>>>> so remove it to force to use the latest audit program
>>>>
>>>> Signed-off-by: Li RongQing <roy.qing.li-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
>>>> ---
>>>> other workaround is to define AUDIT_ARCH_ARMEB as AUDIT_ARCH_ARM,
>>>> but it seems very strange
>>>>
>>>> include/uapi/linux/audit.h | 1 -
>>>> 1 file changed, 1 deletion(-)
>>>
>>> Since this #define lives in the user visible headers I don't want to
>>> remove it and risk causing a userspace breakage. Leaving the #define
>>> in the header, even if it is
>
>
> it is harm, when I compile the audit-2.3.2 for a arm machine, whose linux kernel
> is 3.14; no compile error, but audit does not work; spend one day debug to find
> the root cause is the audit used MACH_ARMEB, but kernel replaced MACH_ARMEB
> with MACH_ARM
>
> grep WITH_ARMEB ./lib/machinetab.h -A10
> #ifdef WITH_ARMEB
> _S(MACH_ARMEB, "armeb" )
> _S(MACH_ARMEB, "armv5tejl")
> _S(MACH_ARMEB, "armv5tel")
> _S(MACH_ARMEB, "armv6l")
> _S(MACH_ARMEB, "armv7l")
> #endif
>
> removal of MACH_ARMEB will let the user find this issue when compile, not
> run.
[NOTE: Adding the linux-arm folks to this thread just in case they are
interested.]
I'm not an ARM expert, but the kernel #define for AUDIT_ARCH_ARMEB
(below) seems reasonable to me based on the other audit machine
definitions. There is clearly a mismatch between the kernel and the
audit userspace, but I wonder if the issue should be addressed in the
userspace tools. Further, you mention kernel 3.14, what happens with
kernel 3.19 and the most recent audit userspace tools?
> grep "AUDIT_ARCH_ARMEB" include/uapi/linux/audit.h
#define AUDIT_ARCH_ARMEB (EM_ARM)
-Paul
--
paul moore
www.paul-moore.com
^ permalink raw reply
* [PATCH v3 0/9] Add simple EEPROM Framework via regmap.
From: Srinivas Kandagatla @ 2015-03-24 22:28 UTC (permalink / raw)
To: linux-arm-kernel
Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown,
Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
linux-arm-msm, arnd, sboyd, Srinivas Kandagatla
In-Reply-To: <1426240157-2383-1-git-send-email-srinivas.kandagatla@linaro.org>
Thankyou all for providing inputs and comments on previous versions of this patchset.
Here is the v3 of the patchset addressing all the issues raised as
part of previous versions review.
This patchset adds a new simple EEPROM framework to kernel.
Up until now, EEPROM drivers were stored in drivers/misc, where they all had to
duplicate pretty much the same code to register a sysfs file, allow in-kernel
users to access the content of the devices they were driving, etc.
This was also a problem as far as other in-kernel users were involved, since
the solutions used were pretty much different from on driver to another, there
was a rather big abstraction leak.
This introduction of this framework aims at solving this. It also introduces DT
representation for consumer devices to go get the data they require (MAC
Addresses, SoC/Revision ID, part numbers, and so on) from the EEPROMs.
Having regmap interface to this framework would give much better
abstraction for eeproms on different buses.
patch 1-2 Introduces two regmap helper functions.
patch 3-5 Introduces the EEPROM framework.
Patch 6 migrates an existing driver to eeprom framework.
Patch 7-8 Adds Qualcomm specific qfprom driver.
Patch 9 adds entry in MAINTAINERS.
Its also possible to migrate other eeprom drivers to this framework.
Patch 6 can also be made a generic mmio-eeprom driver.
Providers APIs:
eeprom_register/unregister();
Consumers APIs:
eeprom_cell_get()/of_eeprom_cell_get()/of_eeprom_cell_get_byname();
eeprom_cell_put();
eeprom_cell_read()/eeprom_cell_write();
Device Tree:
/* Provider */
qfprom: qfprom@00700000 {
compatible = "qcom,qfprom";
reg = <0x00700000 0x1000>;
...
/* Data cells */
tsens_calibration: calib@404 {
reg = <0x404 0x10>;
};
serial_number: sn {
reg = <0x104 0x4>, <0x204 0x4>, <0x30c 0x4>;
};
...
};
/* Consumer node */
tsens: tsens {
...
eeproms = <&tsens_calibration>;
eeprom-names = "calib";
...
};
userspace interface:
hexdump /sys/class/eeprom/qfprom0/eeprom
0000000 0000 0000 0000 0000 0000 0000 0000 0000
*
00000a0 db10 2240 0000 e000 0c00 0c00 0000 0c00
0000000 0000 0000 0000 0000 0000 0000 0000 0000
...
*
0001000
Changes since v2(https://lkml.org/lkml/2015/3/13/168)
* Fixed error handling in eeprom_register spotted by Mark Brown
* Added new regmap_get_max_register() and regmap_get_reg_stride().
* Fixed module build errors reported by kbuild robot.
* recycle the ids when eeprom provider is released.
Changes since v1(https://lkml.org/lkml/2015/3/5/153)
* Fix various Licencing issues spotted by Paul Bolle and Mark Brown
* Allow eeprom core to build as module spotted by Paul Bolle.
* Fix various kconfig issues spotted by Paul Bolle.
* remove unessary atomic varible spotted by Mark Brown.
* Few cleanups and common up some of the code in core.
* Add qfprom bindings.
Changes since RFC(https://lkml.org/lkml/2015/2/19/307)
* Fix documentation and error checks in read/write spotted by Andrew Lunn
* Kconfig fix suggested by Stephen Boyd.
* Add module owner suggested by Stephen Boyd and others.
* Fix unsafe handling of eeprom in unregister spotted by Russell and Mark Brown.
* seperate bindings patch as suggested by Rob.
* Add MAINTAINERS as suggested by Rob.
* Added support to allow reading eeprom for things like serial number which
* canbe scatters across.
* Added eeprom data using reg property suggested by Sascha and Stephen.
* Added non-DT support.
* Move kerneldoc to the src files spotted by Mark Brown.
* Remove local list and do eeprom lookup by using class_find_device()
Thanks,
srini
Maxime Ripard (1):
eeprom: sunxi: Move the SID driver to the eeprom framework
Srinivas Kandagatla (8):
regmap: Introduce regmap_get_max_register.
regmap: Introduce regmap_get_reg_stride.
eeprom: Add a simple EEPROM framework for eeprom providers
eeprom: Add a simple EEPROM framework for eeprom consumers
eeprom: Add bindings for simple eeprom framework
eeprom: qfprom: Add Qualcomm QFPROM support.
eeprom: qfprom: Add bindings for qfprom
eeprom: Add to MAINTAINERS for eeprom framework
Documentation/ABI/testing/sysfs-driver-sunxi-sid | 22 -
.../bindings/eeprom/allwinner,sunxi-sid.txt | 21 +
.../devicetree/bindings/eeprom/eeprom.txt | 70 +++
.../devicetree/bindings/eeprom/qfprom.txt | 23 +
.../bindings/misc/allwinner,sunxi-sid.txt | 17 -
MAINTAINERS | 9 +
drivers/Kconfig | 2 +
drivers/Makefile | 1 +
drivers/base/regmap/regmap.c | 23 +
drivers/eeprom/Kconfig | 37 ++
drivers/eeprom/Makefile | 12 +
drivers/eeprom/core.c | 531 +++++++++++++++++++++
drivers/eeprom/qfprom.c | 87 ++++
drivers/eeprom/sunxi-sid.c | 136 ++++++
drivers/misc/eeprom/Kconfig | 13 -
drivers/misc/eeprom/Makefile | 1 -
drivers/misc/eeprom/sunxi_sid.c | 156 ------
include/linux/eeprom-consumer.h | 67 +++
include/linux/eeprom-provider.h | 42 ++
include/linux/regmap.h | 14 +
20 files changed, 1075 insertions(+), 209 deletions(-)
delete mode 100644 Documentation/ABI/testing/sysfs-driver-sunxi-sid
create mode 100644 Documentation/devicetree/bindings/eeprom/allwinner,sunxi-sid.txt
create mode 100644 Documentation/devicetree/bindings/eeprom/eeprom.txt
create mode 100644 Documentation/devicetree/bindings/eeprom/qfprom.txt
delete mode 100644 Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt
create mode 100644 drivers/eeprom/Kconfig
create mode 100644 drivers/eeprom/Makefile
create mode 100644 drivers/eeprom/core.c
create mode 100644 drivers/eeprom/qfprom.c
create mode 100644 drivers/eeprom/sunxi-sid.c
delete mode 100644 drivers/misc/eeprom/sunxi_sid.c
create mode 100644 include/linux/eeprom-consumer.h
create mode 100644 include/linux/eeprom-provider.h
--
1.9.1
^ permalink raw reply
* [PATCH v3 1/9] regmap: Introduce regmap_get_max_register.
From: Srinivas Kandagatla @ 2015-03-24 22:29 UTC (permalink / raw)
To: linux-arm-kernel
Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown,
Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
linux-arm-msm, arnd, sboyd, Srinivas Kandagatla
In-Reply-To: <1427236116-18531-1-git-send-email-srinivas.kandagatla@linaro.org>
This patch introduces regmap_get_max_register() function which would be
used by the infrastructures like eeprom framework built on top of
regmap.
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
drivers/base/regmap/regmap.c | 12 ++++++++++++
include/linux/regmap.h | 7 +++++++
2 files changed, 19 insertions(+)
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index d2f8a81..6fd234b 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -2616,6 +2616,18 @@ int regmap_get_val_bytes(struct regmap *map)
}
EXPORT_SYMBOL_GPL(regmap_get_val_bytes);
+/*
+ * regmap_get_max_register(): Report the max register value
+ *
+ * Report the max register value, mainly intended to for use by
+ * generic infrastructure built on top of regmap.
+ */
+int regmap_get_max_register(struct regmap *map)
+{
+ return map->max_register ? : -EINVAL;
+}
+EXPORT_SYMBOL_GPL(regmap_get_max_register);
+
int regmap_parse_val(struct regmap *map, const void *buf,
unsigned int *val)
{
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index 4419b99..c46dbf3 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -433,6 +433,7 @@ int regmap_update_bits_check_async(struct regmap *map, unsigned int reg,
unsigned int mask, unsigned int val,
bool *change);
int regmap_get_val_bytes(struct regmap *map);
+int regmap_get_max_register(struct regmap *map);
int regmap_async_complete(struct regmap *map);
bool regmap_can_raw_write(struct regmap *map);
@@ -676,6 +677,12 @@ static inline int regmap_get_val_bytes(struct regmap *map)
return -EINVAL;
}
+static inline int regmap_get_max_register(struct regmap *map)
+{
+ WARN_ONCE(1, "regmap API is disabled");
+ return -EINVAL;
+}
+
static inline int regcache_sync(struct regmap *map)
{
WARN_ONCE(1, "regmap API is disabled");
--
1.9.1
^ permalink raw reply related
* [PATCH v3 2/9] regmap: Introduce regmap_get_reg_stride.
From: Srinivas Kandagatla @ 2015-03-24 22:30 UTC (permalink / raw)
To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown,
Greg Kroah-Hartman, linux-api-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-msm-u79uwXL29TY76Z2rM5mHXA, arnd-r2nGTMty4D4,
sboyd-sgV2jX0FEOL9JmXXK+q4OQ, Srinivas Kandagatla
In-Reply-To: <1427236116-18531-1-git-send-email-srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
This patch introduces regmap_get_reg_stride() function which would
be used by the infrastructures like eeprom framework built on top of
regmap. Mostly this function would be used for sanity checks on inputs
within such infrastructure.
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
---
drivers/base/regmap/regmap.c | 11 +++++++++++
include/linux/regmap.h | 7 +++++++
2 files changed, 18 insertions(+)
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 6fd234b..44d3d94 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -2628,6 +2628,17 @@ int regmap_get_max_register(struct regmap *map)
}
EXPORT_SYMBOL_GPL(regmap_get_max_register);
+ /* regmap_get_reg_stride(): Report the register address stride
+ *
+ * Report the register address stride, mainly intended to for use by
+ * generic infrastructure built on top of regmap.
+ */
+int regmap_get_reg_stride(struct regmap *map)
+{
+ return map->reg_stride;
+}
+EXPORT_SYMBOL_GPL(regmap_get_reg_stride);
+
int regmap_parse_val(struct regmap *map, const void *buf,
unsigned int *val)
{
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index c46dbf3..b58067c 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -434,6 +434,7 @@ int regmap_update_bits_check_async(struct regmap *map, unsigned int reg,
bool *change);
int regmap_get_val_bytes(struct regmap *map);
int regmap_get_max_register(struct regmap *map);
+int regmap_get_reg_stride(struct regmap *map);
int regmap_async_complete(struct regmap *map);
bool regmap_can_raw_write(struct regmap *map);
@@ -683,6 +684,12 @@ static inline int regmap_get_max_register(struct regmap *map)
return -EINVAL;
}
+static inline int regmap_get_reg_stride(struct regmap *map)
+{
+ WARN_ONCE(1, "regmap API is disabled");
+ return -EINVAL;
+}
+
static inline int regcache_sync(struct regmap *map)
{
WARN_ONCE(1, "regmap API is disabled");
--
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 related
* [PATCH v3 3/9] eeprom: Add a simple EEPROM framework for eeprom providers
From: Srinivas Kandagatla @ 2015-03-24 22:30 UTC (permalink / raw)
To: linux-arm-kernel
Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown,
Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
linux-arm-msm, arnd, sboyd, Srinivas Kandagatla
In-Reply-To: <1427236116-18531-1-git-send-email-srinivas.kandagatla@linaro.org>
This patch adds just providers part of the framework just to enable easy
review.
Up until now, EEPROM drivers were stored in drivers/misc, where they all had to
duplicate pretty much the same code to register a sysfs file, allow in-kernel
users to access the content of the devices they were driving, etc.
This was also a problem as far as other in-kernel users were involved, since
the solutions used were pretty much different from on driver to another, there
was a rather big abstraction leak.
This introduction of this framework aims at solving this. It also introduces DT
representation for consumer devices to go get the data they require (MAC
Addresses, SoC/Revision ID, part numbers, and so on) from the EEPROMs.
Having regmap interface to this framework would give much better
abstraction for eeproms on different buses.
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
[Maxime Ripard: intial version of eeprom framework]
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
drivers/Kconfig | 2 +
drivers/Makefile | 1 +
drivers/eeprom/Kconfig | 11 ++
drivers/eeprom/Makefile | 6 ++
drivers/eeprom/core.c | 227 ++++++++++++++++++++++++++++++++++++++++
include/linux/eeprom-provider.h | 42 ++++++++
6 files changed, 289 insertions(+)
create mode 100644 drivers/eeprom/Kconfig
create mode 100644 drivers/eeprom/Makefile
create mode 100644 drivers/eeprom/core.c
create mode 100644 include/linux/eeprom-provider.h
diff --git a/drivers/Kconfig b/drivers/Kconfig
index c70d6e4..d7afc82 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -184,4 +184,6 @@ source "drivers/thunderbolt/Kconfig"
source "drivers/android/Kconfig"
+source "drivers/eeprom/Kconfig"
+
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 527a6da..57eb5b0 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -165,3 +165,4 @@ obj-$(CONFIG_RAS) += ras/
obj-$(CONFIG_THUNDERBOLT) += thunderbolt/
obj-$(CONFIG_CORESIGHT) += coresight/
obj-$(CONFIG_ANDROID) += android/
+obj-$(CONFIG_EEPROM) += eeprom/
diff --git a/drivers/eeprom/Kconfig b/drivers/eeprom/Kconfig
new file mode 100644
index 0000000..21e1847
--- /dev/null
+++ b/drivers/eeprom/Kconfig
@@ -0,0 +1,11 @@
+menuconfig EEPROM
+ tristate "EEPROM Support"
+ depends on OF
+ select REGMAP
+ help
+ Support for EEPROM alike devices.
+
+ This framework is designed to provide a generic interface to EEPROM
+ from both the Linux Kernel and the userspace.
+
+ If unsure, say no.
diff --git a/drivers/eeprom/Makefile b/drivers/eeprom/Makefile
new file mode 100644
index 0000000..51a727f
--- /dev/null
+++ b/drivers/eeprom/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for eeprom drivers.
+#
+
+obj-$(CONFIG_EEPROM) += eeprom_core.o
+eeprom_core-y := core.o
diff --git a/drivers/eeprom/core.c b/drivers/eeprom/core.c
new file mode 100644
index 0000000..9fd556c
--- /dev/null
+++ b/drivers/eeprom/core.c
@@ -0,0 +1,227 @@
+/*
+ * EEPROM framework core.
+ *
+ * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+ * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/eeprom-provider.h>
+#include <linux/export.h>
+#include <linux/fs.h>
+#include <linux/idr.h>
+#include <linux/init.h>
+#include <linux/regmap.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+struct eeprom_device {
+ struct regmap *regmap;
+ int stride;
+ size_t size;
+
+ struct module *owner;
+ struct device dev;
+ int id;
+ int users;
+};
+
+static DEFINE_MUTEX(eeprom_mutex);
+static DEFINE_IDA(eeprom_ida);
+
+#define to_eeprom(d) container_of(d, struct eeprom_device, dev)
+
+static ssize_t bin_attr_eeprom_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t offset, size_t count)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct eeprom_device *eeprom = to_eeprom(dev);
+ int rc;
+
+ if (offset > eeprom->size)
+ return -EINVAL;
+
+ if (offset + count > eeprom->size)
+ count = eeprom->size - offset;
+
+ rc = regmap_bulk_read(eeprom->regmap, offset,
+ buf, count/eeprom->stride);
+
+ if (IS_ERR_VALUE(rc))
+ return rc;
+
+ return count - count % eeprom->stride;
+}
+
+static ssize_t bin_attr_eeprom_write(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t offset, size_t count)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct eeprom_device *eeprom = to_eeprom(dev);
+ int rc;
+
+ if (offset > eeprom->size)
+ return -EINVAL;
+
+ if (offset + count > eeprom->size)
+ count = eeprom->size - offset;
+
+ rc = regmap_bulk_write(eeprom->regmap, offset,
+ buf, count/eeprom->stride);
+
+ if (IS_ERR_VALUE(rc))
+ return rc;
+
+ return count - count % eeprom->stride;
+}
+
+static struct bin_attribute bin_attr_eeprom = {
+ .attr = {
+ .name = "eeprom",
+ .mode = S_IWUSR | S_IRUGO,
+ },
+ .read = bin_attr_eeprom_read,
+ .write = bin_attr_eeprom_write,
+};
+
+static struct bin_attribute *eeprom_bin_attributes[] = {
+ &bin_attr_eeprom,
+ NULL,
+};
+
+static const struct attribute_group eeprom_bin_group = {
+ .bin_attrs = eeprom_bin_attributes,
+};
+
+static const struct attribute_group *eeprom_dev_groups[] = {
+ &eeprom_bin_group,
+ NULL,
+};
+
+static void eeprom_release(struct device *dev)
+{
+ struct eeprom_device *eeprom = to_eeprom(dev);
+
+ ida_simple_remove(&eeprom_ida, eeprom->id);
+ kfree(eeprom);
+}
+
+static struct class eeprom_class = {
+ .name = "eeprom",
+ .dev_groups = eeprom_dev_groups,
+ .dev_release = eeprom_release,
+};
+
+/**
+ * eeprom_register(): Register a eeprom device for given eeprom.
+ * Also creates an binary entry in /sys/class/eeprom/name-id/eeprom
+ *
+ * @eeprom: eeprom device that needs to be created
+ *
+ * The return value will be an error code on error or a zero on success.
+ * The eeprom_device and sysfs entery will be freed by the eeprom_unregister().
+ */
+
+struct eeprom_device *eeprom_register(struct eeprom_config *config)
+{
+ struct eeprom_device *eeprom;
+ struct regmap *rm;
+ int rval;
+
+ if (!config->dev)
+ return ERR_PTR(-EINVAL);
+
+ rm = dev_get_regmap(config->dev, NULL);
+ if (!rm) {
+ dev_err(config->dev, "Regmap not found\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ eeprom = kzalloc(sizeof(*eeprom), GFP_KERNEL);
+ if (!eeprom)
+ return ERR_PTR(-ENOMEM);
+
+ eeprom->id = ida_simple_get(&eeprom_ida, 0, 0, GFP_KERNEL);
+ if (eeprom->id < 0) {
+ kfree(eeprom);
+ return ERR_PTR(eeprom->id);
+ }
+
+ eeprom->regmap = rm;
+ eeprom->owner = config->owner;
+ eeprom->stride = regmap_get_reg_stride(rm);
+ eeprom->size = regmap_get_max_register(rm);
+ eeprom->dev.class = &eeprom_class;
+ eeprom->dev.parent = config->dev;
+ eeprom->dev.of_node = config->dev ? config->dev->of_node : NULL;
+ dev_set_name(&eeprom->dev, "%s%d",
+ config->name ? : "eeprom", config->id);
+
+ device_initialize(&eeprom->dev);
+
+ dev_dbg(&eeprom->dev, "Registering eeprom device %s\n",
+ dev_name(&eeprom->dev));
+
+ rval = device_add(&eeprom->dev);
+ if (rval) {
+ ida_simple_remove(&eeprom_ida, eeprom->id);
+ kfree(eeprom);
+ return ERR_PTR(rval);
+ }
+
+ return eeprom;
+}
+EXPORT_SYMBOL_GPL(eeprom_register);
+
+/**
+ * eeprom_unregister(): Unregister previously registered eeprom device
+ *
+ * @eeprom: Pointer to previously registered eeprom device.
+ *
+ * The return value will be an non zero on error or a zero on success.
+ */
+int eeprom_unregister(struct eeprom_device *eeprom)
+{
+ mutex_lock(&eeprom_mutex);
+ if (eeprom->users) {
+ mutex_unlock(&eeprom_mutex);
+ return -EBUSY;
+ }
+ mutex_unlock(&eeprom_mutex);
+
+ device_del(&eeprom->dev);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(eeprom_unregister);
+
+static int eeprom_init(void)
+{
+ return class_register(&eeprom_class);
+}
+
+static void eeprom_exit(void)
+{
+ class_unregister(&eeprom_class);
+}
+
+subsys_initcall(eeprom_init);
+module_exit(eeprom_exit);
+
+MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org");
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com");
+MODULE_DESCRIPTION("EEPROM Driver Core");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/eeprom-provider.h b/include/linux/eeprom-provider.h
new file mode 100644
index 0000000..f2efa07
--- /dev/null
+++ b/include/linux/eeprom-provider.h
@@ -0,0 +1,42 @@
+/*
+ * EEPROM framework provider.
+ *
+ * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+ * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef _LINUX_EEPROM_PROVIDER_H
+#define _LINUX_EEPROM_PROVIDER_H
+
+struct eeprom_device;
+
+struct eeprom_config {
+ struct device *dev;
+ const char *name;
+ int id;
+ struct module *owner;
+};
+
+#if IS_ENABLED(CONFIG_EEPROM)
+
+struct eeprom_device *eeprom_register(struct eeprom_config *cfg);
+int eeprom_unregister(struct eeprom_device *eeprom);
+
+#else
+
+static inline struct eeprom_device *eeprom_register(struct eeprom_config *cfg)
+{
+ return NULL;
+}
+static inline int eeprom_unregister(struct eeprom_device *eeprom)
+{
+ return -ENOSYS;
+}
+
+#endif /* CONFIG_EEPROM */
+
+#endif /* ifndef _LINUX_EEPROM_PROVIDER_H */
--
1.9.1
^ permalink raw reply related
* [PATCH v3 4/9] eeprom: Add a simple EEPROM framework for eeprom consumers
From: Srinivas Kandagatla @ 2015-03-24 22:30 UTC (permalink / raw)
To: linux-arm-kernel
Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown,
Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
linux-arm-msm, arnd, sboyd, Srinivas Kandagatla
In-Reply-To: <1427236116-18531-1-git-send-email-srinivas.kandagatla@linaro.org>
This patch adds just consumers part of the framework just to enable easy
review.
Up until now, EEPROM drivers were stored in drivers/misc, where they all had to
duplicate pretty much the same code to register a sysfs file, allow in-kernel
users to access the content of the devices they were driving, etc.
This was also a problem as far as other in-kernel users were involved, since
the solutions used were pretty much different from on driver to another, there
was a rather big abstraction leak.
This introduction of this framework aims at solving this. It also introduces DT
representation for consumer devices to go get the data they require (MAC
Addresses, SoC/Revision ID, part numbers, and so on) from the EEPROMs.
Having regmap interface to this framework would give much better
abstraction for eeproms on different buses.
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
[Maxime Ripard: intial version of the framework]
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
drivers/eeprom/core.c | 304 ++++++++++++++++++++++++++++++++++++++++
include/linux/eeprom-consumer.h | 67 +++++++++
2 files changed, 371 insertions(+)
create mode 100644 include/linux/eeprom-consumer.h
diff --git a/drivers/eeprom/core.c b/drivers/eeprom/core.c
index 9fd556c..43d03ef 100644
--- a/drivers/eeprom/core.c
+++ b/drivers/eeprom/core.c
@@ -16,6 +16,7 @@
#include <linux/device.h>
#include <linux/eeprom-provider.h>
+#include <linux/eeprom-consumer.h>
#include <linux/export.h>
#include <linux/fs.h>
#include <linux/idr.h>
@@ -37,6 +38,13 @@ struct eeprom_device {
int users;
};
+struct eeprom_cell {
+ struct eeprom_device *eeprom;
+ int nblocks;
+ int size;
+ struct eeprom_block blocks[0];
+};
+
static DEFINE_MUTEX(eeprom_mutex);
static DEFINE_IDA(eeprom_ida);
@@ -125,6 +133,37 @@ static struct class eeprom_class = {
.dev_release = eeprom_release,
};
+static int of_eeprom_match(struct device *dev, const void *eeprom_np)
+{
+ return dev->of_node == eeprom_np;
+}
+
+static struct eeprom_device *of_eeprom_find(struct device_node *eeprom_np)
+{
+ struct device *d;
+
+ if (!eeprom_np)
+ return NULL;
+
+ d = class_find_device(&eeprom_class, NULL, eeprom_np, of_eeprom_match);
+
+ return d ? to_eeprom(d) : NULL;
+}
+
+static int eeprom_match(struct device *dev, const void *data)
+{
+ return !strcmp(dev_name(dev), (const char *)data);
+}
+
+static struct eeprom_device *eeprom_find(const char *name)
+{
+ struct device *d;
+
+ d = class_find_device(&eeprom_class, NULL, (void *)name, eeprom_match);
+
+ return d ? to_eeprom(d) : NULL;
+}
+
/**
* eeprom_register(): Register a eeprom device for given eeprom.
* Also creates an binary entry in /sys/class/eeprom/name-id/eeprom
@@ -208,6 +247,271 @@ int eeprom_unregister(struct eeprom_device *eeprom)
}
EXPORT_SYMBOL_GPL(eeprom_unregister);
+static int eeprom_cell_sanity_check(struct eeprom_cell *cell)
+{
+ struct eeprom_device *eeprom = cell->eeprom;
+ int i;
+
+ /* byte aligned, no need to check for stride sanity */
+ if (eeprom->stride == 1)
+ return 0;
+
+ for (i = 0; i < cell->nblocks; i++) {
+ if (!IS_ALIGNED(cell->blocks[i].offset, eeprom->stride) ||
+ !IS_ALIGNED(cell->blocks[i].count, eeprom->stride)) {
+ dev_err(&eeprom->dev,
+ "cell unaligned to eeprom stride %d\n",
+ eeprom->stride);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static struct eeprom_cell *__eeprom_cell_get(struct device_node *cell_np,
+ const char *ename,
+ struct eeprom_block *blocks,
+ int nblocks)
+{
+ struct eeprom_cell *cell;
+ struct eeprom_device *eeprom = NULL;
+ struct property *prop;
+ const __be32 *vp;
+ u32 pv;
+ int i, rval;
+
+ mutex_lock(&eeprom_mutex);
+
+ eeprom = cell_np ? of_eeprom_find(cell_np->parent) : eeprom_find(ename);
+ if (!eeprom) {
+ mutex_unlock(&eeprom_mutex);
+ return ERR_PTR(-EPROBE_DEFER);
+ }
+
+ eeprom->users++;
+ mutex_unlock(&eeprom_mutex);
+
+ if (!try_module_get(eeprom->owner)) {
+ dev_err(&eeprom->dev,
+ "could not increase module refcount for cell %s\n",
+ ename);
+ rval = -EINVAL;
+ goto err_mod;
+ }
+
+ if (cell_np)
+ nblocks = of_property_count_u32_elems(cell_np, "reg") / 2;
+
+ cell = kzalloc(sizeof(*cell) + nblocks * sizeof(*blocks), GFP_KERNEL);
+ if (!cell) {
+ rval = -ENOMEM;
+ goto err_mem;
+ }
+
+ cell->nblocks = nblocks;
+ cell->eeprom = eeprom;
+ cell->size = 0;
+ i = 0;
+
+ if (cell_np) {
+ of_property_for_each_u32(cell_np, "reg", prop, vp, pv) {
+ cell->blocks[i].offset = pv;
+ vp = of_prop_next_u32(prop, vp, &pv);
+ cell->blocks[i].count = pv;
+ cell->size += pv;
+ i++;
+ }
+ } else {
+ memcpy(cell->blocks, blocks, nblocks * sizeof(*blocks));
+ for (; i < nblocks; i++)
+ cell->size += blocks[i].count;
+ }
+
+ if (IS_ERR_VALUE(eeprom_cell_sanity_check(cell))) {
+ rval = -EINVAL;
+ goto err_sanity;
+ }
+
+ return cell;
+
+err_sanity:
+ kfree(cell);
+
+err_mem:
+ module_put(eeprom->owner);
+
+err_mod:
+ mutex_lock(&eeprom_mutex);
+ eeprom->users--;
+ mutex_unlock(&eeprom_mutex);
+
+ return ERR_PTR(rval);
+
+}
+
+/**
+ * eeprom_cell_get(): Get eeprom cell of device form a given eeprom name
+ * and blocks.
+ *
+ * @ename: eeprom device name that needs to be looked-up.
+ * @blocks: eeprom blocks containing offset and length information.
+ * @nblocks: number of eeprom blocks.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct eeprom_cell. The eeprom_cell will be freed by the
+ * eeprom_cell_put().
+ */
+struct eeprom_cell *eeprom_cell_get(const char *ename,
+ struct eeprom_block *blocks, int nblocks)
+{
+ return __eeprom_cell_get(NULL, ename, blocks, nblocks);
+}
+EXPORT_SYMBOL_GPL(eeprom_cell_get);
+
+/**
+ * of_eeprom_cell_get(): Get eeprom cell of device form a given index
+ *
+ * @dev: Device that will be interacted with
+ * @index: eeprom index in eeproms property.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct eeprom_cell. The eeprom_cell will be freed by the
+ * eeprom_cell_put().
+ */
+struct eeprom_cell *of_eeprom_cell_get(struct device *dev, int index)
+{
+ struct device_node *cell_np;
+
+ if (!dev || !dev->of_node)
+ return ERR_PTR(-EINVAL);
+
+ cell_np = of_parse_phandle(dev->of_node, "eeproms", index);
+ if (!cell_np)
+ return ERR_PTR(-EPROBE_DEFER);
+
+ return __eeprom_cell_get(cell_np, NULL, NULL, 0);
+}
+EXPORT_SYMBOL_GPL(of_eeprom_cell_get);
+
+/**
+ * of_eeprom_cell_get_byname(): Get eeprom cell of device form a given name
+ *
+ * @dev: Device that will be interacted with
+ * @name: eeprom name in eeprom-names property.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct eeprom_cell. The eeprom_cell will be freed by the
+ * eeprom_cell_put().
+ */
+struct eeprom_cell *of_eeprom_cell_get_byname(struct device *dev,
+ const char *id)
+{
+ int index = 0;
+
+ if (!dev || !dev->of_node)
+ return ERR_PTR(-EINVAL);
+
+ if (id)
+ index = of_property_match_string(dev->of_node,
+ "eeprom-names",
+ id);
+ return of_eeprom_cell_get(dev, index);
+
+}
+EXPORT_SYMBOL_GPL(of_eeprom_cell_get_byname);
+
+/**
+ * eeprom_cell_put(): Release previously allocated eeprom cell.
+ *
+ * @cell: Previously allocated eeprom cell by eeprom_cell_get()
+ * or of_eeprom_cell_get() or of_eeprom_cell_get_byname().
+ */
+void eeprom_cell_put(struct eeprom_cell *cell)
+{
+ struct eeprom_device *eeprom = cell->eeprom;
+
+ mutex_lock(&eeprom_mutex);
+ eeprom->users--;
+ mutex_unlock(&eeprom_mutex);
+ module_put(eeprom->owner);
+ kfree(cell);
+}
+EXPORT_SYMBOL_GPL(eeprom_cell_put);
+
+/**
+ * eeprom_cell_read(): Read a given eeprom cell
+ *
+ * @cell: eeprom cell to be read.
+ * @len: pointer to length of cell which will be populated on successful read.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a char * bufffer. The buffer should be freed by the consumer with a
+ * kfree().
+ */
+char *eeprom_cell_read(struct eeprom_cell *cell, ssize_t *len)
+{
+ struct eeprom_device *eeprom = cell->eeprom;
+ char *buf;
+ int rc, i, offset = 0;
+
+ if (!eeprom || !eeprom->regmap)
+ return ERR_PTR(-EINVAL);
+
+ buf = kzalloc(cell->size, GFP_KERNEL);
+ if (!buf)
+ return ERR_PTR(-ENOMEM);
+
+ for (i = 0; i < cell->nblocks; i++) {
+ rc = regmap_bulk_read(eeprom->regmap, cell->blocks[i].offset,
+ buf + offset,
+ cell->blocks[i].count);
+
+ if (IS_ERR_VALUE(rc)) {
+ kfree(buf);
+ return ERR_PTR(rc);
+ }
+ offset += cell->blocks[i].count;
+ }
+
+ *len = cell->size;
+
+ return buf;
+}
+EXPORT_SYMBOL_GPL(eeprom_cell_read);
+
+/**
+ * eeprom_cell_write(): Write to a given eeprom cell
+ *
+ * @cell: eeprom cell to be written.
+ * @buf: Buffer to be written.
+ * @len: length of buffer to be written to eeprom cell.
+ *
+ * The return value will be an non zero on error or a zero on successful write.
+ */
+int eeprom_cell_write(struct eeprom_cell *cell, const char *buf, ssize_t len)
+{
+ struct eeprom_device *eeprom = cell->eeprom;
+ int i, rc, offset = 0;
+
+ if (!eeprom || !eeprom->regmap || len != cell->size)
+ return -EINVAL;
+
+ for (i = 0; i < cell->nblocks; i++) {
+ rc = regmap_bulk_write(eeprom->regmap, cell->blocks[i].offset,
+ buf + offset,
+ cell->blocks[i].count);
+
+ if (IS_ERR_VALUE(rc))
+ return rc;
+
+ offset += cell->blocks[i].count;
+ }
+
+ return len;
+}
+EXPORT_SYMBOL_GPL(eeprom_cell_write);
+
static int eeprom_init(void)
{
return class_register(&eeprom_class);
diff --git a/include/linux/eeprom-consumer.h b/include/linux/eeprom-consumer.h
new file mode 100644
index 0000000..6d9d075
--- /dev/null
+++ b/include/linux/eeprom-consumer.h
@@ -0,0 +1,67 @@
+/*
+ * EEPROM framework consumer.
+ *
+ * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+ * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef _LINUX_EEPROM_CONSUMER_H
+#define _LINUX_EEPROM_CONSUMER_H
+
+struct eeprom_cell;
+
+struct eeprom_block {
+ loff_t offset;
+ size_t count;
+};
+#if IS_ENABLED(CONFIG_EEPROM)
+struct eeprom_cell *eeprom_cell_get(const char *ename,
+ struct eeprom_block *blocks, int nblocks);
+void eeprom_cell_put(struct eeprom_cell *cell);
+char *eeprom_cell_read(struct eeprom_cell *cell, ssize_t *len);
+int eeprom_cell_write(struct eeprom_cell *cell, const char *buf, ssize_t len);
+#else
+
+static inline struct eeprom_cell *eeprom_cell_get(const char *ename,
+ struct eeprom_block *blocks, int nblocks)
+{
+ return NULL;
+}
+
+static inline void eeprom_cell_put(struct eeprom_cell *cell)
+{
+}
+
+static inline char *eeprom_cell_read(struct eeprom_cell *cell, ssize_t *len)
+{
+ return NULL;
+}
+
+static inline int eeprom_cell_write(struct eeprom_cell *cell,
+ const char *buf, ssize_t len)
+{
+ return -ENOSYS;
+}
+#endif /* CONFIG_EEPROM */
+
+#if IS_ENABLED(CONFIG_EEPROM) && IS_ENABLED(CONFIG_OF)
+struct eeprom_cell *of_eeprom_cell_get(struct device *dev, int index);
+struct eeprom_cell *of_eeprom_cell_get_byname(struct device *dev,
+ const char *name);
+#else
+static inline struct eeprom_cell *of_eeprom_cell_get(
+ struct device *dev, int index)
+{
+ return NULL;
+}
+static inline struct eeprom_cell *of_eeprom_cell_get_byname(struct device *dev,
+ const char *name)
+{
+ return NULL;
+}
+#endif
+#endif /* ifndef _LINUX_EEPROM_CONSUMER_H */
--
1.9.1
^ permalink raw reply related
* [PATCH v3 5/9] eeprom: Add bindings for simple eeprom framework
From: Srinivas Kandagatla @ 2015-03-24 22:30 UTC (permalink / raw)
To: linux-arm-kernel
Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown,
Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
linux-arm-msm, arnd, sboyd, Srinivas Kandagatla
In-Reply-To: <1427236116-18531-1-git-send-email-srinivas.kandagatla@linaro.org>
This patch adds bindings for simple eeprom framework which allows eeprom
consumers to talk to eeprom providers to get access to eeprom cell data.
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
[Maxime Ripard: intial version of eeprom framework]
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
.../devicetree/bindings/eeprom/eeprom.txt | 70 ++++++++++++++++++++++
1 file changed, 70 insertions(+)
create mode 100644 Documentation/devicetree/bindings/eeprom/eeprom.txt
diff --git a/Documentation/devicetree/bindings/eeprom/eeprom.txt b/Documentation/devicetree/bindings/eeprom/eeprom.txt
new file mode 100644
index 0000000..8348d18
--- /dev/null
+++ b/Documentation/devicetree/bindings/eeprom/eeprom.txt
@@ -0,0 +1,70 @@
+= EEPROM Data Device Tree Bindings =
+
+This binding is intended to represent the location of hardware
+configuration data stored in EEPROMs.
+
+On a significant proportion of boards, the manufacturer has stored
+some data on an EEPROM-like device, for the OS to be able to retrieve
+these information and act upon it. Obviously, the OS has to know
+about where to retrieve these data from, and where they are stored on
+the storage device.
+
+This document is here to document this.
+
+= Data providers =
+Contains bindings specific to provider drivers and data cells as children
+to this node.
+
+= Data cells =
+These are the child nodes of the provider which contain data cell
+information like offset and size in eeprom provider.
+
+Required properties:
+reg: specifies the offset in byte within that storage device, and the length
+ in bytes of the data we care about.
+ There could be more then one offset-length pairs in this property.
+
+Optional properties:
+As required by specific data parsers/interpreters.
+
+For example:
+
+ /* Provider */
+ qfprom: qfprom@00700000 {
+ compatible = "qcom,qfprom";
+ reg = <0x00700000 0x1000>;
+ ...
+
+ /* Data cells */
+ tsens_calibration: calib@404 {
+ reg = <0x404 0x10>;
+ };
+
+ serial_number: sn {
+ reg = <0x104 0x4>, <0x204 0x4>, <0x30c 0x4>;
+
+ };
+ ...
+ };
+
+= Data consumers =
+Are device nodes which consume eeprom data cells.
+
+Required properties:
+
+eeproms: List of phandle and data cell the device might be interested in.
+
+Optional properties:
+
+eeprom-names: List of data cell name strings sorted in the same order
+ as the eeproms property. Consumers drivers will use
+ eeprom-names to differentiate between multiple cells,
+ and hence being able to know what these cells are for.
+
+For example:
+
+ tsens {
+ ...
+ eeproms = <&tsens_calibration>;
+ eeprom-names = "calibration";
+ };
--
1.9.1
^ permalink raw reply related
* [PATCH v3 6/9] eeprom: sunxi: Move the SID driver to the eeprom framework
From: Srinivas Kandagatla @ 2015-03-24 22:30 UTC (permalink / raw)
To: linux-arm-kernel
Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown,
Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
linux-arm-msm, arnd, sboyd, Srinivas Kandagatla
In-Reply-To: <1427236116-18531-1-git-send-email-srinivas.kandagatla@linaro.org>
From: Maxime Ripard <maxime.ripard@free-electrons.com>
Now that we have the EEPROM framework, we can consolidate the common driver
code. Move the driver to the framework, and hopefully, it will fix the sysfs
file creation race.
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
[srinivas.kandagatla: Moved to regmap based EEPROM framework]
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
Documentation/ABI/testing/sysfs-driver-sunxi-sid | 22 ---
.../bindings/eeprom/allwinner,sunxi-sid.txt | 21 +++
.../bindings/misc/allwinner,sunxi-sid.txt | 17 ---
drivers/eeprom/Kconfig | 15 ++
drivers/eeprom/Makefile | 4 +
drivers/eeprom/sunxi-sid.c | 136 ++++++++++++++++++
drivers/misc/eeprom/Kconfig | 13 --
drivers/misc/eeprom/Makefile | 1 -
drivers/misc/eeprom/sunxi_sid.c | 156 ---------------------
9 files changed, 176 insertions(+), 209 deletions(-)
delete mode 100644 Documentation/ABI/testing/sysfs-driver-sunxi-sid
create mode 100644 Documentation/devicetree/bindings/eeprom/allwinner,sunxi-sid.txt
delete mode 100644 Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt
create mode 100644 drivers/eeprom/sunxi-sid.c
delete mode 100644 drivers/misc/eeprom/sunxi_sid.c
diff --git a/Documentation/ABI/testing/sysfs-driver-sunxi-sid b/Documentation/ABI/testing/sysfs-driver-sunxi-sid
deleted file mode 100644
index ffb9536..0000000
--- a/Documentation/ABI/testing/sysfs-driver-sunxi-sid
+++ /dev/null
@@ -1,22 +0,0 @@
-What: /sys/devices/*/<our-device>/eeprom
-Date: August 2013
-Contact: Oliver Schinagl <oliver@schinagl.nl>
-Description: read-only access to the SID (Security-ID) on current
- A-series SoC's from Allwinner. Currently supports A10, A10s, A13
- and A20 CPU's. The earlier A1x series of SoCs exports 16 bytes,
- whereas the newer A20 SoC exposes 512 bytes split into sections.
- Besides the 16 bytes of SID, there's also an SJTAG area,
- HDMI-HDCP key and some custom keys. Below a quick overview, for
- details see the user manual:
- 0x000 128 bit root-key (sun[457]i)
- 0x010 128 bit boot-key (sun7i)
- 0x020 64 bit security-jtag-key (sun7i)
- 0x028 16 bit key configuration (sun7i)
- 0x02b 16 bit custom-vendor-key (sun7i)
- 0x02c 320 bit low general key (sun7i)
- 0x040 32 bit read-control access (sun7i)
- 0x064 224 bit low general key (sun7i)
- 0x080 2304 bit HDCP-key (sun7i)
- 0x1a0 768 bit high general key (sun7i)
-Users: any user space application which wants to read the SID on
- Allwinner's A-series of CPU's.
diff --git a/Documentation/devicetree/bindings/eeprom/allwinner,sunxi-sid.txt b/Documentation/devicetree/bindings/eeprom/allwinner,sunxi-sid.txt
new file mode 100644
index 0000000..cceaaf6
--- /dev/null
+++ b/Documentation/devicetree/bindings/eeprom/allwinner,sunxi-sid.txt
@@ -0,0 +1,21 @@
+Allwinner sunxi-sid
+
+Required properties:
+- compatible: "allwinner,sun4i-a10-sid" or "allwinner,sun7i-a20-sid"
+- reg: Should contain registers location and length
+
+= Data cells =
+Are child nodes of qfprom, bindings of which as described in
+bindings/eeprom/eeprom.txt
+
+Example for sun4i:
+ sid@01c23800 {
+ compatible = "allwinner,sun4i-a10-sid";
+ reg = <0x01c23800 0x10>
+ };
+
+Example for sun7i:
+ sid@01c23800 {
+ compatible = "allwinner,sun7i-a20-sid";
+ reg = <0x01c23800 0x200>
+ };
diff --git a/Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt b/Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt
deleted file mode 100644
index fabdf64..0000000
--- a/Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-Allwinner sunxi-sid
-
-Required properties:
-- compatible: "allwinner,sun4i-a10-sid" or "allwinner,sun7i-a20-sid"
-- reg: Should contain registers location and length
-
-Example for sun4i:
- sid@01c23800 {
- compatible = "allwinner,sun4i-a10-sid";
- reg = <0x01c23800 0x10>
- };
-
-Example for sun7i:
- sid@01c23800 {
- compatible = "allwinner,sun7i-a20-sid";
- reg = <0x01c23800 0x200>
- };
diff --git a/drivers/eeprom/Kconfig b/drivers/eeprom/Kconfig
index 21e1847..ad396c1 100644
--- a/drivers/eeprom/Kconfig
+++ b/drivers/eeprom/Kconfig
@@ -9,3 +9,18 @@ menuconfig EEPROM
from both the Linux Kernel and the userspace.
If unsure, say no.
+
+if EEPROM
+
+config EEPROM_SUNXI_SID
+ tristate "Allwinner SoCs SID support"
+ depends on ARCH_SUNXI
+ select REGMAP_MMIO
+ help
+ This is a driver for the 'security ID' available on various Allwinner
+ devices.
+
+ This driver can also be built as a module. If so, the module
+ will be called eeprom-sunxi-sid.
+
+endif
diff --git a/drivers/eeprom/Makefile b/drivers/eeprom/Makefile
index 51a727f..184aa53 100644
--- a/drivers/eeprom/Makefile
+++ b/drivers/eeprom/Makefile
@@ -4,3 +4,7 @@
obj-$(CONFIG_EEPROM) += eeprom_core.o
eeprom_core-y := core.o
+
+# Devices
+obj-$(CONFIG_EEPROM_SUNXI_SID) += eeprom-sunxi-sid.o
+eeprom-sunxi-sid-y := sunxi-sid.o
diff --git a/drivers/eeprom/sunxi-sid.c b/drivers/eeprom/sunxi-sid.c
new file mode 100644
index 0000000..dd7238d
--- /dev/null
+++ b/drivers/eeprom/sunxi-sid.c
@@ -0,0 +1,136 @@
+/*
+ * Allwinner sunXi SoCs Security ID support.
+ *
+ * Copyright (c) 2013 Oliver Schinagl <oliver@schinagl.nl>
+ * Copyright (C) 2014 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/eeprom-provider.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+struct eeprom_sid {
+ void __iomem *membase;
+ struct eeprom_device *eeprom;
+};
+
+static struct eeprom_config econfig = {
+ .name = "sunix-sid",
+};
+
+/* We read the entire key, due to a 32 bit read alignment requirement. Since we
+ * want to return the requested byte, this results in somewhat slower code and
+ * uses 4 times more reads as needed but keeps code simpler. Since the SID is
+ * only very rarely probed, this is not really an issue.
+ */
+static int sunxi_sid_reg_read(void *context,
+ unsigned int offset, unsigned int *val)
+{
+ struct eeprom_sid *sid = context;
+ u32 sid_key;
+
+ sid_key = ioread32be(sid->membase + round_down(offset, 4));
+ sid_key >>= (offset % 4) * 8;
+
+ *val = sid_key;
+
+ return 0;
+}
+
+static bool sunxi_sid_writeable_reg(struct device *dev, unsigned int reg)
+{
+ return false;
+}
+
+static const struct of_device_id sunxi_sid_of_match[] = {
+ { .compatible = "allwinner,sun4i-a10-sid", .data = (void *)16},
+ { .compatible = "allwinner,sun7i-a20-sid", .data = (void *)512},
+ {/* sentinel */},
+};
+MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);
+
+static struct regmap_config sunxi_sid_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 8,
+ .reg_stride = 1,
+ .reg_read = sunxi_sid_reg_read,
+ .writeable_reg = sunxi_sid_writeable_reg,
+};
+
+static int sunxi_sid_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *device;
+ struct eeprom_sid *sid;
+ struct resource *res;
+ struct eeprom_device *eeprom;
+ struct device *dev = &pdev->dev;
+ struct regmap *regmap;
+
+ sid = devm_kzalloc(dev, sizeof(*sid), GFP_KERNEL);
+ if (!sid)
+ return -ENOMEM;
+
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ sid->membase = devm_ioremap_resource(dev, res);
+ if (IS_ERR(sid->membase))
+ return PTR_ERR(sid->membase);
+
+ device = of_match_device(sunxi_sid_of_match, dev);
+ if (!device)
+ return -ENODEV;
+
+ sunxi_sid_regmap_config.max_register = (unsigned int)device->data - 1;
+
+ regmap = devm_regmap_init(dev, NULL,
+ sid, &sunxi_sid_regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ econfig.dev = dev;
+ econfig.owner = THIS_MODULE;
+
+ eeprom = eeprom_register(&econfig);
+ if (IS_ERR(eeprom))
+ return PTR_ERR(eeprom);
+
+ platform_set_drvdata(pdev, eeprom);
+
+ return 0;
+}
+
+static int sunxi_sid_remove(struct platform_device *pdev)
+{
+ struct eeprom_device *eeprom = platform_get_drvdata(pdev);
+
+ return eeprom_unregister(eeprom);
+}
+
+static struct platform_driver sunxi_sid_driver = {
+ .probe = sunxi_sid_probe,
+ .remove = sunxi_sid_remove,
+ .driver = {
+ .name = "eeprom-sunxi-sid",
+ .of_match_table = sunxi_sid_of_match,
+ },
+};
+module_platform_driver(sunxi_sid_driver);
+
+MODULE_AUTHOR("Oliver Schinagl <oliver@schinagl.nl>");
+MODULE_DESCRIPTION("Allwinner sunxi security id driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
index 9536852f..04f2e1f 100644
--- a/drivers/misc/eeprom/Kconfig
+++ b/drivers/misc/eeprom/Kconfig
@@ -96,17 +96,4 @@ config EEPROM_DIGSY_MTC_CFG
If unsure, say N.
-config EEPROM_SUNXI_SID
- tristate "Allwinner sunxi security ID support"
- depends on ARCH_SUNXI && SYSFS
- help
- This is a driver for the 'security ID' available on various Allwinner
- devices.
-
- Due to the potential risks involved with changing e-fuses,
- this driver is read-only.
-
- This driver can also be built as a module. If so, the module
- will be called sunxi_sid.
-
endmenu
diff --git a/drivers/misc/eeprom/Makefile b/drivers/misc/eeprom/Makefile
index 9507aec..fc1e81d 100644
--- a/drivers/misc/eeprom/Makefile
+++ b/drivers/misc/eeprom/Makefile
@@ -4,5 +4,4 @@ obj-$(CONFIG_EEPROM_LEGACY) += eeprom.o
obj-$(CONFIG_EEPROM_MAX6875) += max6875.o
obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o
obj-$(CONFIG_EEPROM_93XX46) += eeprom_93xx46.o
-obj-$(CONFIG_EEPROM_SUNXI_SID) += sunxi_sid.o
obj-$(CONFIG_EEPROM_DIGSY_MTC_CFG) += digsy_mtc_eeprom.o
diff --git a/drivers/misc/eeprom/sunxi_sid.c b/drivers/misc/eeprom/sunxi_sid.c
deleted file mode 100644
index 8385177..0000000
--- a/drivers/misc/eeprom/sunxi_sid.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (c) 2013 Oliver Schinagl <oliver@schinagl.nl>
- * http://www.linux-sunxi.org
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * This driver exposes the Allwinner security ID, efuses exported in byte-
- * sized chunks.
- */
-
-#include <linux/compiler.h>
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/export.h>
-#include <linux/fs.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/kobject.h>
-#include <linux/module.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/random.h>
-#include <linux/slab.h>
-#include <linux/stat.h>
-#include <linux/sysfs.h>
-#include <linux/types.h>
-
-#define DRV_NAME "sunxi-sid"
-
-struct sunxi_sid_data {
- void __iomem *reg_base;
- unsigned int keysize;
-};
-
-/* We read the entire key, due to a 32 bit read alignment requirement. Since we
- * want to return the requested byte, this results in somewhat slower code and
- * uses 4 times more reads as needed but keeps code simpler. Since the SID is
- * only very rarely probed, this is not really an issue.
- */
-static u8 sunxi_sid_read_byte(const struct sunxi_sid_data *sid_data,
- const unsigned int offset)
-{
- u32 sid_key;
-
- if (offset >= sid_data->keysize)
- return 0;
-
- sid_key = ioread32be(sid_data->reg_base + round_down(offset, 4));
- sid_key >>= (offset % 4) * 8;
-
- return sid_key; /* Only return the last byte */
-}
-
-static ssize_t sid_read(struct file *fd, struct kobject *kobj,
- struct bin_attribute *attr, char *buf,
- loff_t pos, size_t size)
-{
- struct platform_device *pdev;
- struct sunxi_sid_data *sid_data;
- int i;
-
- pdev = to_platform_device(kobj_to_dev(kobj));
- sid_data = platform_get_drvdata(pdev);
-
- if (pos < 0 || pos >= sid_data->keysize)
- return 0;
- if (size > sid_data->keysize - pos)
- size = sid_data->keysize - pos;
-
- for (i = 0; i < size; i++)
- buf[i] = sunxi_sid_read_byte(sid_data, pos + i);
-
- return i;
-}
-
-static struct bin_attribute sid_bin_attr = {
- .attr = { .name = "eeprom", .mode = S_IRUGO, },
- .read = sid_read,
-};
-
-static int sunxi_sid_remove(struct platform_device *pdev)
-{
- device_remove_bin_file(&pdev->dev, &sid_bin_attr);
- dev_dbg(&pdev->dev, "driver unloaded\n");
-
- return 0;
-}
-
-static const struct of_device_id sunxi_sid_of_match[] = {
- { .compatible = "allwinner,sun4i-a10-sid", .data = (void *)16},
- { .compatible = "allwinner,sun7i-a20-sid", .data = (void *)512},
- {/* sentinel */},
-};
-MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);
-
-static int sunxi_sid_probe(struct platform_device *pdev)
-{
- struct sunxi_sid_data *sid_data;
- struct resource *res;
- const struct of_device_id *of_dev_id;
- u8 *entropy;
- unsigned int i;
-
- sid_data = devm_kzalloc(&pdev->dev, sizeof(struct sunxi_sid_data),
- GFP_KERNEL);
- if (!sid_data)
- return -ENOMEM;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- sid_data->reg_base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(sid_data->reg_base))
- return PTR_ERR(sid_data->reg_base);
-
- of_dev_id = of_match_device(sunxi_sid_of_match, &pdev->dev);
- if (!of_dev_id)
- return -ENODEV;
- sid_data->keysize = (int)of_dev_id->data;
-
- platform_set_drvdata(pdev, sid_data);
-
- sid_bin_attr.size = sid_data->keysize;
- if (device_create_bin_file(&pdev->dev, &sid_bin_attr))
- return -ENODEV;
-
- entropy = kzalloc(sizeof(u8) * sid_data->keysize, GFP_KERNEL);
- for (i = 0; i < sid_data->keysize; i++)
- entropy[i] = sunxi_sid_read_byte(sid_data, i);
- add_device_randomness(entropy, sid_data->keysize);
- kfree(entropy);
-
- dev_dbg(&pdev->dev, "loaded\n");
-
- return 0;
-}
-
-static struct platform_driver sunxi_sid_driver = {
- .probe = sunxi_sid_probe,
- .remove = sunxi_sid_remove,
- .driver = {
- .name = DRV_NAME,
- .of_match_table = sunxi_sid_of_match,
- },
-};
-module_platform_driver(sunxi_sid_driver);
-
-MODULE_AUTHOR("Oliver Schinagl <oliver@schinagl.nl>");
-MODULE_DESCRIPTION("Allwinner sunxi security id driver");
-MODULE_LICENSE("GPL");
--
1.9.1
^ permalink raw reply related
* [PATCH v3 7/9] eeprom: qfprom: Add Qualcomm QFPROM support.
From: Srinivas Kandagatla @ 2015-03-24 22:30 UTC (permalink / raw)
To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown,
Greg Kroah-Hartman, linux-api-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-msm-u79uwXL29TY76Z2rM5mHXA, arnd-r2nGTMty4D4,
sboyd-sgV2jX0FEOL9JmXXK+q4OQ, Srinivas Kandagatla
In-Reply-To: <1427236116-18531-1-git-send-email-srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
This patch adds QFPROM support driver which is used by other drivers
like thermal sensor and cpufreq.
On MSM parts there are some efuses (called qfprom) these fuses store things like
calibration data, speed bins.. etc. Drivers like cpufreq, thermal sensors would
read out this data for configuring the driver.
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
---
drivers/eeprom/Kconfig | 11 +++++++
drivers/eeprom/Makefile | 2 ++
drivers/eeprom/qfprom.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 100 insertions(+)
create mode 100644 drivers/eeprom/qfprom.c
diff --git a/drivers/eeprom/Kconfig b/drivers/eeprom/Kconfig
index ad396c1..8fc14d3 100644
--- a/drivers/eeprom/Kconfig
+++ b/drivers/eeprom/Kconfig
@@ -23,4 +23,15 @@ config EEPROM_SUNXI_SID
This driver can also be built as a module. If so, the module
will be called eeprom-sunxi-sid.
+config QCOM_QFPROM
+ tristate "QCOM QFPROM Support"
+ depends on ARCH_QCOM
+ select REGMAP_MMIO
+ help
+ Say y here to enable QFPROM support. The QFPROM provides access
+ functions for QFPROM data to rest of the drivers via eeprom interface.
+
+ This driver can also be built as a module. If so, the module
+ will be called eeprom-qfprom.
+
endif
diff --git a/drivers/eeprom/Makefile b/drivers/eeprom/Makefile
index 184aa53..4ac437e 100644
--- a/drivers/eeprom/Makefile
+++ b/drivers/eeprom/Makefile
@@ -8,3 +8,5 @@ eeprom_core-y := core.o
# Devices
obj-$(CONFIG_EEPROM_SUNXI_SID) += eeprom-sunxi-sid.o
eeprom-sunxi-sid-y := sunxi-sid.o
+obj-$(CONFIG_QCOM_QFPROM) += eeprom_qfprom.o
+eeprom_qfprom-y := qfprom.o
diff --git a/drivers/eeprom/qfprom.c b/drivers/eeprom/qfprom.c
new file mode 100644
index 0000000..8d5d4d8
--- /dev/null
+++ b/drivers/eeprom/qfprom.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <linux/platform_device.h>
+#include <linux/eeprom-provider.h>
+
+static struct regmap_config qfprom_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 8,
+ .reg_stride = 1,
+};
+
+static struct eeprom_config econfig = {
+ .name = "qfprom",
+};
+
+static int qfprom_remove(struct platform_device *pdev)
+{
+ struct eeprom_device *eeprom = platform_get_drvdata(pdev);
+
+ return eeprom_unregister(eeprom);
+}
+
+static int qfprom_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ void __iomem *base;
+ struct device *dev = &pdev->dev;
+ struct eeprom_device *eeprom;
+ struct regmap *regmap;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ qfprom_regmap_config.max_register = resource_size(res) - 1;
+
+ regmap = devm_regmap_init_mmio(dev, base,
+ &qfprom_regmap_config);
+ if (IS_ERR(regmap)) {
+ dev_err(dev, "regmap init failed\n");
+ return PTR_ERR(regmap);
+ }
+ econfig.owner = THIS_MODULE;
+ econfig.dev = dev;
+ eeprom = eeprom_register(&econfig);
+ if (IS_ERR(eeprom))
+ return PTR_ERR(eeprom);
+
+ platform_set_drvdata(pdev, eeprom);
+ return 0;
+}
+
+static const struct of_device_id qfprom_of_match[] = {
+ { .compatible = "qcom,qfprom"},
+ {/* sentinel */},
+};
+MODULE_DEVICE_TABLE(of, qfprom_of_match);
+
+static struct platform_driver qfprom_driver = {
+ .probe = qfprom_probe,
+ .remove = qfprom_remove,
+ .driver = {
+ .name = "qcom,qfprom",
+ .of_match_table = qfprom_of_match,
+ },
+};
+module_platform_driver(qfprom_driver);
+MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>");
+MODULE_DESCRIPTION("Qualcomm QFPROM driver");
+MODULE_LICENSE("GPL v2");
--
1.9.1
^ permalink raw reply related
* [PATCH v3 8/9] eeprom: qfprom: Add bindings for qfprom
From: Srinivas Kandagatla @ 2015-03-24 22:31 UTC (permalink / raw)
To: linux-arm-kernel
Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown,
Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
linux-arm-msm, arnd, sboyd, Srinivas Kandagatla
In-Reply-To: <1427236116-18531-1-git-send-email-srinivas.kandagatla@linaro.org>
This patch adds bindings for qfprom found in QCOM SOCs. QFPROM driver
is based on simple eeprom framework.
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
.../devicetree/bindings/eeprom/qfprom.txt | 23 ++++++++++++++++++++++
1 file changed, 23 insertions(+)
create mode 100644 Documentation/devicetree/bindings/eeprom/qfprom.txt
diff --git a/Documentation/devicetree/bindings/eeprom/qfprom.txt b/Documentation/devicetree/bindings/eeprom/qfprom.txt
new file mode 100644
index 0000000..d5baed6
--- /dev/null
+++ b/Documentation/devicetree/bindings/eeprom/qfprom.txt
@@ -0,0 +1,23 @@
+= Qualcomm QFPROM device tree bindings =
+
+This binding is intended to represent QFPROM which is found in most QCOM SOCs.
+
+Required properties:
+- compatible: should be "qcom,qfprom"
+- reg: Should contain registers location and length
+
+= Data cells =
+Are child nodes of qfprom, bindings of which as described in
+bindings/eeprom/eeprom.txt
+
+Example:
+
+ qfprom: qfprom@00700000 {
+ compatible = "qcom,qfprom";
+ reg = <0x00700000 0x1000>;
+ ...
+ /* Data cells */
+ tsens_calibration: calib@404 {
+ reg = <0x404 0x10>;
+ };
+ };
--
1.9.1
^ permalink raw reply related
* [PATCH v3 9/9] eeprom: Add to MAINTAINERS for eeprom framework
From: Srinivas Kandagatla @ 2015-03-24 22:31 UTC (permalink / raw)
To: linux-arm-kernel
Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown,
Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
linux-arm-msm, arnd, sboyd, Srinivas Kandagatla
In-Reply-To: <1427236116-18531-1-git-send-email-srinivas.kandagatla@linaro.org>
This patch adds MAINTAINERS to eeprom framework.
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
MAINTAINERS | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index d66a97d..ee7ba92 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3657,6 +3657,15 @@ T: git git://git.alsa-project.org/alsa-kernel.git
S: Maintained
F: sound/usb/misc/ua101.c
+EEPROM FRAMEWORK
+M: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+M: Maxime Ripard <maxime.ripard@free-electrons.com>
+S: Maintained
+F: drivers/eeprom/
+F: Documentation/devicetree/bindings/eeprom/
+F: include/linux/eeprom-provider.h
+F: include/linux/eeprom-consumer.h
+
EXTENSIBLE FIRMWARE INTERFACE (EFI)
M: Matt Fleming <matt.fleming@intel.com>
L: linux-efi@vger.kernel.org
--
1.9.1
^ permalink raw reply related
* Re: [PATCH v3 1/9] regmap: Introduce regmap_get_max_register.
From: Mark Brown @ 2015-03-24 22:36 UTC (permalink / raw)
To: Srinivas Kandagatla
Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Kumar Gala,
Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
linux-arm-msm, arnd, sboyd
In-Reply-To: <1427236179-18580-1-git-send-email-srinivas.kandagatla@linaro.org>
[-- Attachment #1: Type: text/plain, Size: 429 bytes --]
On Tue, Mar 24, 2015 at 10:29:39PM +0000, Srinivas Kandagatla wrote:
> This patch introduces regmap_get_max_register() function which would be
> used by the infrastructures like eeprom framework built on top of
> regmap.
In what way would it be used?
> +int regmap_get_max_register(struct regmap *map)
> +{
> + return map->max_register ? : -EINVAL;
> +}
Please write the logic out properly, don't abuse the ternery operator.
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]
^ permalink raw reply
* Re: [PATCH v3 2/9] regmap: Introduce regmap_get_reg_stride.
From: Mark Brown @ 2015-03-24 22:37 UTC (permalink / raw)
To: Srinivas Kandagatla
Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Kumar Gala,
Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
linux-arm-msm, arnd, sboyd
In-Reply-To: <1427236200-18625-1-git-send-email-srinivas.kandagatla@linaro.org>
[-- Attachment #1: Type: text/plain, Size: 472 bytes --]
On Tue, Mar 24, 2015 at 10:30:00PM +0000, Srinivas Kandagatla wrote:
> + /* regmap_get_reg_stride(): Report the register address stride
> + *
> + * Report the register address stride, mainly intended to for use by
> + * generic infrastructure built on top of regmap.
> + */
> +int regmap_get_reg_stride(struct regmap *map)
Please fix the indentation for the comment block and add kerneldoc for
the argument. This is an exported function so it should also be /** not
/*
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]
^ permalink raw reply
* [PATCH 2/3] powerpc: make copyuser_power7.S 64-byte cacheline friendly
From: Kim Phillips @ 2015-03-24 22:44 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
Scott Wood, Joel Stanley, Anton Blanchard, Paul Bolle,
Jiri Kosina, Ulrich Weigand, Alexander Graf, Stewart Smith,
Kyle Moffett
Cc: linux-api, linuxppc-dev, Shuah Khan, linux-kernel
The innermost copyloops were optimized for POWER7's 128-byte cacheline.
This patch adds optimization for the e6500, which has a 64-byte
cacheline.
We basically do this by stripping loop bodies using L1_CACHE_BYTES
ifdeferry, replace 128 with L1_CACHE_BYTES, and 7's with L1_CACHE_SHIFTs.
We also add an e6500 copyuser to copyloops tests, which requires we copy
asm/cache.h into copyloops, just to satisfy the #include: We define
the define symbols manually in the testing makefile.
Includes a minor spelling fix: desination->destination.
Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
Cc: Shuah Khan <shuahkh@osg.samsung.com> [SELFTESTS]
Cc: linux-api@vger.kernel.org [SELFTESTS]
---
arch/powerpc/lib/copyuser_power7.S | 74 +++++++++++++------
tools/testing/selftests/powerpc/copyloops/Makefile | 11 ++-
.../selftests/powerpc/copyloops/asm/cache.h | 84 ++++++++++++++++++++++
3 files changed, 144 insertions(+), 25 deletions(-)
create mode 100644 tools/testing/selftests/powerpc/copyloops/asm/cache.h
diff --git a/arch/powerpc/lib/copyuser_power7.S b/arch/powerpc/lib/copyuser_power7.S
index 92ee840..2d22e58 100644
--- a/arch/powerpc/lib/copyuser_power7.S
+++ b/arch/powerpc/lib/copyuser_power7.S
@@ -18,6 +18,7 @@
* Author: Anton Blanchard <anton@au.ibm.com>
*/
#include <asm/ppc_asm.h>
+#include <asm/cache.h>
#ifdef __BIG_ENDIAN__
#define LVS(VRT,RA,RB) lvsl VRT,RA,RB
@@ -137,7 +138,7 @@ err1; stw r0,0(r3)
addi r3,r3,4
3: sub r5,r5,r6
- cmpldi r5,128
+ cmpldi r5,L1_CACHE_BYTES
blt 5f
mflr r0
@@ -153,10 +154,10 @@ err1; stw r0,0(r3)
std r22,STK_REG(R22)(r1)
std r0,STACKFRAMESIZE+16(r1)
- srdi r6,r5,7
+ srdi r6,r5,L1_CACHE_SHIFT
mtctr r6
- /* Now do cacheline (128B) sized loads and stores. */
+ /* Now do cacheline sized loads and stores. */
.align 5
4:
err2; ld r0,0(r4)
@@ -167,6 +168,7 @@ err2; ld r9,32(r4)
err2; ld r10,40(r4)
err2; ld r11,48(r4)
err2; ld r12,56(r4)
+#if L1_CACHE_BYTES >= 128
err2; ld r14,64(r4)
err2; ld r15,72(r4)
err2; ld r16,80(r4)
@@ -175,7 +177,8 @@ err2; ld r18,96(r4)
err2; ld r19,104(r4)
err2; ld r20,112(r4)
err2; ld r21,120(r4)
- addi r4,r4,128
+#endif
+ addi r4,r4,L1_CACHE_BYTES
err2; std r0,0(r3)
err2; std r6,8(r3)
err2; std r7,16(r3)
@@ -184,6 +187,7 @@ err2; std r9,32(r3)
err2; std r10,40(r3)
err2; std r11,48(r3)
err2; std r12,56(r3)
+#if L1_CACHE_BYTES >= 128
err2; std r14,64(r3)
err2; std r15,72(r3)
err2; std r16,80(r3)
@@ -192,10 +196,11 @@ err2; std r18,96(r3)
err2; std r19,104(r3)
err2; std r20,112(r3)
err2; std r21,120(r3)
- addi r3,r3,128
+#endif
+ addi r3,r3,L1_CACHE_BYTES
bdnz 4b
- clrldi r5,r5,(64-7)
+ clrldi r5,r5,(64-L1_CACHE_SHIFT)
ld r14,STK_REG(R14)(r1)
ld r15,STK_REG(R15)(r1)
@@ -208,10 +213,11 @@ err2; std r21,120(r3)
ld r22,STK_REG(R22)(r1)
addi r1,r1,STACKFRAMESIZE
- /* Up to 127B to go */
+ /* Up to L1_CACHE_BYTES - 1 to go */
5: srdi r6,r5,4
mtocrf 0x01,r6
+#if L1_CACHE_BYTES >= 128
6: bf cr7*4+1,7f
err1; ld r0,0(r4)
err1; ld r6,8(r4)
@@ -231,6 +237,7 @@ err1; std r10,40(r3)
err1; std r11,48(r3)
err1; std r12,56(r3)
addi r3,r3,64
+#endif
/* Up to 63B to go */
7: bf cr7*4+2,8f
@@ -377,11 +384,11 @@ err3; std r0,0(r3)
4: sub r5,r5,r6
- /* Get the desination 128B aligned */
+ /* Get the destination L1_CACHE_BYTES aligned */
neg r6,r3
srdi r7,r6,4
mtocrf 0x01,r7
- clrldi r6,r6,(64-7)
+ clrldi r6,r6,(64-L1_CACHE_SHIFT)
li r9,16
li r10,32
@@ -401,7 +408,9 @@ err3; stvx vr1,r0,r3
err3; stvx vr0,r3,r9
addi r3,r3,32
-6: bf cr7*4+1,7f
+6:
+#if L1_CACHE_BYTES >= 128
+ bf cr7*4+1,7f
err3; lvx vr3,r0,r4
err3; lvx vr2,r4,r9
err3; lvx vr1,r4,r10
@@ -412,9 +421,10 @@ err3; stvx vr2,r3,r9
err3; stvx vr1,r3,r10
err3; stvx vr0,r3,r11
addi r3,r3,64
+#endif
7: sub r5,r5,r6
- srdi r6,r5,7
+ srdi r6,r5,L1_CACHE_SHIFT
std r14,STK_REG(R14)(r1)
std r15,STK_REG(R15)(r1)
@@ -437,31 +447,36 @@ err4; lvx vr7,r0,r4
err4; lvx vr6,r4,r9
err4; lvx vr5,r4,r10
err4; lvx vr4,r4,r11
+#if L1_CACHE_BYTES >= 128
err4; lvx vr3,r4,r12
err4; lvx vr2,r4,r14
err4; lvx vr1,r4,r15
err4; lvx vr0,r4,r16
- addi r4,r4,128
+#endif
+ addi r4,r4,L1_CACHE_BYTES
err4; stvx vr7,r0,r3
err4; stvx vr6,r3,r9
err4; stvx vr5,r3,r10
err4; stvx vr4,r3,r11
+#if L1_CACHE_BYTES >= 128
err4; stvx vr3,r3,r12
err4; stvx vr2,r3,r14
err4; stvx vr1,r3,r15
err4; stvx vr0,r3,r16
- addi r3,r3,128
+#endif
+ addi r3,r3,L1_CACHE_BYTES
bdnz 8b
ld r14,STK_REG(R14)(r1)
ld r15,STK_REG(R15)(r1)
ld r16,STK_REG(R16)(r1)
- /* Up to 127B to go */
- clrldi r5,r5,(64-7)
+ /* Up to L1_CACHE_BYTES - 1 to go */
+ clrldi r5,r5,(64-L1_CACHE_SHIFT)
srdi r6,r5,4
mtocrf 0x01,r6
+#if L1_CACHE_BYTES >= 128
bf cr7*4+1,9f
err3; lvx vr3,r0,r4
err3; lvx vr2,r4,r9
@@ -473,6 +488,7 @@ err3; stvx vr2,r3,r9
err3; stvx vr1,r3,r10
err3; stvx vr0,r3,r11
addi r3,r3,64
+#endif
9: bf cr7*4+2,10f
err3; lvx vr1,r0,r4
@@ -550,11 +566,11 @@ err3; stw r7,4(r3)
4: sub r5,r5,r6
- /* Get the desination 128B aligned */
+ /* Get the destination L1_CACHE_BYTES aligned */
neg r6,r3
srdi r7,r6,4
mtocrf 0x01,r7
- clrldi r6,r6,(64-7)
+ clrldi r6,r6,(64-L1_CACHE_SHIFT)
li r9,16
li r10,32
@@ -582,7 +598,9 @@ err3; stvx vr8,r0,r3
err3; stvx vr9,r3,r9
addi r3,r3,32
-6: bf cr7*4+1,7f
+6:
+#if L1_CACHE_BYTES >= 128
+ bf cr7*4+1,7f
err3; lvx vr3,r0,r4
VPERM(vr8,vr0,vr3,vr16)
err3; lvx vr2,r4,r9
@@ -597,9 +615,10 @@ err3; stvx vr9,r3,r9
err3; stvx vr10,r3,r10
err3; stvx vr11,r3,r11
addi r3,r3,64
+#endif
7: sub r5,r5,r6
- srdi r6,r5,7
+ srdi r6,r5,L1_CACHE_SHIFT
std r14,STK_REG(R14)(r1)
std r15,STK_REG(R15)(r1)
@@ -626,6 +645,10 @@ err4; lvx vr5,r4,r10
VPERM(vr10,vr6,vr5,vr16)
err4; lvx vr4,r4,r11
VPERM(vr11,vr5,vr4,vr16)
+#if L1_CACHE_BYTES == 64
+err4; lvx vr0,r4,r11
+ VPERM(vr11,vr5,vr0,vr16)
+#else
err4; lvx vr3,r4,r12
VPERM(vr12,vr4,vr3,vr16)
err4; lvx vr2,r4,r14
@@ -634,27 +657,31 @@ err4; lvx vr1,r4,r15
VPERM(vr14,vr2,vr1,vr16)
err4; lvx vr0,r4,r16
VPERM(vr15,vr1,vr0,vr16)
- addi r4,r4,128
+#endif
+ addi r4,r4,L1_CACHE_BYTES
err4; stvx vr8,r0,r3
err4; stvx vr9,r3,r9
err4; stvx vr10,r3,r10
err4; stvx vr11,r3,r11
+#if L1_CACHE_BYTES >= 128
err4; stvx vr12,r3,r12
err4; stvx vr13,r3,r14
err4; stvx vr14,r3,r15
err4; stvx vr15,r3,r16
- addi r3,r3,128
+#endif
+ addi r3,r3,L1_CACHE_BYTES
bdnz 8b
ld r14,STK_REG(R14)(r1)
ld r15,STK_REG(R15)(r1)
ld r16,STK_REG(R16)(r1)
- /* Up to 127B to go */
- clrldi r5,r5,(64-7)
+ /* Up to L1_CACHE_BYTES - 1 to go */
+ clrldi r5,r5,(64-L1_CACHE_SHIFT)
srdi r6,r5,4
mtocrf 0x01,r6
+#if L1_CACHE_BYTES >= 128
bf cr7*4+1,9f
err3; lvx vr3,r0,r4
VPERM(vr8,vr0,vr3,vr16)
@@ -670,6 +697,7 @@ err3; stvx vr9,r3,r9
err3; stvx vr10,r3,r10
err3; stvx vr11,r3,r11
addi r3,r3,64
+#endif
9: bf cr7*4+2,10f
err3; lvx vr1,r0,r4
diff --git a/tools/testing/selftests/powerpc/copyloops/Makefile b/tools/testing/selftests/powerpc/copyloops/Makefile
index 6f2d3be..eb912c5 100644
--- a/tools/testing/selftests/powerpc/copyloops/Makefile
+++ b/tools/testing/selftests/powerpc/copyloops/Makefile
@@ -6,18 +6,25 @@ CFLAGS += -D SELFTEST
# Use our CFLAGS for the implicit .S rule
ASFLAGS = $(CFLAGS)
-PROGS := copyuser_64 copyuser_power7 memcpy_64 memcpy_power7
+PROGS := copyuser_64 copyuser_power7 copyuser_e6500 memcpy_64 memcpy_power7
EXTRA_SOURCES := validate.c ../harness.c
all: $(PROGS)
copyuser_64: CPPFLAGS += -D COPY_LOOP=test___copy_tofrom_user_base
-copyuser_power7: CPPFLAGS += -D COPY_LOOP=test___copy_tofrom_user_power7
+copyuser_power7: CPPFLAGS += -D COPY_LOOP=test___copy_tofrom_user_power7 \
+ -D CONFIG_PPC_BOOK3S_64 -D L1_CACHE_SHIFT=7 \
+ -D L1_CACHE_BYTES=128
memcpy_64: CPPFLAGS += -D COPY_LOOP=test_memcpy
memcpy_power7: CPPFLAGS += -D COPY_LOOP=test_memcpy_power7
$(PROGS): $(EXTRA_SOURCES)
+copyuser_e6500: copyuser_power7.S
+ $(CC) $(CFLAGS) -D COPY_LOOP=test___copy_tofrom_user_power7 \
+ -D CONFIG_PPC_BOOK3E_64 -D L1_CACHE_SHIFT=6 \
+ -D L1_CACHE_BYTES=64 copyuser_power7.S $(EXTRA_SOURCES) -o $@
+
run_tests: all
@-for PROG in $(PROGS); do \
./$$PROG; \
diff --git a/tools/testing/selftests/powerpc/copyloops/asm/cache.h b/tools/testing/selftests/powerpc/copyloops/asm/cache.h
new file mode 100644
index 0000000..34a05a1
--- /dev/null
+++ b/tools/testing/selftests/powerpc/copyloops/asm/cache.h
@@ -0,0 +1,84 @@
+#ifndef _ASM_POWERPC_CACHE_H
+#define _ASM_POWERPC_CACHE_H
+
+#ifdef __KERNEL__
+
+#include <asm/reg.h>
+
+/* bytes per L1 cache line */
+#if defined(CONFIG_8xx) || defined(CONFIG_403GCX)
+#define L1_CACHE_SHIFT 4
+#define MAX_COPY_PREFETCH 1
+#elif defined(CONFIG_PPC_E500MC)
+#define L1_CACHE_SHIFT 6
+#define MAX_COPY_PREFETCH 4
+#elif defined(CONFIG_PPC32)
+#define MAX_COPY_PREFETCH 4
+#if defined(CONFIG_PPC_47x)
+#define L1_CACHE_SHIFT 7
+#else
+#define L1_CACHE_SHIFT 5
+#endif
+#else /* CONFIG_PPC64 */
+#define L1_CACHE_SHIFT 7
+#endif
+
+#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT)
+
+#define SMP_CACHE_BYTES L1_CACHE_BYTES
+
+#if defined(__powerpc64__) && !defined(__ASSEMBLY__)
+struct ppc64_caches {
+ u32 dsize; /* L1 d-cache size */
+ u32 dline_size; /* L1 d-cache line size */
+ u32 log_dline_size;
+ u32 dlines_per_page;
+ u32 isize; /* L1 i-cache size */
+ u32 iline_size; /* L1 i-cache line size */
+ u32 log_iline_size;
+ u32 ilines_per_page;
+};
+
+extern struct ppc64_caches ppc64_caches;
+
+static inline void logmpp(u64 x)
+{
+ asm volatile(PPC_LOGMPP(R1) : : "r" (x));
+}
+
+#endif /* __powerpc64__ && ! __ASSEMBLY__ */
+
+#if defined(__ASSEMBLY__)
+/*
+ * For a snooping icache, we still need a dummy icbi to purge all the
+ * prefetched instructions from the ifetch buffers. We also need a sync
+ * before the icbi to order the the actual stores to memory that might
+ * have modified instructions with the icbi.
+ */
+#define PURGE_PREFETCHED_INS \
+ sync; \
+ icbi 0,r3; \
+ sync; \
+ isync
+
+#else
+#define __read_mostly __attribute__((__section__(".data..read_mostly")))
+
+#ifdef CONFIG_6xx
+extern long _get_L2CR(void);
+extern long _get_L3CR(void);
+extern void _set_L2CR(unsigned long);
+extern void _set_L3CR(unsigned long);
+#else
+#define _get_L2CR() 0L
+#define _get_L3CR() 0L
+#define _set_L2CR(val) do { } while(0)
+#define _set_L3CR(val) do { } while(0)
+#endif
+
+extern void cacheable_memzero(void *p, unsigned int nb);
+extern void *cacheable_memcpy(void *, const void *, unsigned int);
+
+#endif /* !__ASSEMBLY__ */
+#endif /* __KERNEL__ */
+#endif /* _ASM_POWERPC_CACHE_H */
--
2.3.3
_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox