diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-10-02 12:17:24 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-10-02 12:17:24 -0700 |
| commit | 3f1fe48a36b0b6722dc3fd421d93512bac138e9a (patch) | |
| tree | b767d7f6e26bc64334d3f14f8422d187239dc45d /drivers/rtc/rtc-bq4802.c | |
| download | linux-stable-3f1fe48a36b0b6722dc3fd421d93512bac138e9a.tar.gz linux-stable-3f1fe48a36b0b6722dc3fd421d93512bac138e9a.zip | |
Merge tag 'io_uring-7.3-20261002' of git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linuxgrafted
Pull io_uring fixes from Jens Axboe:
- Fix a task_work add use-after-free with SQPOLL.
The sqpoll thread could pop and complete the last request while
io_req_normal_work_add() was still looking at them after the mpscq
push.
Use the same approach as DEFER_TASKRUN to protect from that, holding
an RCU read lock across the add, and have exit wait for an RCU grace
period for SQPOLL rings as well.
- CQE32 ring fixes: correct the free entry check for 32b CQEs, zero the
big_cqe for aux CQEs, and only post the dummy skip CQE on CQE_MIXED
rings
- Mark the source filter table as COW when cloning bpf filters, so
registering another filter on the source doesn't modify the shared
table in place
- Initialize the task context before running the BPF loop
- Requeue zcrx multishot receives stopped by a local resource
- End a TX_TIMESTAMP multishot cmd when the CQ is full (lollipopkit)
* tag 'io_uring-7.3-20261002' of git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux:
io_uring: fix task_work add use-after-free with SQPOLL
io_uring/cmd_net: end TX_TIMESTAMP multishot when the CQ is full
io_uring/zcrx: requeue multishot receives stopped by a local resource
io_uring: initialize task context before running the BPF loop
io_uring: zero big_cqe for aux CQEs on CQE32 rings
io_uring: fix free entry check for 32b CQEs on CQE32 rings
io_uring: only post the dummy skip CQE on CQE_MIXED rings
io_uring/bpf_filter: mark source as COW when cloning filters
Diffstat (limited to 'drivers/rtc/rtc-bq4802.c')
| -rw-r--r-- | drivers/rtc/rtc-bq4802.c | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/drivers/rtc/rtc-bq4802.c b/drivers/rtc/rtc-bq4802.c new file mode 100644 index 000000000..472e75668 --- /dev/null +++ b/drivers/rtc/rtc-bq4802.c @@ -0,0 +1,202 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* rtc-bq4802.c: TI BQ4802 RTC driver. + * + * Copyright (C) 2008 David S. Miller <davem@davemloft.net> + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/platform_device.h> +#include <linux/rtc.h> +#include <linux/bcd.h> +#include <linux/slab.h> + +MODULE_AUTHOR("David S. Miller <davem@davemloft.net>"); +MODULE_DESCRIPTION("TI BQ4802 RTC driver"); +MODULE_LICENSE("GPL"); + +struct bq4802 { + void __iomem *regs; + unsigned long ioport; + struct rtc_device *rtc; + spinlock_t lock; + struct resource *r; + u8 (*read)(struct bq4802 *, int); + void (*write)(struct bq4802 *, int, u8); +}; + +static u8 bq4802_read_io(struct bq4802 *p, int off) +{ + return inb(p->ioport + off); +} + +static void bq4802_write_io(struct bq4802 *p, int off, u8 val) +{ + outb(val, p->ioport + off); +} + +static u8 bq4802_read_mem(struct bq4802 *p, int off) +{ + return readb(p->regs + off); +} + +static void bq4802_write_mem(struct bq4802 *p, int off, u8 val) +{ + writeb(val, p->regs + off); +} + +static int bq4802_read_time(struct device *dev, struct rtc_time *tm) +{ + struct bq4802 *p = dev_get_drvdata(dev); + unsigned long flags; + unsigned int century; + u8 val; + + spin_lock_irqsave(&p->lock, flags); + + val = p->read(p, 0x0e); + p->write(p, 0xe, val | 0x08); + + tm->tm_sec = p->read(p, 0x00); + tm->tm_min = p->read(p, 0x02); + tm->tm_hour = p->read(p, 0x04); + tm->tm_mday = p->read(p, 0x06); + tm->tm_mon = p->read(p, 0x09); + tm->tm_year = p->read(p, 0x0a); + tm->tm_wday = p->read(p, 0x08); + century = p->read(p, 0x0f); + + p->write(p, 0x0e, val); + + spin_unlock_irqrestore(&p->lock, flags); + + tm->tm_sec = bcd2bin(tm->tm_sec); + tm->tm_min = bcd2bin(tm->tm_min); + tm->tm_hour = bcd2bin(tm->tm_hour); + tm->tm_mday = bcd2bin(tm->tm_mday); + tm->tm_mon = bcd2bin(tm->tm_mon); + tm->tm_year = bcd2bin(tm->tm_year); + tm->tm_wday = bcd2bin(tm->tm_wday); + century = bcd2bin(century); + + tm->tm_year += (century * 100); + tm->tm_year -= 1900; + + tm->tm_mon--; + + return 0; +} + +static int bq4802_set_time(struct device *dev, struct rtc_time *tm) +{ + struct bq4802 *p = dev_get_drvdata(dev); + u8 sec, min, hrs, day, mon, yrs, century, val; + unsigned long flags; + unsigned int year; + + year = tm->tm_year + 1900; + century = year / 100; + yrs = year % 100; + + mon = tm->tm_mon + 1; /* tm_mon starts at zero */ + day = tm->tm_mday; + hrs = tm->tm_hour; + min = tm->tm_min; + sec = tm->tm_sec; + + sec = bin2bcd(sec); + min = bin2bcd(min); + hrs = bin2bcd(hrs); + day = bin2bcd(day); + mon = bin2bcd(mon); + yrs = bin2bcd(yrs); + century = bin2bcd(century); + + spin_lock_irqsave(&p->lock, flags); + + val = p->read(p, 0x0e); + p->write(p, 0x0e, val | 0x08); + + p->write(p, 0x00, sec); + p->write(p, 0x02, min); + p->write(p, 0x04, hrs); + p->write(p, 0x06, day); + p->write(p, 0x09, mon); + p->write(p, 0x0a, yrs); + p->write(p, 0x0f, century); + + p->write(p, 0x0e, val); + + spin_unlock_irqrestore(&p->lock, flags); + + return 0; +} + +static const struct rtc_class_ops bq4802_ops = { + .read_time = bq4802_read_time, + .set_time = bq4802_set_time, +}; + +static int bq4802_probe(struct platform_device *pdev) +{ + struct bq4802 *p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL); + int err = -ENOMEM; + + if (!p) + goto out; + + spin_lock_init(&p->lock); + + p->r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!p->r) { + p->r = platform_get_resource(pdev, IORESOURCE_IO, 0); + err = -EINVAL; + if (!p->r) + goto out; + } + if (p->r->flags & IORESOURCE_IO) { + p->ioport = p->r->start; + p->read = bq4802_read_io; + p->write = bq4802_write_io; + } else if (p->r->flags & IORESOURCE_MEM) { + p->regs = devm_ioremap(&pdev->dev, p->r->start, + resource_size(p->r)); + if (!p->regs){ + err = -ENOMEM; + goto out; + } + p->read = bq4802_read_mem; + p->write = bq4802_write_mem; + } else { + err = -EINVAL; + goto out; + } + + platform_set_drvdata(pdev, p); + + p->rtc = devm_rtc_device_register(&pdev->dev, "bq4802", + &bq4802_ops, THIS_MODULE); + if (IS_ERR(p->rtc)) { + err = PTR_ERR(p->rtc); + goto out; + } + + err = 0; +out: + return err; + +} + +/* work with hotplug and coldplug */ +MODULE_ALIAS("platform:rtc-bq4802"); + +static struct platform_driver bq4802_driver = { + .driver = { + .name = "rtc-bq4802", + }, + .probe = bq4802_probe, +}; + +module_platform_driver(bq4802_driver); |
