* [PATCH zram] extend zero pages to same element pages
From: zhouxianrong @ 2017-01-04 6:20 UTC (permalink / raw)
Cc: linux-kernel, minchan, ngupta, zhouxianrong, zhouxiyu, weidu.du,
zhangshiming5, won.ho.park
From: z00281421 <z00281421@notesmail.huawei.com>
Signed-off-by: z00281421 <z00281421@notesmail.huawei.com>
---
drivers/block/zram/zram_drv.c | 67 ++++++++++++++++++++++++++---------------
drivers/block/zram/zram_drv.h | 11 ++++---
2 files changed, 49 insertions(+), 29 deletions(-)
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index 15f58ab..c3af69a 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -94,6 +94,17 @@ static void zram_clear_flag(struct zram_meta *meta, u32 index,
meta->table[index].value &= ~BIT(flag);
}
+static inline void zram_set_element(struct zram_meta *meta, u32 index,
+ unsigned long element)
+{
+ meta->table[index].element = element;
+}
+
+static inline void zram_clear_element(struct zram_meta *meta, u32 index)
+{
+ meta->table[index].element = 0;
+}
+
static size_t zram_get_obj_size(struct zram_meta *meta, u32 index)
{
return meta->table[index].value & (BIT(ZRAM_FLAG_SHIFT) - 1);
@@ -158,31 +169,31 @@ static inline void update_used_max(struct zram *zram,
} while (old_max != cur_max);
}
-static bool page_zero_filled(void *ptr)
+static bool page_same_filled(void *ptr)
{
unsigned int pos;
unsigned long *page;
page = (unsigned long *)ptr;
- for (pos = 0; pos != PAGE_SIZE / sizeof(*page); pos++) {
- if (page[pos])
+ for (pos = PAGE_SIZE / sizeof(unsigned long) - 1; pos > 0; pos--) {
+ if (page[pos] != page[pos - 1])
return false;
}
return true;
}
-static void handle_zero_page(struct bio_vec *bvec)
+static void handle_same_page(struct bio_vec *bvec, unsigned long element)
{
struct page *page = bvec->bv_page;
void *user_mem;
user_mem = kmap_atomic(page);
if (is_partial_io(bvec))
- memset(user_mem + bvec->bv_offset, 0, bvec->bv_len);
+ memset(user_mem + bvec->bv_offset, (char)element, bvec->bv_len);
else
- clear_page(user_mem);
+ memset(user_mem, (char)element, PAGE_SIZE);
kunmap_atomic(user_mem);
flush_dcache_page(page);
@@ -431,7 +442,7 @@ static ssize_t mm_stat_show(struct device *dev,
mem_used << PAGE_SHIFT,
zram->limit_pages << PAGE_SHIFT,
max_used << PAGE_SHIFT,
- (u64)atomic64_read(&zram->stats.zero_pages),
+ (u64)atomic64_read(&zram->stats.same_pages),
pool_stats.pages_compacted);
up_read(&zram->init_lock);
@@ -464,7 +475,7 @@ static ssize_t debug_stat_show(struct device *dev,
ZRAM_ATTR_RO(failed_writes);
ZRAM_ATTR_RO(invalid_io);
ZRAM_ATTR_RO(notify_free);
-ZRAM_ATTR_RO(zero_pages);
+ZRAM_ATTR_RO(same_pages);
ZRAM_ATTR_RO(compr_data_size);
static inline bool zram_meta_get(struct zram *zram)
@@ -538,18 +549,20 @@ static void zram_free_page(struct zram *zram, size_t index)
struct zram_meta *meta = zram->meta;
unsigned long handle = meta->table[index].handle;
- if (unlikely(!handle)) {
- /*
- * No memory is allocated for zero filled pages.
- * Simply clear zero page flag.
- */
- if (zram_test_flag(meta, index, ZRAM_ZERO)) {
- zram_clear_flag(meta, index, ZRAM_ZERO);
- atomic64_dec(&zram->stats.zero_pages);
- }
+ /*
+ * No memory is allocated for same element filled pages.
+ * Simply clear same page flag.
+ */
+ if (zram_test_flag(meta, index, ZRAM_SAME)) {
+ zram_clear_flag(meta, index, ZRAM_SAME);
+ zram_clear_element(meta, index);
+ atomic64_dec(&zram->stats.same_pages);
return;
}
+ if (!handle)
+ return;
+
zs_free(meta->mem_pool, handle);
atomic64_sub(zram_get_obj_size(meta, index),
@@ -572,9 +585,9 @@ static int zram_decompress_page(struct zram *zram, char *mem, u32 index)
handle = meta->table[index].handle;
size = zram_get_obj_size(meta, index);
- if (!handle || zram_test_flag(meta, index, ZRAM_ZERO)) {
+ if (!handle || zram_test_flag(meta, index, ZRAM_SAME)) {
bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);
- clear_page(mem);
+ memset(mem, (char)meta->table[index].element, PAGE_SIZE);
return 0;
}
@@ -610,9 +623,9 @@ static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec,
bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value);
if (unlikely(!meta->table[index].handle) ||
- zram_test_flag(meta, index, ZRAM_ZERO)) {
+ zram_test_flag(meta, index, ZRAM_SAME)) {
bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);
- handle_zero_page(bvec);
+ handle_same_page(bvec, meta->table[index].element);
return 0;
}
bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);
@@ -688,16 +701,20 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
uncmem = user_mem;
}
- if (page_zero_filled(uncmem)) {
+ if (page_same_filled(uncmem)) {
+ unsigned long element;
+
+ element = uncmem[0];
if (user_mem)
kunmap_atomic(user_mem);
/* Free memory associated with this sector now. */
bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value);
zram_free_page(zram, index);
- zram_set_flag(meta, index, ZRAM_ZERO);
+ zram_set_flag(meta, index, ZRAM_SAME);
+ zram_set_element(meta, index, element);
bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);
- atomic64_inc(&zram->stats.zero_pages);
+ atomic64_inc(&zram->stats.same_pages);
ret = 0;
goto out;
}
@@ -1203,7 +1220,7 @@ static int zram_open(struct block_device *bdev, fmode_t mode)
&dev_attr_compact.attr,
&dev_attr_invalid_io.attr,
&dev_attr_notify_free.attr,
- &dev_attr_zero_pages.attr,
+ &dev_attr_same_pages.attr,
&dev_attr_orig_data_size.attr,
&dev_attr_compr_data_size.attr,
&dev_attr_mem_used_total.attr,
diff --git a/drivers/block/zram/zram_drv.h b/drivers/block/zram/zram_drv.h
index 74fcf10..4bb92e1 100644
--- a/drivers/block/zram/zram_drv.h
+++ b/drivers/block/zram/zram_drv.h
@@ -60,8 +60,8 @@
/* Flags for zram pages (table[page_no].value) */
enum zram_pageflags {
- /* Page consists entirely of zeros */
- ZRAM_ZERO = ZRAM_FLAG_SHIFT,
+ /* Page consists entirely of same elements */
+ ZRAM_SAME = ZRAM_FLAG_SHIFT,
ZRAM_ACCESS, /* page is now accessed */
__NR_ZRAM_PAGEFLAGS,
@@ -71,7 +71,10 @@ enum zram_pageflags {
/* Allocated for each disk page */
struct zram_table_entry {
- unsigned long handle;
+ union {
+ unsigned long handle;
+ unsigned long element;
+ };
unsigned long value;
};
@@ -83,7 +86,7 @@ struct zram_stats {
atomic64_t failed_writes; /* can happen when memory is too low */
atomic64_t invalid_io; /* non-page-aligned I/O requests */
atomic64_t notify_free; /* no. of swap slot free notifications */
- atomic64_t zero_pages; /* no. of zero filled pages */
+ atomic64_t same_pages; /* no. of same element filled pages */
atomic64_t pages_stored; /* no. of pages currently stored */
atomic_long_t max_used_pages; /* no. of maximum pages stored */
atomic64_t writestall; /* no. of write slow paths */
--
1.7.9.5
^ permalink raw reply related
* Re: [PATCH v3 0/8] pstore: ramoops: support multiple pmsg instances
From: Kees Cook @ 2017-01-04 6:20 UTC (permalink / raw)
To: 岩松信洋 / IWAMATSU,NOBUHIRO
Cc: Anton Vorontsov, Colin Cross, Tony Luck, LKML,
cti.systems-productivity-manager.ts@hitachi.com
In-Reply-To: <F89ECF87BC754A49BB74E794F6A0EC2F01041248@GSjpTKYDCembx31.service.hitachi.net>
On Mon, Dec 26, 2016 at 4:48 PM, 岩松信洋 / IWAMATSU,NOBUHIRO
<nobuhiro.iwamatsu.kw@hitachi.com> wrote:
> Ping?_
>
>> -----Original Message-----
>> From: linux-kernel-owner@vger.kernel.org
>> [mailto:linux-kernel-owner@vger.kernel.org] On Behalf Of 岩松信洋 /
>> IWAMATSU,NOBUHIRO
>> Sent: Monday, December 05, 2016 10:47 AM
>> To: Kees Cook
>> Cc: Anton Vorontsov; Colin Cross; Tony Luck; LKML;
>> cti.systems-productivity-manager.ts@hitachi.com
>> Subject: RE: [PATCH v3 0/8] pstore: ramoops: support multiple pmsg instances
>>
>> Hi, Kees.
>>
>> > -----Original Message-----
>> > From: keescook@google.com [mailto:keescook@google.com] On Behalf Of
>> > Kees Cook
>> > Sent: Saturday, November 12, 2016 7:24 AM
>> > To: 岩松信洋 / IWAMATSU,NOBUHIRO
>> > Cc: Anton Vorontsov; Colin Cross; Tony Luck; LKML;
>> > cti.systems-productivity-manager.ts@hitachi.com
>> > Subject: Re: [PATCH v3 0/8] pstore: ramoops: support multiple pmsg
>> > instances
>> >
>> > On Tue, Oct 18, 2016 at 12:13 AM, Nobuhiro Iwamatsu
>> > <nobuhiro.iwamatsu.kw@hitachi.com> wrote:
>> > > The following series implements multiple pmsg. This feature allows
>> > > userspace program to control individual content aging or priority.
>> > >
>> > > If a pstore backend module(e.g. ramoops) requires the multiple pmsg
>> > > instances when registering itself to pstore, multiple /dev/pmsg[ID]
>> > > are created. Writes to each /dev/pmsg[ID] are isolated each other.
>> > > After reboot, the contents are available in
>> > /sys/fs/pstore/pmsg-[backend]-[ID].
>> > >
>> > > In addition, we add multiple pmsg support for ramoops. We can
>> > > specify multiple pmsg area size by its module parameter as follows.
>> > >
>> > > pmsg_size=0x1000,0x2000,...
>> > >
>> > > I did check the operation of this feature on CycloneV (socfpga)
>> > > Helio
>> > board.
>> > >
>> > > v3:
>> > > Rebase to v4.8.
>> > > Split patch.
>> > > merged device_create().
>> > > Remove Blank lines.
>> > > Update documentiation of DT binding.
>> > > Update parsing function of ramoops_pmsg_size, add NULL termination.
>> > > Update module parameters for pmsg_size list.
>> >
>> > Thanks for this v3! Sorry for the delay, I should be able to review
>> > this shortly.
>>
>> Thank you.
>> I will wait for your review.
Now that the big changes have landed in Linus's tree, are you able to
rebase your series on those?
-Kees
--
Kees Cook
Nexus Security
^ permalink raw reply
* Re: [PATCH V5 1/3] dt-bindings: document common IEEE 802.11 frequency limit property
From: Rafał Miłecki @ 2017-01-04 6:20 UTC (permalink / raw)
To: Johannes Berg, linux-wireless, Rob Herring
Cc: Martin Blumenstingl, Felix Fietkau, Arend van Spriel,
Arnd Bergmann, devicetree, Rafał Miłecki
In-Reply-To: <20170103225715.14072-1-zajec5@gmail.com>
Hi Rob,
On 01/03/2017 11:57 PM, Rafał Miłecki wrote:
> From: Rafał Miłecki <rafal@milecki.pl>
>
> This new file should be used for properties that apply to all wireless
> devices.
>
> Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
> ---
> V2: Switch to a single ieee80211-freq-limit property that allows specifying
> *multiple* ranges. This resolves problem with more complex rules as pointed
> by Felx.
> Make description implementation agnostic as pointed by Arend.
> Rename node to wifi as suggested by Martin.
> V3: Use more real-life frequencies in the example.
> V5: Describe hardware design as possible use for this property
> ---
> .../devicetree/bindings/net/wireless/ieee80211.txt | 20 ++++++++++++++++++++
> 1 file changed, 20 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/net/wireless/ieee80211.txt
>
> diff --git a/Documentation/devicetree/bindings/net/wireless/ieee80211.txt b/Documentation/devicetree/bindings/net/wireless/ieee80211.txt
> new file mode 100644
> index 0000000..1c82c16
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/net/wireless/ieee80211.txt
> @@ -0,0 +1,20 @@
> +Common IEEE 802.11 properties
> +
> +This provides documentation of common properties that are valid for all wireless
> +devices.
> +
> +Optional properties:
> + - ieee80211-freq-limit : list of supported frequency ranges in KHz. This can be
> + used to specify extra hardware limitations caused by e.g. used antennas
> + or power amplifiers.
Do you find this description sufficient now? I'm not sure how/if I could answer
"Where would this data normally come from?" question.
One vendor may hardcode choice of channels in their PHP web UI.
Another one may do it in Andoid app.
OpenWrt so far was describing this limitation on their wiki page.
It doesn't sound like any valuable info if I understand this correctly. We also
don't describe where to get information about amount o RAM. One may just check
the hardware, one may use vendor firmware, one could check product data sheet.
If I missed the point, could you help me get this?
> +Example:
> +
> +pcie@0,0 {
> + reg = <0x0000 0 0 0 0>;
> + wifi@0,0 {
> + reg = <0x0000 0 0 0 0>;
> + ieee80211-freq-limit = <2402000 2482000>,
> + <5170000 5250000>;
> + };
> +};
>
^ permalink raw reply
* Re: [PATCH V5 1/3] dt-bindings: document common IEEE 802.11 frequency limit property
From: Rafał Miłecki @ 2017-01-04 6:20 UTC (permalink / raw)
To: Johannes Berg, linux-wireless-u79uwXL29TY76Z2rM5mHXA, Rob Herring
Cc: Martin Blumenstingl, Felix Fietkau, Arend van Spriel,
Arnd Bergmann, devicetree-u79uwXL29TY76Z2rM5mHXA,
Rafał Miłecki
In-Reply-To: <20170103225715.14072-1-zajec5-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Hi Rob,
On 01/03/2017 11:57 PM, Rafał Miłecki wrote:
> From: Rafał Miłecki <rafal-g1n6cQUeyibVItvQsEIGlw@public.gmane.org>
>
> This new file should be used for properties that apply to all wireless
> devices.
>
> Signed-off-by: Rafał Miłecki <rafal-g1n6cQUeyibVItvQsEIGlw@public.gmane.org>
> ---
> V2: Switch to a single ieee80211-freq-limit property that allows specifying
> *multiple* ranges. This resolves problem with more complex rules as pointed
> by Felx.
> Make description implementation agnostic as pointed by Arend.
> Rename node to wifi as suggested by Martin.
> V3: Use more real-life frequencies in the example.
> V5: Describe hardware design as possible use for this property
> ---
> .../devicetree/bindings/net/wireless/ieee80211.txt | 20 ++++++++++++++++++++
> 1 file changed, 20 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/net/wireless/ieee80211.txt
>
> diff --git a/Documentation/devicetree/bindings/net/wireless/ieee80211.txt b/Documentation/devicetree/bindings/net/wireless/ieee80211.txt
> new file mode 100644
> index 0000000..1c82c16
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/net/wireless/ieee80211.txt
> @@ -0,0 +1,20 @@
> +Common IEEE 802.11 properties
> +
> +This provides documentation of common properties that are valid for all wireless
> +devices.
> +
> +Optional properties:
> + - ieee80211-freq-limit : list of supported frequency ranges in KHz. This can be
> + used to specify extra hardware limitations caused by e.g. used antennas
> + or power amplifiers.
Do you find this description sufficient now? I'm not sure how/if I could answer
"Where would this data normally come from?" question.
One vendor may hardcode choice of channels in their PHP web UI.
Another one may do it in Andoid app.
OpenWrt so far was describing this limitation on their wiki page.
It doesn't sound like any valuable info if I understand this correctly. We also
don't describe where to get information about amount o RAM. One may just check
the hardware, one may use vendor firmware, one could check product data sheet.
If I missed the point, could you help me get this?
> +Example:
> +
> +pcie@0,0 {
> + reg = <0x0000 0 0 0 0>;
> + wifi@0,0 {
> + reg = <0x0000 0 0 0 0>;
> + ieee80211-freq-limit = <2402000 2482000>,
> + <5170000 5250000>;
> + };
> +};
>
^ permalink raw reply
* Re: [Qemu-arm] [PATCH v4 8/8] arm: Add an RX8900 RTC to the ASpeed board
From: Andrew Jeffery @ 2017-01-04 6:19 UTC (permalink / raw)
To: Alastair D'Silva, qemu-arm
Cc: Peter Maydell, qemu-devel, Chris Smart, Joel Stanley,
Alastair D'Silva, Cédric Le Goater
In-Reply-To: <20161215054812.12602-9-alastair@au1.ibm.com>
[-- Attachment #1: Type: text/plain, Size: 3441 bytes --]
On Thu, 2016-12-15 at 16:48 +1100, Alastair D'Silva wrote:
> > From: Alastair D'Silva <alastair@d-silva.org>
>
> Connect an RX8900 RTC to i2c12 of the AST2500 SOC at address 0x32
>
> > Signed-off-by: Alastair D'Silva <alastair@d-silva.org>
> Signed-off-by: Chris Smart <chris@distroguy.com>
Reviewed-by: Andrew Jeffery <andrew@aj.id.au>
> ---
> hw/arm/aspeed.c | 29 +++++++++++++++++++++++++++++
> 1 file changed, 29 insertions(+)
>
> diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
> index 40c1383..ef63fd0 100644
> --- a/hw/arm/aspeed.c
> +++ b/hw/arm/aspeed.c
> @@ -26,6 +26,12 @@ static struct arm_boot_info aspeed_board_binfo = {
> .nb_cpus = 1,
> };
>
> +typedef struct AspeedI2CDevice {
> + const char *type;
> + uint8_t address;
> + int bus;
> +} AspeedI2CDevice;
> +
> typedef struct AspeedBoardState {
> AspeedSoCState soc;
> MemoryRegion ram;
> @@ -37,6 +43,7 @@ typedef struct AspeedBoardConfig {
> const char *fmc_model;
> const char *spi_model;
> uint32_t num_cs;
> + const AspeedI2CDevice *i2c_devices;
> } AspeedBoardConfig;
>
> enum {
> @@ -80,6 +87,11 @@ enum {
> SCU_AST2500_HW_STRAP_ACPI_ENABLE | \
> SCU_HW_STRAP_SPI_MODE(SCU_HW_STRAP_SPI_MASTER))
>
> +
> +static const AspeedI2CDevice ast2500_i2c_devices[] = {
> + {"rx8900", 0x32, 11}
> +};
> +
> static const AspeedBoardConfig aspeed_boards[] = {
> [PALMETTO_BMC] = {
> .soc_name = "ast2400-a1",
> @@ -94,6 +106,7 @@ static const AspeedBoardConfig aspeed_boards[] = {
> .fmc_model = "n25q256a",
> .spi_model = "mx25l25635e",
> .num_cs = 1,
> + .i2c_devices = ast2500_i2c_devices,
> },
> [ROMULUS_BMC] = {
> .soc_name = "ast2500-a1",
> @@ -104,6 +117,7 @@ static const AspeedBoardConfig aspeed_boards[] = {
> },
> };
>
> +
> static void aspeed_board_init_flashes(AspeedSMCState *s, const char *flashtype,
> Error **errp)
> {
> @@ -130,6 +144,19 @@ static void aspeed_board_init_flashes(AspeedSMCState *s, const char *flashtype,
> }
> }
>
> +static void aspeed_i2c_init(AspeedBoardState *bmc,
> + const AspeedBoardConfig *cfg)
> +{
> + AspeedSoCState *soc = &bmc->soc;
> + const AspeedI2CDevice *dev;
> +
> + for (dev = cfg->i2c_devices; dev != NULL && dev->type != NULL; dev++) {
> + I2CBus *i2c_bus = aspeed_i2c_get_bus((DeviceState *)&soc->i2c,
> + dev->bus);
> + (void)i2c_create_slave(i2c_bus, dev->type, dev->address);
> + }
> +}
> +
> static void aspeed_board_init(MachineState *machine,
> const AspeedBoardConfig *cfg)
> {
> @@ -174,6 +201,8 @@ static void aspeed_board_init(MachineState *machine,
> aspeed_board_binfo.ram_size = ram_size;
> aspeed_board_binfo.loader_start = sc->info->sdram_base;
>
> + aspeed_i2c_init(bmc, cfg);
> +
> arm_load_kernel(ARM_CPU(first_cpu), &aspeed_board_binfo);
> }
>
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply
* Re: [Qemu-devel] [PATCH v4 8/8] arm: Add an RX8900 RTC to the ASpeed board
From: Andrew Jeffery @ 2017-01-04 6:19 UTC (permalink / raw)
To: Alastair D'Silva, qemu-arm
Cc: qemu-devel, Peter Maydell, Cédric Le Goater, Joel Stanley,
Alastair D'Silva, Chris Smart
In-Reply-To: <20161215054812.12602-9-alastair@au1.ibm.com>
[-- Attachment #1: Type: text/plain, Size: 3441 bytes --]
On Thu, 2016-12-15 at 16:48 +1100, Alastair D'Silva wrote:
> > From: Alastair D'Silva <alastair@d-silva.org>
>
> Connect an RX8900 RTC to i2c12 of the AST2500 SOC at address 0x32
>
> > Signed-off-by: Alastair D'Silva <alastair@d-silva.org>
> Signed-off-by: Chris Smart <chris@distroguy.com>
Reviewed-by: Andrew Jeffery <andrew@aj.id.au>
> ---
> hw/arm/aspeed.c | 29 +++++++++++++++++++++++++++++
> 1 file changed, 29 insertions(+)
>
> diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
> index 40c1383..ef63fd0 100644
> --- a/hw/arm/aspeed.c
> +++ b/hw/arm/aspeed.c
> @@ -26,6 +26,12 @@ static struct arm_boot_info aspeed_board_binfo = {
> .nb_cpus = 1,
> };
>
> +typedef struct AspeedI2CDevice {
> + const char *type;
> + uint8_t address;
> + int bus;
> +} AspeedI2CDevice;
> +
> typedef struct AspeedBoardState {
> AspeedSoCState soc;
> MemoryRegion ram;
> @@ -37,6 +43,7 @@ typedef struct AspeedBoardConfig {
> const char *fmc_model;
> const char *spi_model;
> uint32_t num_cs;
> + const AspeedI2CDevice *i2c_devices;
> } AspeedBoardConfig;
>
> enum {
> @@ -80,6 +87,11 @@ enum {
> SCU_AST2500_HW_STRAP_ACPI_ENABLE | \
> SCU_HW_STRAP_SPI_MODE(SCU_HW_STRAP_SPI_MASTER))
>
> +
> +static const AspeedI2CDevice ast2500_i2c_devices[] = {
> + {"rx8900", 0x32, 11}
> +};
> +
> static const AspeedBoardConfig aspeed_boards[] = {
> [PALMETTO_BMC] = {
> .soc_name = "ast2400-a1",
> @@ -94,6 +106,7 @@ static const AspeedBoardConfig aspeed_boards[] = {
> .fmc_model = "n25q256a",
> .spi_model = "mx25l25635e",
> .num_cs = 1,
> + .i2c_devices = ast2500_i2c_devices,
> },
> [ROMULUS_BMC] = {
> .soc_name = "ast2500-a1",
> @@ -104,6 +117,7 @@ static const AspeedBoardConfig aspeed_boards[] = {
> },
> };
>
> +
> static void aspeed_board_init_flashes(AspeedSMCState *s, const char *flashtype,
> Error **errp)
> {
> @@ -130,6 +144,19 @@ static void aspeed_board_init_flashes(AspeedSMCState *s, const char *flashtype,
> }
> }
>
> +static void aspeed_i2c_init(AspeedBoardState *bmc,
> + const AspeedBoardConfig *cfg)
> +{
> + AspeedSoCState *soc = &bmc->soc;
> + const AspeedI2CDevice *dev;
> +
> + for (dev = cfg->i2c_devices; dev != NULL && dev->type != NULL; dev++) {
> + I2CBus *i2c_bus = aspeed_i2c_get_bus((DeviceState *)&soc->i2c,
> + dev->bus);
> + (void)i2c_create_slave(i2c_bus, dev->type, dev->address);
> + }
> +}
> +
> static void aspeed_board_init(MachineState *machine,
> const AspeedBoardConfig *cfg)
> {
> @@ -174,6 +201,8 @@ static void aspeed_board_init(MachineState *machine,
> aspeed_board_binfo.ram_size = ram_size;
> aspeed_board_binfo.loader_start = sc->info->sdram_base;
>
> + aspeed_i2c_init(bmc, cfg);
> +
> arm_load_kernel(ARM_CPU(first_cpu), &aspeed_board_binfo);
> }
>
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply
* [RESEND] cxl: Force psl data-cache flush during device shutdown
From: Vaibhav Jain @ 2017-01-04 6:18 UTC (permalink / raw)
To: linuxppc-dev
Cc: Vaibhav Jain, frederic.barrat, Andrew Donnellan, Ian Munsie,
Christophe Lombard, Philippe Bergheaud, Gregory Kurz
This change adds a force psl data cache flush during device shutdown
callback. This should reduce a possibility of psl holding a dirty
cache line while the CAPP is being reinitialized, which may result in
a UE [load/store] machine check error.
Signed-off-by: Vaibhav Jain <vaibhav@linux.vnet.ibm.com>
---
Resend: Fixed the author ident.
---
drivers/misc/cxl/pci.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c
index 80a87ab..73432e7 100644
--- a/drivers/misc/cxl/pci.c
+++ b/drivers/misc/cxl/pci.c
@@ -1610,6 +1610,9 @@ static void cxl_pci_remove_adapter(struct cxl *adapter)
cxl_sysfs_adapter_remove(adapter);
cxl_debugfs_adapter_remove(adapter);
+ /* Flush adapter datacache as its about to be removed */
+ cxl_data_cache_flush(adapter);
+
cxl_deconfigure_adapter(adapter);
device_unregister(&adapter->dev);
--
2.9.3
^ permalink raw reply related
* [PATCH] checkpatch: Warn on embedded function names
From: Joe Perches @ 2017-01-04 3:21 UTC (permalink / raw)
To: Andrew Morton, Andy Whitcroft; +Cc: linux-kernel
Embedded function names are less appropriate to use when
refactoring can cause function renaming. Prefer the use
of "%s", __func__ to embedded function names.
Signed-off-by: Joe Perches <joe@perches.com>
---
scripts/checkpatch.pl | 22 ++++++++++++++++++++--
1 file changed, 20 insertions(+), 2 deletions(-)
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 982c52ca6473..4f53093a1b0b 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -2134,7 +2134,7 @@ sub process {
my $in_header_lines = $file ? 0 : 1;
my $in_commit_log = 0; #Scanning lines before patch
my $has_commit_log = 0; #Encountered lines before patch
- my $commit_log_possible_stack_dump = 0;
+ my $commit_log_possible_stack_dump = 0;
my $commit_log_long_line = 0;
my $commit_log_has_diff = 0;
my $reported_maintainer_file = 0;
@@ -2154,6 +2154,7 @@ sub process {
my $realline = 0;
my $realcnt = 0;
my $here = '';
+ my $context_function; #undef'd unless there's a known function
my $in_comment = 0;
my $comment_edge = 0;
my $first_line = 0;
@@ -2192,7 +2193,8 @@ sub process {
}
#next;
}
- if ($rawline=~/^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) {
+ if ($rawline=~/^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@(.*)/) {
+ my $context = $4;
$realline=$1-1;
if (defined $2) {
$realcnt=$3+1;
@@ -2201,6 +2203,12 @@ sub process {
}
$in_comment = 0;
+ if ($context =~ /\b(\w+)\s*\(/) {
+ $context_function = $1;
+ } else {
+ undef $context_function;
+ }
+
# Guestimate if this is a continuing comment. Run
# the context looking for a comment "edge". If this
# edge is a close comment then we must be in a comment
@@ -5157,6 +5165,16 @@ sub process {
"break quoted strings at a space character\n" . $hereprev);
}
+#check for an embedded function name in a string when the function is known
+# as part of a diff. This does not work for -f --file checking as it
+#depends on patch context providing the function name
+ if ($line =~ /^\+.*$String/ &&
+ defined($context_function) &&
+ get_quoted_string($line, $rawline) =~ /\b$context_function\b/) {
+ WARN("EMBEDDED_FUNCTION_NAME",
+ "Prefer using \"%s\", __func__ to embedded function names\n" . $herecurr);
+ }
+
# check for spaces before a quoted newline
if ($rawline =~ /^.*\".*\s\\n/) {
if (WARN("QUOTED_WHITESPACE_BEFORE_NEWLINE",
--
2.10.0.rc2.1.g053435c
^ permalink raw reply related
* [PATCH] checkpatch: Warn on embedded function names
From: Joe Perches @ 2017-01-04 6:16 UTC (permalink / raw)
To: Andrew Morton, Andy Whitcroft; +Cc: linux-kernel
Embedded function names are less appropriate to use when
refactoring can cause function renaming. Prefer the use
of "%s", __func__ to embedded function names.
Signed-off-by: Joe Perches <joe@perches.com>
---
scripts/checkpatch.pl | 22 ++++++++++++++++++++--
1 file changed, 20 insertions(+), 2 deletions(-)
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 982c52ca6473..4f53093a1b0b 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -2134,7 +2134,7 @@ sub process {
my $in_header_lines = $file ? 0 : 1;
my $in_commit_log = 0; #Scanning lines before patch
my $has_commit_log = 0; #Encountered lines before patch
- my $commit_log_possible_stack_dump = 0;
+ my $commit_log_possible_stack_dump = 0;
my $commit_log_long_line = 0;
my $commit_log_has_diff = 0;
my $reported_maintainer_file = 0;
@@ -2154,6 +2154,7 @@ sub process {
my $realline = 0;
my $realcnt = 0;
my $here = '';
+ my $context_function; #undef'd unless there's a known function
my $in_comment = 0;
my $comment_edge = 0;
my $first_line = 0;
@@ -2192,7 +2193,8 @@ sub process {
}
#next;
}
- if ($rawline=~/^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) {
+ if ($rawline=~/^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@(.*)/) {
+ my $context = $4;
$realline=$1-1;
if (defined $2) {
$realcnt=$3+1;
@@ -2201,6 +2203,12 @@ sub process {
}
$in_comment = 0;
+ if ($context =~ /\b(\w+)\s*\(/) {
+ $context_function = $1;
+ } else {
+ undef $context_function;
+ }
+
# Guestimate if this is a continuing comment. Run
# the context looking for a comment "edge". If this
# edge is a close comment then we must be in a comment
@@ -5157,6 +5165,16 @@ sub process {
"break quoted strings at a space character\n" . $hereprev);
}
+#check for an embedded function name in a string when the function is known
+# as part of a diff. This does not work for -f --file checking as it
+#depends on patch context providing the function name
+ if ($line =~ /^\+.*$String/ &&
+ defined($context_function) &&
+ get_quoted_string($line, $rawline) =~ /\b$context_function\b/) {
+ WARN("EMBEDDED_FUNCTION_NAME",
+ "Prefer using \"%s\", __func__ to embedded function names\n" . $herecurr);
+ }
+
# check for spaces before a quoted newline
if ($rawline =~ /^.*\".*\s\\n/) {
if (WARN("QUOTED_WHITESPACE_BEFORE_NEWLINE",
--
2.10.0.rc2.1.g053435c
^ permalink raw reply related
* Re: [PATCH RFC V2] purgatory: fix up declarations
From: Dave Young @ 2017-01-04 6:16 UTC (permalink / raw)
To: Nicholas Mc Guire
Cc: Vivek Goyal, Nicholas Mc Guire, Thomas Gleixner, Ingo Molnar,
H. Peter Anvin, x86, linux-kernel, Baoquan He
In-Reply-To: <20170103163422.GB24542@osadl.at>
Vivek, thanks for ccing me..
On 01/03/17 at 04:34pm, Nicholas Mc Guire wrote:
> On Tue, Jan 03, 2017 at 10:38:14AM -0500, Vivek Goyal wrote:
> > On Fri, Dec 23, 2016 at 12:43:07PM +0100, Nicholas Mc Guire wrote:
> > > Add the missing declarations of basic purgatory functions and variables
> > > used with kexec_purgatory_get_set_symbol() to allow a clean build.
> > >
> > > Fixes: commit 8fc5b4d4121c ("purgatory: core purgatory functionality")
> > > Signed-off-by: Nicholas Mc Guire <hofrat@osadl.org>
> > > ---
> > >
> > > V2: after kbuild test robot <lkp@intel.com> reported a build failure
> > > removed incorrect declaration of copy_backup_region which is static
> > > anyway.
> > >
> > > sparse complained about:
> > > CHECK arch/x86/purgatory/purgatory.c
> > > arch/x86/purgatory/purgatory.c:21:15: warning: symbol 'backup_dest' was not declared. Should it be static?
> > > arch/x86/purgatory/purgatory.c:22:15: warning: symbol 'backup_src' was not declared. Should it be static?
> > > arch/x86/purgatory/purgatory.c:23:15: warning: symbol 'backup_sz' was not declared. Should it be static?
> > > arch/x86/purgatory/purgatory.c:25:4: warning: symbol 'sha256_digest' was not declared. Should it be static?
> > > arch/x86/purgatory/purgatory.c:27:19: warning: symbol 'sha_regions' was not declared. Should it be static?
> > > arch/x86/purgatory/purgatory.c:42:5: warning: symbol 'verify_sha256_digest' was not declared. Should it be static?
> > > arch/x86/purgatory/purgatory.c:61:6: warning: symbol 'purgatory' was not declared. Should it be static?
> > > CC arch/x86/purgatory/purgatory.o
> > >
> > > Numerous sparse messages regarding functions not being declared, these
> > > functions are resolved via kexec_purgatory_get_set_symbol() and not
> > > directly called anywhere.
> >
> > Hi Nicholas,
> >
> > So purgatory() is a separate piece of small binary which does not link
> > against kernel. And we don't want these symbols static as kernel
> > obtains the values of these symbols and modifies binary in place on
> > the fly. I am assuming if we make them static, then we will lose this
> > capability to be able to read elf headers and be able to modify value
> > of these symbols.
>
> I don´t understand why this would be lost - the symbols are not being
> used by kernel code other than kexec code it self - in what way
> would declaring them extern change there handling ?
> kexec_purgatory_find_symbol is using the elf header to resolve the
> symbol location and declaring it extern should not change that in any
> way - am I overlooking something ?
>
> >
> > Now question is how to supress warnings from sparse. If just declaring
> > them extern in header file and including that header file in some other
> > .c file make the sparse warning go away, so be it. Atleast we need
> > to make explicit comment that this is being done just to take care
> > of sparse warning.
> >
> > I am not very happy with the solution though. In future it will make
> > people scratch their head that why are we including this header file
> > and why some symbols are being declared extern. So if there is another
> > way to tell sparse to not worry about it, would be even better.
> >
>
> The assumtion was that these changes would be side-effect free - if they are
> not then this is probably the wrong path to go - the intent is to remove
> the sparse warnings only.
Another way is do not include the header file, but declare them in the c
file just for avoiding the sparse warnings with some comments to explain
it.
>
> >
> > > To resolve the sparse issues appropriate
> > > declarations were added to asm/kexec-bzimage64.h and the appropriate
> > > reference included in purgatory.c. Adding this to kexec-bzimage64.h
> > > was done as setup_purgatory() from machine_kexec_file_64.c uses
> > > these symbols - not sure if this is the proper place to add this.
> > >
> > > While at it the initialization of sha_regions to {{0,0}} was added.
> > >
> >
> > Is it really required. I thought all these global variable are will be
> > set to 0 without doing anything explicit.
> >
>
> No - technically it is not needed - but rather just a consistency
> issue as
> u8 sha256_digest[SHA256_DIGEST_SIZE] = { 0 };
> is being initialized explicidly I just found it consostent to initialize
> struct sha_region sha_regions[16] = {};
> explicidly as well - but that can be dropped if its usual practice.
It can be in another patch, removing the explicit zero initializing
looks better..
>
> thx!
> hofrat
>
> > Vivek
> >
> > > Patch was compile tested with: x86_64_defconfig (implies CONFIG_KEXEC=y)
> > >
> > > Patch is against 4.9.0 (localversion-next is next-20161223)
> > >
> > > arch/x86/include/asm/kexec-bzimage64.h | 16 ++++++++++++++++
> > > arch/x86/purgatory/purgatory.c | 8 ++------
> > > 2 files changed, 18 insertions(+), 6 deletions(-)
> > >
> > > diff --git a/arch/x86/include/asm/kexec-bzimage64.h b/arch/x86/include/asm/kexec-bzimage64.h
> > > index d1b5d19..fd7f776 100644
> > > --- a/arch/x86/include/asm/kexec-bzimage64.h
> > > +++ b/arch/x86/include/asm/kexec-bzimage64.h
> > > @@ -1,6 +1,21 @@
> > > #ifndef _ASM_KEXEC_BZIMAGE64_H
> > > #define _ASM_KEXEC_BZIMAGE64_H
> > >
> > > +struct sha_region {
> > > + unsigned long start;
> > > + unsigned long len;
> > > +};
> > > +
> > > extern struct kexec_file_ops kexec_bzImage64_ops;
> > >
> > > +/* needed for kexec_purgatory_get_set_symbol() */
> > > +extern unsigned long backup_dest;
> > > +extern unsigned long backup_src;
> > > +extern unsigned long backup_sz;
> > > +extern u8 sha256_digest[];
> > > +extern struct sha_region sha_regions[];
> > > +
> > > +void purgatory(void);
> > > +int verify_sha256_digest(void);
> > > +
> > > #endif /* _ASM_KEXE_BZIMAGE64_H */
> > > diff --git a/arch/x86/purgatory/purgatory.c b/arch/x86/purgatory/purgatory.c
> > > index 25e068b..26c8367 100644
> > > --- a/arch/x86/purgatory/purgatory.c
> > > +++ b/arch/x86/purgatory/purgatory.c
> > > @@ -12,11 +12,7 @@
> > >
> > > #include "sha256.h"
> > > #include "../boot/string.h"
> > > -
> > > -struct sha_region {
> > > - unsigned long start;
> > > - unsigned long len;
> > > -};
> > > +#include <asm/kexec-bzimage64.h>
> > >
> > > unsigned long backup_dest = 0;
> > > unsigned long backup_src = 0;
> > > @@ -24,7 +20,7 @@ unsigned long backup_sz = 0;
> > >
> > > u8 sha256_digest[SHA256_DIGEST_SIZE] = { 0 };
> > >
> > > -struct sha_region sha_regions[16] = {};
> > > +struct sha_region sha_regions[16] = { { 0, 0 } };
> > >
> > > /*
> > > * On x86, second kernel requries first 640K of memory to boot. Copy
> > > --
> > > 2.1.4
Thanks
Dave
^ permalink raw reply
* Re: [Qemu-arm] [PATCH v4 7/8] tests: Test all implemented RX8900 functionality
From: Andrew Jeffery @ 2017-01-04 6:14 UTC (permalink / raw)
To: Alastair D'Silva, qemu-arm
Cc: Peter Maydell, Alastair D'Silva, Joel Stanley, qemu-devel,
Cédric Le Goater
In-Reply-To: <20161215054812.12602-8-alastair@au1.ibm.com>
[-- Attachment #1: Type: text/plain, Size: 31763 bytes --]
Hi Alastair,
Again, small comments below.
On Thu, 2016-12-15 at 16:48 +1100, Alastair D'Silva wrote:
> > From: Alastair D'Silva <alastair@d-silva.org>
>
> > Signed-off-by: Alastair D'Silva <alastair@d-silva.org>
> ---
> tests/Makefile.include | 2 +
> tests/rx8900-test.c | 882 +++++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 884 insertions(+)
> create mode 100644 tests/rx8900-test.c
>
> diff --git a/tests/Makefile.include b/tests/Makefile.include
> index e98d3b6..e52e355 100644
> --- a/tests/Makefile.include
> +++ b/tests/Makefile.include
> @@ -300,6 +300,7 @@ check-qtest-sparc64-y = tests/endianness-test$(EXESUF)
>
> check-qtest-arm-y = tests/tmp105-test$(EXESUF)
> check-qtest-arm-y += tests/ds1338-test$(EXESUF)
> +check-qtest-arm-y += tests/rx8900-test$(EXESUF)
> check-qtest-arm-y += tests/m25p80-test$(EXESUF)
> gcov-files-arm-y += hw/misc/tmp105.c
> check-qtest-arm-y += tests/virtio-blk-test$(EXESUF)
> @@ -637,6 +638,7 @@ tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o \
> tests/pxe-test$(EXESUF): tests/pxe-test.o tests/boot-sector.o $(libqos-obj-y)
> tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y)
> tests/ds1338-test$(EXESUF): tests/ds1338-test.o $(libqos-imx-obj-y)
> +tests/rx8900-test$(EXESUF): tests/rx8900-test.o $(libqos-imx-obj-y)
> tests/m25p80-test$(EXESUF): tests/m25p80-test.o
> tests/i440fx-test$(EXESUF): tests/i440fx-test.o $(libqos-pc-obj-y)
> tests/q35-test$(EXESUF): tests/q35-test.o $(libqos-pc-obj-y)
> diff --git a/tests/rx8900-test.c b/tests/rx8900-test.c
> new file mode 100644
> index 0000000..1769659
> --- /dev/null
> +++ b/tests/rx8900-test.c
> @@ -0,0 +1,882 @@
> +/*
> + * QTest testcase for the Epson RX8900SA/CE RTC
> + *
> + * Copyright (c) 2016 IBM Corporation
> + * Authors:
> > + * Alastair D'Silva <alastair@d-silva.org>
> + *
> + * This code is licensed under the GPL version 2 or later. See
> + * the COPYING file in the top-level directory.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "hw/timer/rx8900_regs.h"
> +#include "libqtest.h"
> +#include "libqos/i2c.h"
> +#include "qemu/timer.h"
> +
> +#define IMX25_I2C_0_BASE 0x43F80000
> +#define RX8900_TEST_ID "rx8900-test"
> +#define RX8900_ADDR 0x32
> +#define RX8900_INTERRUPT_OUT "rx8900-interrupt-out"
> +#define RX8900_FOUT_ENABLE "rx8900-fout-enable"
> +#define RX8900_FOUT "rx8900-fout"
> +
> +static I2CAdapter *i2c;
> +static uint8_t addr;
> +
> +static inline uint8_t bcd2bin(uint8_t x)
> +{
> + return (x & 0x0f) + (x >> 4) * 10;
> +}
> +
> +static inline uint8_t bin2bcd(uint8_t x)
> +{
> + return (x / 10 << 4) | (x % 10);
> +}
> +
> +static void qmp_rx8900_set_temperature(const char *id, double value)
> +{
> + QDict *response;
> +
> + response = qmp("{ 'execute': 'qom-set', 'arguments': { 'path': %s, "
> + "'property': 'temperature', 'value': %f } }", id, value);
> + g_assert(qdict_haskey(response, "return"));
> + QDECREF(response);
> +}
> +
> +static void qmp_rx8900_set_voltage(const char *id, double value)
> +{
> + QDict *response;
> +
> + response = qmp("{ 'execute': 'qom-set', 'arguments': { 'path': %s, "
> + "'property': 'voltage', 'value': %f } }", id, value);
> + g_assert(qdict_haskey(response, "return"));
> + QDECREF(response);
> +}
> +
> +/**
> + * Read an RX8900 register
> + * @param reg the address of the register
> + * @return the value of the register
> + */
> +static uint8_t read_register(RX8900Addresses reg)
> +{
> + uint8_t val;
> + uint8_t reg_address = (uint8_t)reg;
> +
> + i2c_send(i2c, addr, ®_address, 1);
> + i2c_recv(i2c, addr, &val, 1);
> +
> + return val;
> +}
> +
> +/**
> + * Write to an RX8900 register
> + * @param reg the address of the register
> + * @param val the value to write
> + */
> +static uint8_t write_register(RX8900Addresses reg, uint8_t val)
> +{
> + uint8_t buf[2];
> +
> + buf[0] = reg;
> + buf[1] = val;
> +
> + i2c_send(i2c, addr, buf, 2);
> +
> + return val;
> +}
> +
> +/**
> + * Set bits in a register
> + * @param reg the address of the register
> + * @param mask a mask of the bits to set
> + */
> +static void set_bits_in_register(RX8900Addresses reg, uint8_t mask)
> +{
> + uint8_t value = read_register(reg);
> + value |= mask;
> + write_register(reg, value);
> +}
> +
> +/**
> + * Clear bits in a register
> + * @param reg the address of the register
> + * @param mask a mask of the bits to set
> + */
> +static void clear_bits_in_register(RX8900Addresses reg, uint8_t mask)
> +{
> + uint8_t value = read_register(reg);
> + value &= ~mask;
> + write_register(reg, value);
> +}
> +
> +/**
> + * Read a number of sequential RX8900 registers
> + * @param reg the address of the first register
> + * @param buf (out) an output buffer to stash the register values
> + * @param count the number of registers to read
> + */
> +static void read_registers(RX8900Addresses reg, uint8_t *buf, uint8_t count)
> +{
> + uint8_t reg_address = (uint8_t)reg;
> +
> + i2c_send(i2c, addr, ®_address, 1);
> + i2c_recv(i2c, addr, buf, count);
> +}
> +
> +/**
> + * Write to a sequential number of RX8900 registers
> + * @param reg the address of the first register
> + * @param buffer a buffer of values to write
> + * @param count the sumber of registers to write
> + */
> +static void write_registers(RX8900Addresses reg, uint8_t *buffer, uint8_t count)
> +{
> + uint8_t buf[RX8900_NVRAM_SIZE + 1];
> +
> + buf[0] = (uint8_t)reg;
> + memcpy(buf + 1, buffer, count);
> +
> + i2c_send(i2c, addr, buf, count + 1);
> +}
> +
> +/**
> + * Set the time on the RX8900
> + * @param secs the seconds to set
> + * @param mins the minutes to set
> + * @param hours the hours to set
> + * @param weekday the day of the week to set (0 = Sunday)
> + * @param day the day of the month to set
> + * @param month the month to set
> + * @param year the year to set
> + */
> +static void set_time(uint8_t secs, uint8_t mins, uint8_t hours,
> + uint8_t weekday, uint8_t day, uint8_t month, uint8_t year)
> +{
> + uint8_t buf[7];
> +
> + buf[0] = bin2bcd(secs);
> + buf[1] = bin2bcd(mins);
> + buf[2] = bin2bcd(hours);
> + buf[3] = BIT(weekday);
> + buf[4] = bin2bcd(day);
> + buf[5] = bin2bcd(month);
> + buf[6] = bin2bcd(year);
> +
> + write_registers(SECONDS, buf, 7);
> +}
> +
> +
> +/**
> + * Check basic communication
> + */
> +static void send_and_receive(void)
> +{
> + uint8_t buf[7];
> + time_t now = time(NULL);
> + struct tm *tm_ptr;
> +
> + /* retrieve the date */
> + read_registers(SECONDS, buf, 7);
> +
> + tm_ptr = gmtime(&now);
> +
> + /* check retrieved time against local time */
> + g_assert_cmpuint(bcd2bin(buf[0]), == , tm_ptr->tm_sec);
> + g_assert_cmpuint(bcd2bin(buf[1]), == , tm_ptr->tm_min);
> + g_assert_cmpuint(bcd2bin(buf[2]), == , tm_ptr->tm_hour);
> + g_assert_cmpuint(bcd2bin(buf[4]), == , tm_ptr->tm_mday);
> + g_assert_cmpuint(bcd2bin(buf[5]), == , 1 + tm_ptr->tm_mon);
> + g_assert_cmpuint(2000 + bcd2bin(buf[6]), == , 1900 + tm_ptr->tm_year);
> +}
> +
> +/**
> + * Check that the temperature can be altered via properties
> + */
> +static void check_temperature(void)
> +{
> + /* Check the initial temperature is 25C */
> + uint8_t temperature;
> +
> + temperature = read_register(TEMPERATURE);
> + g_assert_cmpuint(temperature, == , 133);
> +
> + /* Set the temperature to 40C and check the temperature again */
> + qmp_rx8900_set_temperature(RX8900_TEST_ID, 40.0f);
> + temperature = read_register(TEMPERATURE);
> + g_assert_cmpuint(temperature, == , 157);
> +}
> +
> +/**
> + * Check that the time rolls over correctly
> + */
> +static void check_rollover(void)
> +{
> + uint8_t buf[7];
> +
> +
> + set_time(59, 59, 23, 1, 29, 2, 16);
> +
> + /* Wait for the clock to rollover */
> + sleep(2);
>
Can we control time some other way so we're not delaying the test
suite? I assume not?
> +
> + memset(buf, 0, sizeof(buf));
> +
> + /* Check that the clock rolled over */
> + /* Read from registers starting at 0x00 */
> + buf[0] = 0x00;
> +
> + read_registers(SECONDS, buf, 7);
> +
> + /* Ignore seconds as there may be some noise,
> + * we expect 00:00:xx Tuesday 1/3/2016
> + */
this is why it would be nice if we could control time.
> + g_assert_cmpuint(bcd2bin(buf[1]), == , 0);
> + g_assert_cmpuint(bcd2bin(buf[2]), == , 0);
> + g_assert_cmpuint(bcd2bin(buf[3]), == , 0x04);
> + g_assert_cmpuint(bcd2bin(buf[4]), == , 1);
> + g_assert_cmpuint(bcd2bin(buf[5]), == , 3);
> + g_assert_cmpuint(bcd2bin(buf[6]), == , 16);
> +}
> +
> +uint32_t interrupt_counts[RX8900_INTERRUPT_SOURCES];
> +
> +/**
> + * Reset the interrupt counts
> + */
> +static void count_reset(void)
> +{
> + for (int source = 0; source < RX8900_INTERRUPT_SOURCES; source++) {
> + interrupt_counts[source] = 0;
> + }
> +}
> +
> +/**
> + * Handle an RX8900 interrupt (update the counts for that interrupt type)
> + */
> +static void handle_interrupt(void *opaque, const char *name, int irq,
> + bool level)
> +{
> + if (!level) {
> + return;
> + }
> +
> + uint8_t flags = read_register(FLAG_REGISTER);
> +
> + for (int flag = 0; flag < 8; flag++) {
> + if (flags & BIT(flag)) {
> + interrupt_counts[flag]++;
> + }
> + }
> +
> + write_register(FLAG_REGISTER, 0x00);
> +}
> +
> +uint32_t fout_counts;
> +
> +/**
> + * Handle an Fout state change
> + */
> +static void handle_fout(void *opaque, const char *name, int irq, bool level)
> +{
> + if (!level) {
> + return;
> + }
> +
> + fout_counts++;
> +}
> +
> +/**
> + * Reset the fout count
> + */
> +static void fout_count_reset(void)
> +{
> + fout_counts = 0;
> +}
> +
> +
> +/**
> + * Sleep for some real time while counting interrupts
> + * @param delay the delay in microseconds
> + * @param loop the loop time in microseconds
> + */
> +static void wait_for(uint64_t delay, uint64_t loop)
> +{
> + struct timeval end, now;
> +
> + gettimeofday(&end, NULL);
> + delay += end.tv_usec;
> + end.tv_sec += delay / 1000000;
> + end.tv_usec = delay % 1000000;
I think we should use timeradd() here, as this might be out by part of
a second.
> +
> + while (gettimeofday(&now, NULL),
> + now.tv_sec < end.tv_sec || now.tv_usec < end.tv_usec) {
This condition is a little clever and also buggy. You'll at least need
something like:
while(gettimeofday(&now, NULL),
now.tv_sec < end.tv_sec ||
now.tv_sec == end.tv_sec && now.tv_usec < end.tv_usec) { ... }
Depending on the value of loop you may wind up in the position where
now.tv_usec < end.tv_usec is true for multiple loops beyond now.tv_sec
< end.tv_sec failing with the case now.tv_sec > end.tv_sec.
But you should probably use timercmp().
> + clock_step(loop * 1000);
> + usleep(loop);
> + }
> +}
> +
> +/**
> + * Sleep for some emulated time while counting interrupts
> + * @param delay the delay in nanoseconds
> + * @param loop the loop time in nanoseconds
> + */
> +static void wait_cycles(uint64_t delay, uint64_t loop)
> +{
> + uint64_t counter;
> +
> + for (counter = 0; counter < delay; counter += loop) {
> + clock_step(loop);
> + }
> +}
> +
> +
> +/**
> + * Check that when the update timer interrupt is disabled, that no interrupts
> + * occur
> + */
> +static void check_update_interrupt_disabled(void)
> +{
> + /* Disable the update interrupt */
> + clear_bits_in_register(CONTROL_REGISTER, CTRL_MASK_UIE);
> +
> + /* Wait for the clock to rollover, this will cover both seconds & minutes
> + */
> + set_time(59, 59, 23, 1, 29, 2, 16);
> +
> + count_reset();
> + wait_for(2 * 1000000, 1000);
> +
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_UF], ==, 0);
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_AF], ==, 0);
> +}
> +
> +
> +/**
> + * Check that when the update timer interrupt is enabled and configured for
> + * per second updates, that we get the appropriate number of interrupts
> + */
> +static void check_update_interrupt_seconds(void)
> +{
> + set_time(59, 59, 23, 1, 29, 2, 16);
> +
> + /* Enable the update interrupt for per second updates */
> + clear_bits_in_register(EXTENSION_REGISTER, EXT_MASK_USEL);
> + set_bits_in_register(CONTROL_REGISTER, CTRL_MASK_UIE);
> +
> + count_reset();
> + wait_for(5.1f * 1000000ULL, 1000);
> +
> + /* Disable the update interrupt */
> + clear_bits_in_register(CONTROL_REGISTER, CTRL_MASK_UIE);
> +
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_UF], >=, 5);
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_UF], <=, 6);
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_AF], ==, 0);
> +}
> +
> +/**
> + * Check that when the update timer interrupt is enabled and configured for
> + * per minute updates, that we get the appropriate number of interrupts
> + */
> +static void check_update_interrupt_minutes(void)
> +{
> + set_time(59, 59, 23, 1, 29, 2, 16);
> +
> + /* Enable the update interrupt for per minute updates */
> + set_bits_in_register(EXTENSION_REGISTER, EXT_MASK_USEL);
> + set_bits_in_register(CONTROL_REGISTER, CTRL_MASK_UIE);
> +
> + count_reset();
> + wait_for(5 * 1000000ULL, 1000);
> +
> + /* Disable the update interrupt */
> + clear_bits_in_register(CONTROL_REGISTER, CTRL_MASK_UIE);
> +
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_UF], ==, 1);
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_AF], ==, 0);
> +}
> +
> +
> +/**
> + * Check that when the alarm timer interrupt is disabled, that no interrupts
> + * occur
> + */
> +static void check_alarm_interrupt_disabled(void)
> +{
> + /* Disable the alarm interrupt */
> + clear_bits_in_register(CONTROL_REGISTER, CTRL_MASK_AIE);
> +
> + /* Set an alarm for midnight */
> + uint8_t buf[3];
> +
> + buf[0] = bin2bcd(0); /* minutes */
> + buf[1] = bin2bcd(0); /* hours */
> + buf[2] = bin2bcd(1); /* day */
> +
> + write_registers(ALARM_MINUTE, buf, 3);
> +
> + /* Wait for the clock to rollover */
> + set_time(59, 59, 23, 1, 29, 2, 16);
> +
> + count_reset();
> + wait_for(2 * 1000000, 1000);
> +
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_UF], ==, 0);
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_AF], ==, 0);
> +}
> +
> +/**
> + * Check that when the alarm timer interrupt is enabled, that an interrupt
> + * occurs
> + */
> +static void check_alarm_interrupt_day_of_month(void)
> +{
> +
> + /* Set an alarm for midnight */
> + uint8_t buf[3];
> +
> + buf[0] = bin2bcd(0); /* minutes */
> + buf[1] = bin2bcd(0); /* hours */
> + buf[2] = bin2bcd(1); /* day */
> +
> + write_registers(ALARM_MINUTE, buf, 3);
> +
> + /* Set alarm to day of month mode */
> + set_bits_in_register(EXTENSION_REGISTER, EXT_MASK_WADA);
> +
> + /* Enable the alarm interrupt */
> + set_bits_in_register(CONTROL_REGISTER, CTRL_MASK_AIE);
> +
> + /* Wait for the clock to rollover */
> + set_time(59, 59, 23, 1, 29, 2, 16);
> +
> + count_reset();
> + wait_for(2 * 1000000, 1000);
> +
> + /* Disable the alarm interrupt */
> + clear_bits_in_register(CONTROL_REGISTER, CTRL_MASK_AIE);
> +
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_UF], ==, 0);
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_AF], ==, 1);
> +}
> +
> +/**
> + * Check that when the alarm timer interrupt is enabled, that an interrupt
> + * does not occur
> + */
> +static void check_alarm_interrupt_day_of_month_negative(void)
> +{
> +
> + /* Set an alarm for midnight */
> + uint8_t buf[3];
> +
> + buf[0] = bin2bcd(0); /* minutes */
> + buf[1] = bin2bcd(0); /* hours */
> + buf[2] = bin2bcd(2); /* day */
> +
> + write_registers(ALARM_MINUTE, buf, 3);
> +
> + /* Set alarm to day of month mode */
> + set_bits_in_register(EXTENSION_REGISTER, EXT_MASK_WADA);
> +
> + /* Enable the alarm interrupt */
> + set_bits_in_register(CONTROL_REGISTER, CTRL_MASK_AIE);
> +
> + /* Wait for the clock to rollover */
> + set_time(59, 59, 23, 1, 29, 2, 16);
> +
> + count_reset();
> + wait_for(2 * 1000000, 1000);
> +
> + /* Disable the alarm interrupt */
> + clear_bits_in_register(CONTROL_REGISTER, CTRL_MASK_AIE);
> +
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_UF], ==, 0);
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_AF], ==, 0);
> +}
> +
> +/**
> + * Check that when the alarm timer interrupt is enabled, that an interrupt
> + * occurs
> + */
> +static void check_alarm_interrupt_day_of_week(void)
> +{
> +
> + /* Set an alarm for midnight */
> + uint8_t buf[3];
> +
> + buf[0] = bin2bcd(0); /* minutes */
> + buf[1] = bin2bcd(0); /* hours */
> + buf[2] = 0x01 << 2; /* day */
> +
> + write_registers(ALARM_MINUTE, buf, 3);
> +
> + /* Set alarm to day of week mode */
> + clear_bits_in_register(EXTENSION_REGISTER, EXT_MASK_WADA);
> +
> + /* Enable the alarm interrupt */
> + set_bits_in_register(CONTROL_REGISTER, CTRL_MASK_AIE);
> +
> + /* Wait for the clock to rollover */
> + set_time(59, 59, 23, 1, 29, 2, 16);
> +
> + count_reset();
> + wait_for(2 * 1000000, 1000);
> +
> + /* Disable the alarm interrupt */
> + clear_bits_in_register(CONTROL_REGISTER, CTRL_MASK_AIE);
> +
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_UF], ==, 0);
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_AF], ==, 1);
> +}
> +
> +/**
> + * Check that when the alarm timer interrupt is enabled, that an interrupt
> + * does not occur
> + */
> +static void check_alarm_interrupt_day_of_week_negative(void)
> +{
> +
> + /* Set an alarm for midnight */
> + uint8_t buf[3];
> +
> + buf[0] = bin2bcd(0); /* minutes */
> + buf[1] = bin2bcd(0); /* hours */
> + buf[2] = 0x01 << 2; /* day */
> +
> + write_registers(ALARM_MINUTE, buf, 3);
> +
> + /* Set alarm to day of week mode */
> + clear_bits_in_register(EXTENSION_REGISTER, EXT_MASK_WADA);
> +
> + /* Enable the alarm interrupt */
> + set_bits_in_register(CONTROL_REGISTER, CTRL_MASK_AIE);
> +
> + /* Wait for the clock to rollover */
> + set_time(59, 59, 23, 3, 29, 2, 16);
> +
> + count_reset();
> + wait_for(2 * 1000000, 1000);
> +
> + /* Disable the alarm interrupt */
> + clear_bits_in_register(CONTROL_REGISTER, CTRL_MASK_AIE);
> +
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_UF], ==, 0);
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_AF], ==, 0);
> +}
> +
> +/**
> + * Check that the reset function
> + */
> +static void check_reset(void)
> +{
> + set_bits_in_register(FLAG_REGISTER, FLAG_MASK_UF);
> + set_bits_in_register(CONTROL_REGISTER, CTRL_MASK_RESET);
> +
> + g_assert_cmpuint(read_register(FLAG_REGISTER), ==,
> + 0x00);
> +}
> +
> +/**
> + * Check that Fout operates at 1Hz
> + */
> +static void check_fout_1hz(void)
> +{
> + uint8_t ext_reg = read_register(EXTENSION_REGISTER);
> + ext_reg |= EXT_MASK_FSEL1;
> + ext_reg &= ~EXT_MASK_FSEL0;
> + write_register(EXTENSION_REGISTER, ext_reg);
> +
> + /* Enable Fout */
> + irq_set(RX8900_TEST_ID, RX8900_FOUT_ENABLE, 0, true);
> +
> + fout_count_reset();
> + wait_cycles(2 * 1000000000ULL, 1000000);
> +
> + /* disable Fout */
> + irq_set(RX8900_TEST_ID, RX8900_FOUT_ENABLE, 0, false);
> +
> + g_assert_cmpuint(fout_counts, ==, 2);
> +}
> +
> +/**
> + * Check that Fout operates at 1024Hz
> + */
> +static void check_fout_1024hz(void)
> +{
> + uint8_t ext_reg = read_register(EXTENSION_REGISTER);
> + ext_reg |= EXT_MASK_FSEL0;
> + ext_reg &= ~EXT_MASK_FSEL1;
> + write_register(EXTENSION_REGISTER, ext_reg);
> +
> + /* Enable Fout */
> + irq_set(RX8900_TEST_ID, RX8900_FOUT_ENABLE, 0, true);
> +
> + fout_count_reset();
> + wait_cycles(2 * 1000000000ULL, 100000);
> +
> + /* disable Fout */
> + irq_set(RX8900_TEST_ID, RX8900_FOUT_ENABLE, 0, false);
> +
> + g_assert_cmpuint(fout_counts, ==, 1024 * 2);
> +}
> +
> +/**
> + * Check that Fout operates at 32768Hz
> + */
> +static void check_fout_32768hz(void)
> +{
> + uint8_t ext_reg = read_register(EXTENSION_REGISTER);
> + ext_reg &= ~EXT_MASK_FSEL0;
> + ext_reg &= ~EXT_MASK_FSEL1;
> + write_register(EXTENSION_REGISTER, ext_reg);
> +
> + /* Enable Fout */
> + irq_set(RX8900_TEST_ID, RX8900_FOUT_ENABLE, 0, true);
> +
> + fout_count_reset();
> + wait_cycles(2 * 1000000000ULL, 15000);
> +
> + /* disable Fout */
> + irq_set(RX8900_TEST_ID, RX8900_FOUT_ENABLE, 0, false);
> +
> + /* There appears to be some rounding errors in the timer,
> + * we'll tolerate it for now
> + */
> + g_assert_cmpuint(fout_counts, >=, 32768 * 2);
> + g_assert_cmpuint(fout_counts, <=, 65540);
Maybe it would be more intuitive to write this as (32768 * 2 + 4) so
it's clear what the tolerance is.
> +}
> +
> +/**
> + * Check the countdown timer operates at 1 Hz
> + */
> +static void check_countdown_1hz(void)
> +{
> + uint8_t ext_reg;
> +
> + write_register(TIMER_COUNTER_0, 5);
> + write_register(TIMER_COUNTER_1, 0);
> +
> + ext_reg = read_register(EXTENSION_REGISTER);
> + ext_reg &= ~EXT_MASK_TSEL1;
> + ext_reg |= EXT_MASK_TSEL0;
> + ext_reg |= EXT_MASK_TE;
> + write_register(EXTENSION_REGISTER, ext_reg);
> + set_bits_in_register(CONTROL_REGISTER, CTRL_MASK_TIE);
> +
> + count_reset();
> + wait_cycles(5 * 1000000000ULL, 1000000);
> +
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_TF], ==, 0);
> +
> + wait_cycles(1 * 1000000000ULL, 1000000);
> +
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_TF], ==, 1);
> +}
> +
> +/**
> + * Check the countdown timer operates at 64 Hz
> + */
> +static void check_countdown_64hz(void)
> +{
> + uint8_t ext_reg;
> +
> + write_register(TIMER_COUNTER_0, 0x40);
> + write_register(TIMER_COUNTER_1, 0x01); /* 5 * 64 */
> +
> + ext_reg = read_register(EXTENSION_REGISTER);
> + ext_reg &= ~EXT_MASK_TSEL0;
> + ext_reg &= ~EXT_MASK_TSEL1;
> + ext_reg |= EXT_MASK_TE;
> + write_register(EXTENSION_REGISTER, ext_reg);
> + set_bits_in_register(CONTROL_REGISTER, CTRL_MASK_TIE);
> +
> + count_reset();
> + wait_cycles(5 * 1000000000ULL, 1000000);
> +
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_TF], ==, 0);
> +
> + wait_cycles(1 * 1000000000ULL, 1000000);
> +
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_TF], ==, 1);
> +}
> +
> +/**
> + * Check the countdown timer operates at 4096 Hz
> + */
> +static void check_countdown_4096hz(void)
> +{
> + uint8_t ext_reg;
> +
> + write_register(TIMER_COUNTER_0, 0xFF);
> + write_register(TIMER_COUNTER_1, 0x0F); /* 4095 */
> + ext_reg = read_register(EXTENSION_REGISTER);
> + ext_reg |= EXT_MASK_TSEL0;
> + ext_reg |= EXT_MASK_TSEL1;
> + ext_reg |= EXT_MASK_TE;
> + write_register(EXTENSION_REGISTER, ext_reg);
> + set_bits_in_register(CONTROL_REGISTER, CTRL_MASK_TIE);
> +
> + count_reset();
> + wait_cycles(999755859ULL, 10000);
> +
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_TF], ==, 0);
> +
> + wait_cycles(244141ULL, 10000);
> +
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_TF], ==, 1);
> +}
> +
> +/**
> + * Check the countdown timer operates at 1 minute
> + */
> +static void check_countdown_1m(void)
> +{
> + uint8_t ext_reg;
> +
> + write_register(TIMER_COUNTER_0, 0x01);
> + write_register(TIMER_COUNTER_1, 0x00);
> + ext_reg = read_register(EXTENSION_REGISTER);
> + ext_reg &= ~EXT_MASK_TSEL0;
> + ext_reg |= EXT_MASK_TSEL1;
> + ext_reg |= EXT_MASK_TE;
> + write_register(EXTENSION_REGISTER, ext_reg);
> + set_bits_in_register(CONTROL_REGISTER, CTRL_MASK_TIE);
> +
> + count_reset();
> + wait_cycles(59 * 1000000000ULL, 100000);
> +
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_TF], ==, 0);
> +
> + wait_cycles(1000000001LL, 100000);
> +
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_TF], ==, 1);
> +}
> +
> +/**
> + * Check that the voltage can be altered via properties
> + */
> +static void check_voltage(void)
> +{
> + uint8_t flags = read_register(FLAG_REGISTER) &
> + (FLAG_MASK_VDET | FLAG_MASK_VLF);
> +
> + /* start from a good state */
> + g_assert_cmpuint(flags, == , 0x00);
> +
> + /* 1.9V triggers VDET but not VLF */
> + qmp_rx8900_set_voltage(RX8900_TEST_ID, 1.9f);
> +
> + flags = read_register(FLAG_REGISTER) & (FLAG_MASK_VDET | FLAG_MASK_VLF);
> + g_assert_cmpuint(flags, == , FLAG_MASK_VDET);
> +
> + /* Clearing the flag should reassert it as the voltage is still low */
> + write_register(FLAG_REGISTER, 0x00);
> +
> + flags = read_register(FLAG_REGISTER) & (FLAG_MASK_VDET | FLAG_MASK_VLF);
> + g_assert_cmpuint(flags, == , FLAG_MASK_VDET);
> +
> + /* Set the voltage to a good level, the low voltage flag should persist */
> + qmp_rx8900_set_voltage(RX8900_TEST_ID, 3.3f);
> +
> + flags = read_register(FLAG_REGISTER) & (FLAG_MASK_VDET | FLAG_MASK_VLF);
> + g_assert_cmpuint(flags, == , FLAG_MASK_VDET);
> +
> + /* We should be able to clear the flag with a good voltage */
> + write_register(FLAG_REGISTER, 0x00);
> +
> + flags = read_register(FLAG_REGISTER) & (FLAG_MASK_VDET | FLAG_MASK_VLF);
> + g_assert_cmpuint(flags, == , 0x00);
> +
> +
> + /* 1.5V should trigger both VDET & VLF */
> + qmp_rx8900_set_voltage(RX8900_TEST_ID, 1.5f);
> + flags = read_register(FLAG_REGISTER) & (FLAG_MASK_VDET | FLAG_MASK_VLF);
> + g_assert_cmpuint(flags, == , FLAG_MASK_VDET | FLAG_MASK_VLF);
> +
> +
> + /* Clearing the flag should reassert it as the voltage is still low */
> + write_register(FLAG_REGISTER, 0x00);
> +
> + flags = read_register(FLAG_REGISTER) & (FLAG_MASK_VDET | FLAG_MASK_VLF);
> + g_assert_cmpuint(flags, == , FLAG_MASK_VDET | FLAG_MASK_VLF);
> +
> + /* Set the voltage to a good level, the low voltage flag should persist */
> + qmp_rx8900_set_voltage(RX8900_TEST_ID, 3.3f);
> +
> + flags = read_register(FLAG_REGISTER) & (FLAG_MASK_VDET | FLAG_MASK_VLF);
> + g_assert_cmpuint(flags, == , FLAG_MASK_VDET | FLAG_MASK_VLF);
> +
> + /* We should be able to clear the flag with a good voltage */
> + write_register(FLAG_REGISTER, 0x00);
> +
> + flags = read_register(FLAG_REGISTER) & (FLAG_MASK_VDET | FLAG_MASK_VLF);
> + g_assert_cmpuint(flags, == , 0);
> +}
> +
> +
> +
> +int main(int argc, char **argv)
> +{
> + QTestState *s = NULL;
> + int ret;
> + char args[255];
> + snprintf(args, sizeof(args), "-display none -machine imx25-pdk "
> + "-device rx8900,bus=i2c-bus.0,address=0x%x,id=%s"
> +#ifdef RX8900_TRACE
> + " -trace events=/tmp/events"
> +#endif
> + ,
> + RX8900_ADDR, RX8900_TEST_ID);
> +
> + g_test_init(&argc, &argv, NULL);
> +
> + s = qtest_start(args);
> + i2c = imx_i2c_create(IMX25_I2C_0_BASE);
> + addr = RX8900_ADDR;
> +
> + irq_intercept_out(RX8900_TEST_ID);
> + irq_attach(RX8900_INTERRUPT_OUT, 0, handle_interrupt, NULL);
> + irq_attach(RX8900_FOUT, 0, handle_fout, NULL);
> +
> + qtest_add_func("/rx8900/reset", check_reset);
> + qtest_add_func("/rx8900/tx-rx", send_and_receive);
> + qtest_add_func("/rx8900/temperature", check_temperature);
> + qtest_add_func("/rx8900/rollover", check_rollover);
> + qtest_add_func("/rx8900/update-interrupt-disabled",
> + check_update_interrupt_disabled);
> + qtest_add_func("/rx8900/update-interrupt-seconds",
> + check_update_interrupt_seconds);
> + qtest_add_func("/rx8900/update-interrupt-minutes",
> + check_update_interrupt_minutes);
> + qtest_add_func("/rx8900/alarm-interrupt-disabled",
> + check_alarm_interrupt_disabled);
> + qtest_add_func("/rx8900/alarm-interrupt-month",
> + check_alarm_interrupt_day_of_month);
> + qtest_add_func("/rx8900/alarm-interrupt-month-negative",
> + check_alarm_interrupt_day_of_month_negative);
> + qtest_add_func("/rx8900/alarm-interrupt-week",
> + check_alarm_interrupt_day_of_week);
> + qtest_add_func("/rx8900/alarm-interrupt-week-negative",
> + check_alarm_interrupt_day_of_week_negative);
> + qtest_add_func("/rx8900/fout_1hz", check_fout_1hz);
> + qtest_add_func("/rx8900/fout_1024hz", check_fout_1024hz);
> + qtest_add_func("/rx8900/fout_32768hz", check_fout_32768hz);
> + qtest_add_func("/rx8900/countdown_1hz", check_countdown_1hz);
> + qtest_add_func("/rx8900/countdown_64hz", check_countdown_64hz);
> + qtest_add_func("/rx8900/countdown_4096hz", check_countdown_4096hz);
> + qtest_add_func("/rx8900/countdown_1m", check_countdown_1m);
> + qtest_add_func("/rx8900/low_voltage", check_voltage);
> +
> + ret = g_test_run();
> +
> + if (s) {
> + qtest_quit(s);
> + }
> + g_free(i2c);
> +
> + return ret;
> +}
Andrew
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply
* Re: [Qemu-devel] [PATCH v4 7/8] tests: Test all implemented RX8900 functionality
From: Andrew Jeffery @ 2017-01-04 6:14 UTC (permalink / raw)
To: Alastair D'Silva, qemu-arm
Cc: qemu-devel, Peter Maydell, Cédric Le Goater, Joel Stanley,
Alastair D'Silva
In-Reply-To: <20161215054812.12602-8-alastair@au1.ibm.com>
[-- Attachment #1: Type: text/plain, Size: 31763 bytes --]
Hi Alastair,
Again, small comments below.
On Thu, 2016-12-15 at 16:48 +1100, Alastair D'Silva wrote:
> > From: Alastair D'Silva <alastair@d-silva.org>
>
> > Signed-off-by: Alastair D'Silva <alastair@d-silva.org>
> ---
> tests/Makefile.include | 2 +
> tests/rx8900-test.c | 882 +++++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 884 insertions(+)
> create mode 100644 tests/rx8900-test.c
>
> diff --git a/tests/Makefile.include b/tests/Makefile.include
> index e98d3b6..e52e355 100644
> --- a/tests/Makefile.include
> +++ b/tests/Makefile.include
> @@ -300,6 +300,7 @@ check-qtest-sparc64-y = tests/endianness-test$(EXESUF)
>
> check-qtest-arm-y = tests/tmp105-test$(EXESUF)
> check-qtest-arm-y += tests/ds1338-test$(EXESUF)
> +check-qtest-arm-y += tests/rx8900-test$(EXESUF)
> check-qtest-arm-y += tests/m25p80-test$(EXESUF)
> gcov-files-arm-y += hw/misc/tmp105.c
> check-qtest-arm-y += tests/virtio-blk-test$(EXESUF)
> @@ -637,6 +638,7 @@ tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o \
> tests/pxe-test$(EXESUF): tests/pxe-test.o tests/boot-sector.o $(libqos-obj-y)
> tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y)
> tests/ds1338-test$(EXESUF): tests/ds1338-test.o $(libqos-imx-obj-y)
> +tests/rx8900-test$(EXESUF): tests/rx8900-test.o $(libqos-imx-obj-y)
> tests/m25p80-test$(EXESUF): tests/m25p80-test.o
> tests/i440fx-test$(EXESUF): tests/i440fx-test.o $(libqos-pc-obj-y)
> tests/q35-test$(EXESUF): tests/q35-test.o $(libqos-pc-obj-y)
> diff --git a/tests/rx8900-test.c b/tests/rx8900-test.c
> new file mode 100644
> index 0000000..1769659
> --- /dev/null
> +++ b/tests/rx8900-test.c
> @@ -0,0 +1,882 @@
> +/*
> + * QTest testcase for the Epson RX8900SA/CE RTC
> + *
> + * Copyright (c) 2016 IBM Corporation
> + * Authors:
> > + * Alastair D'Silva <alastair@d-silva.org>
> + *
> + * This code is licensed under the GPL version 2 or later. See
> + * the COPYING file in the top-level directory.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "hw/timer/rx8900_regs.h"
> +#include "libqtest.h"
> +#include "libqos/i2c.h"
> +#include "qemu/timer.h"
> +
> +#define IMX25_I2C_0_BASE 0x43F80000
> +#define RX8900_TEST_ID "rx8900-test"
> +#define RX8900_ADDR 0x32
> +#define RX8900_INTERRUPT_OUT "rx8900-interrupt-out"
> +#define RX8900_FOUT_ENABLE "rx8900-fout-enable"
> +#define RX8900_FOUT "rx8900-fout"
> +
> +static I2CAdapter *i2c;
> +static uint8_t addr;
> +
> +static inline uint8_t bcd2bin(uint8_t x)
> +{
> + return (x & 0x0f) + (x >> 4) * 10;
> +}
> +
> +static inline uint8_t bin2bcd(uint8_t x)
> +{
> + return (x / 10 << 4) | (x % 10);
> +}
> +
> +static void qmp_rx8900_set_temperature(const char *id, double value)
> +{
> + QDict *response;
> +
> + response = qmp("{ 'execute': 'qom-set', 'arguments': { 'path': %s, "
> + "'property': 'temperature', 'value': %f } }", id, value);
> + g_assert(qdict_haskey(response, "return"));
> + QDECREF(response);
> +}
> +
> +static void qmp_rx8900_set_voltage(const char *id, double value)
> +{
> + QDict *response;
> +
> + response = qmp("{ 'execute': 'qom-set', 'arguments': { 'path': %s, "
> + "'property': 'voltage', 'value': %f } }", id, value);
> + g_assert(qdict_haskey(response, "return"));
> + QDECREF(response);
> +}
> +
> +/**
> + * Read an RX8900 register
> + * @param reg the address of the register
> + * @return the value of the register
> + */
> +static uint8_t read_register(RX8900Addresses reg)
> +{
> + uint8_t val;
> + uint8_t reg_address = (uint8_t)reg;
> +
> + i2c_send(i2c, addr, ®_address, 1);
> + i2c_recv(i2c, addr, &val, 1);
> +
> + return val;
> +}
> +
> +/**
> + * Write to an RX8900 register
> + * @param reg the address of the register
> + * @param val the value to write
> + */
> +static uint8_t write_register(RX8900Addresses reg, uint8_t val)
> +{
> + uint8_t buf[2];
> +
> + buf[0] = reg;
> + buf[1] = val;
> +
> + i2c_send(i2c, addr, buf, 2);
> +
> + return val;
> +}
> +
> +/**
> + * Set bits in a register
> + * @param reg the address of the register
> + * @param mask a mask of the bits to set
> + */
> +static void set_bits_in_register(RX8900Addresses reg, uint8_t mask)
> +{
> + uint8_t value = read_register(reg);
> + value |= mask;
> + write_register(reg, value);
> +}
> +
> +/**
> + * Clear bits in a register
> + * @param reg the address of the register
> + * @param mask a mask of the bits to set
> + */
> +static void clear_bits_in_register(RX8900Addresses reg, uint8_t mask)
> +{
> + uint8_t value = read_register(reg);
> + value &= ~mask;
> + write_register(reg, value);
> +}
> +
> +/**
> + * Read a number of sequential RX8900 registers
> + * @param reg the address of the first register
> + * @param buf (out) an output buffer to stash the register values
> + * @param count the number of registers to read
> + */
> +static void read_registers(RX8900Addresses reg, uint8_t *buf, uint8_t count)
> +{
> + uint8_t reg_address = (uint8_t)reg;
> +
> + i2c_send(i2c, addr, ®_address, 1);
> + i2c_recv(i2c, addr, buf, count);
> +}
> +
> +/**
> + * Write to a sequential number of RX8900 registers
> + * @param reg the address of the first register
> + * @param buffer a buffer of values to write
> + * @param count the sumber of registers to write
> + */
> +static void write_registers(RX8900Addresses reg, uint8_t *buffer, uint8_t count)
> +{
> + uint8_t buf[RX8900_NVRAM_SIZE + 1];
> +
> + buf[0] = (uint8_t)reg;
> + memcpy(buf + 1, buffer, count);
> +
> + i2c_send(i2c, addr, buf, count + 1);
> +}
> +
> +/**
> + * Set the time on the RX8900
> + * @param secs the seconds to set
> + * @param mins the minutes to set
> + * @param hours the hours to set
> + * @param weekday the day of the week to set (0 = Sunday)
> + * @param day the day of the month to set
> + * @param month the month to set
> + * @param year the year to set
> + */
> +static void set_time(uint8_t secs, uint8_t mins, uint8_t hours,
> + uint8_t weekday, uint8_t day, uint8_t month, uint8_t year)
> +{
> + uint8_t buf[7];
> +
> + buf[0] = bin2bcd(secs);
> + buf[1] = bin2bcd(mins);
> + buf[2] = bin2bcd(hours);
> + buf[3] = BIT(weekday);
> + buf[4] = bin2bcd(day);
> + buf[5] = bin2bcd(month);
> + buf[6] = bin2bcd(year);
> +
> + write_registers(SECONDS, buf, 7);
> +}
> +
> +
> +/**
> + * Check basic communication
> + */
> +static void send_and_receive(void)
> +{
> + uint8_t buf[7];
> + time_t now = time(NULL);
> + struct tm *tm_ptr;
> +
> + /* retrieve the date */
> + read_registers(SECONDS, buf, 7);
> +
> + tm_ptr = gmtime(&now);
> +
> + /* check retrieved time against local time */
> + g_assert_cmpuint(bcd2bin(buf[0]), == , tm_ptr->tm_sec);
> + g_assert_cmpuint(bcd2bin(buf[1]), == , tm_ptr->tm_min);
> + g_assert_cmpuint(bcd2bin(buf[2]), == , tm_ptr->tm_hour);
> + g_assert_cmpuint(bcd2bin(buf[4]), == , tm_ptr->tm_mday);
> + g_assert_cmpuint(bcd2bin(buf[5]), == , 1 + tm_ptr->tm_mon);
> + g_assert_cmpuint(2000 + bcd2bin(buf[6]), == , 1900 + tm_ptr->tm_year);
> +}
> +
> +/**
> + * Check that the temperature can be altered via properties
> + */
> +static void check_temperature(void)
> +{
> + /* Check the initial temperature is 25C */
> + uint8_t temperature;
> +
> + temperature = read_register(TEMPERATURE);
> + g_assert_cmpuint(temperature, == , 133);
> +
> + /* Set the temperature to 40C and check the temperature again */
> + qmp_rx8900_set_temperature(RX8900_TEST_ID, 40.0f);
> + temperature = read_register(TEMPERATURE);
> + g_assert_cmpuint(temperature, == , 157);
> +}
> +
> +/**
> + * Check that the time rolls over correctly
> + */
> +static void check_rollover(void)
> +{
> + uint8_t buf[7];
> +
> +
> + set_time(59, 59, 23, 1, 29, 2, 16);
> +
> + /* Wait for the clock to rollover */
> + sleep(2);
>
Can we control time some other way so we're not delaying the test
suite? I assume not?
> +
> + memset(buf, 0, sizeof(buf));
> +
> + /* Check that the clock rolled over */
> + /* Read from registers starting at 0x00 */
> + buf[0] = 0x00;
> +
> + read_registers(SECONDS, buf, 7);
> +
> + /* Ignore seconds as there may be some noise,
> + * we expect 00:00:xx Tuesday 1/3/2016
> + */
this is why it would be nice if we could control time.
> + g_assert_cmpuint(bcd2bin(buf[1]), == , 0);
> + g_assert_cmpuint(bcd2bin(buf[2]), == , 0);
> + g_assert_cmpuint(bcd2bin(buf[3]), == , 0x04);
> + g_assert_cmpuint(bcd2bin(buf[4]), == , 1);
> + g_assert_cmpuint(bcd2bin(buf[5]), == , 3);
> + g_assert_cmpuint(bcd2bin(buf[6]), == , 16);
> +}
> +
> +uint32_t interrupt_counts[RX8900_INTERRUPT_SOURCES];
> +
> +/**
> + * Reset the interrupt counts
> + */
> +static void count_reset(void)
> +{
> + for (int source = 0; source < RX8900_INTERRUPT_SOURCES; source++) {
> + interrupt_counts[source] = 0;
> + }
> +}
> +
> +/**
> + * Handle an RX8900 interrupt (update the counts for that interrupt type)
> + */
> +static void handle_interrupt(void *opaque, const char *name, int irq,
> + bool level)
> +{
> + if (!level) {
> + return;
> + }
> +
> + uint8_t flags = read_register(FLAG_REGISTER);
> +
> + for (int flag = 0; flag < 8; flag++) {
> + if (flags & BIT(flag)) {
> + interrupt_counts[flag]++;
> + }
> + }
> +
> + write_register(FLAG_REGISTER, 0x00);
> +}
> +
> +uint32_t fout_counts;
> +
> +/**
> + * Handle an Fout state change
> + */
> +static void handle_fout(void *opaque, const char *name, int irq, bool level)
> +{
> + if (!level) {
> + return;
> + }
> +
> + fout_counts++;
> +}
> +
> +/**
> + * Reset the fout count
> + */
> +static void fout_count_reset(void)
> +{
> + fout_counts = 0;
> +}
> +
> +
> +/**
> + * Sleep for some real time while counting interrupts
> + * @param delay the delay in microseconds
> + * @param loop the loop time in microseconds
> + */
> +static void wait_for(uint64_t delay, uint64_t loop)
> +{
> + struct timeval end, now;
> +
> + gettimeofday(&end, NULL);
> + delay += end.tv_usec;
> + end.tv_sec += delay / 1000000;
> + end.tv_usec = delay % 1000000;
I think we should use timeradd() here, as this might be out by part of
a second.
> +
> + while (gettimeofday(&now, NULL),
> + now.tv_sec < end.tv_sec || now.tv_usec < end.tv_usec) {
This condition is a little clever and also buggy. You'll at least need
something like:
while(gettimeofday(&now, NULL),
now.tv_sec < end.tv_sec ||
now.tv_sec == end.tv_sec && now.tv_usec < end.tv_usec) { ... }
Depending on the value of loop you may wind up in the position where
now.tv_usec < end.tv_usec is true for multiple loops beyond now.tv_sec
< end.tv_sec failing with the case now.tv_sec > end.tv_sec.
But you should probably use timercmp().
> + clock_step(loop * 1000);
> + usleep(loop);
> + }
> +}
> +
> +/**
> + * Sleep for some emulated time while counting interrupts
> + * @param delay the delay in nanoseconds
> + * @param loop the loop time in nanoseconds
> + */
> +static void wait_cycles(uint64_t delay, uint64_t loop)
> +{
> + uint64_t counter;
> +
> + for (counter = 0; counter < delay; counter += loop) {
> + clock_step(loop);
> + }
> +}
> +
> +
> +/**
> + * Check that when the update timer interrupt is disabled, that no interrupts
> + * occur
> + */
> +static void check_update_interrupt_disabled(void)
> +{
> + /* Disable the update interrupt */
> + clear_bits_in_register(CONTROL_REGISTER, CTRL_MASK_UIE);
> +
> + /* Wait for the clock to rollover, this will cover both seconds & minutes
> + */
> + set_time(59, 59, 23, 1, 29, 2, 16);
> +
> + count_reset();
> + wait_for(2 * 1000000, 1000);
> +
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_UF], ==, 0);
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_AF], ==, 0);
> +}
> +
> +
> +/**
> + * Check that when the update timer interrupt is enabled and configured for
> + * per second updates, that we get the appropriate number of interrupts
> + */
> +static void check_update_interrupt_seconds(void)
> +{
> + set_time(59, 59, 23, 1, 29, 2, 16);
> +
> + /* Enable the update interrupt for per second updates */
> + clear_bits_in_register(EXTENSION_REGISTER, EXT_MASK_USEL);
> + set_bits_in_register(CONTROL_REGISTER, CTRL_MASK_UIE);
> +
> + count_reset();
> + wait_for(5.1f * 1000000ULL, 1000);
> +
> + /* Disable the update interrupt */
> + clear_bits_in_register(CONTROL_REGISTER, CTRL_MASK_UIE);
> +
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_UF], >=, 5);
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_UF], <=, 6);
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_AF], ==, 0);
> +}
> +
> +/**
> + * Check that when the update timer interrupt is enabled and configured for
> + * per minute updates, that we get the appropriate number of interrupts
> + */
> +static void check_update_interrupt_minutes(void)
> +{
> + set_time(59, 59, 23, 1, 29, 2, 16);
> +
> + /* Enable the update interrupt for per minute updates */
> + set_bits_in_register(EXTENSION_REGISTER, EXT_MASK_USEL);
> + set_bits_in_register(CONTROL_REGISTER, CTRL_MASK_UIE);
> +
> + count_reset();
> + wait_for(5 * 1000000ULL, 1000);
> +
> + /* Disable the update interrupt */
> + clear_bits_in_register(CONTROL_REGISTER, CTRL_MASK_UIE);
> +
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_UF], ==, 1);
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_AF], ==, 0);
> +}
> +
> +
> +/**
> + * Check that when the alarm timer interrupt is disabled, that no interrupts
> + * occur
> + */
> +static void check_alarm_interrupt_disabled(void)
> +{
> + /* Disable the alarm interrupt */
> + clear_bits_in_register(CONTROL_REGISTER, CTRL_MASK_AIE);
> +
> + /* Set an alarm for midnight */
> + uint8_t buf[3];
> +
> + buf[0] = bin2bcd(0); /* minutes */
> + buf[1] = bin2bcd(0); /* hours */
> + buf[2] = bin2bcd(1); /* day */
> +
> + write_registers(ALARM_MINUTE, buf, 3);
> +
> + /* Wait for the clock to rollover */
> + set_time(59, 59, 23, 1, 29, 2, 16);
> +
> + count_reset();
> + wait_for(2 * 1000000, 1000);
> +
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_UF], ==, 0);
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_AF], ==, 0);
> +}
> +
> +/**
> + * Check that when the alarm timer interrupt is enabled, that an interrupt
> + * occurs
> + */
> +static void check_alarm_interrupt_day_of_month(void)
> +{
> +
> + /* Set an alarm for midnight */
> + uint8_t buf[3];
> +
> + buf[0] = bin2bcd(0); /* minutes */
> + buf[1] = bin2bcd(0); /* hours */
> + buf[2] = bin2bcd(1); /* day */
> +
> + write_registers(ALARM_MINUTE, buf, 3);
> +
> + /* Set alarm to day of month mode */
> + set_bits_in_register(EXTENSION_REGISTER, EXT_MASK_WADA);
> +
> + /* Enable the alarm interrupt */
> + set_bits_in_register(CONTROL_REGISTER, CTRL_MASK_AIE);
> +
> + /* Wait for the clock to rollover */
> + set_time(59, 59, 23, 1, 29, 2, 16);
> +
> + count_reset();
> + wait_for(2 * 1000000, 1000);
> +
> + /* Disable the alarm interrupt */
> + clear_bits_in_register(CONTROL_REGISTER, CTRL_MASK_AIE);
> +
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_UF], ==, 0);
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_AF], ==, 1);
> +}
> +
> +/**
> + * Check that when the alarm timer interrupt is enabled, that an interrupt
> + * does not occur
> + */
> +static void check_alarm_interrupt_day_of_month_negative(void)
> +{
> +
> + /* Set an alarm for midnight */
> + uint8_t buf[3];
> +
> + buf[0] = bin2bcd(0); /* minutes */
> + buf[1] = bin2bcd(0); /* hours */
> + buf[2] = bin2bcd(2); /* day */
> +
> + write_registers(ALARM_MINUTE, buf, 3);
> +
> + /* Set alarm to day of month mode */
> + set_bits_in_register(EXTENSION_REGISTER, EXT_MASK_WADA);
> +
> + /* Enable the alarm interrupt */
> + set_bits_in_register(CONTROL_REGISTER, CTRL_MASK_AIE);
> +
> + /* Wait for the clock to rollover */
> + set_time(59, 59, 23, 1, 29, 2, 16);
> +
> + count_reset();
> + wait_for(2 * 1000000, 1000);
> +
> + /* Disable the alarm interrupt */
> + clear_bits_in_register(CONTROL_REGISTER, CTRL_MASK_AIE);
> +
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_UF], ==, 0);
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_AF], ==, 0);
> +}
> +
> +/**
> + * Check that when the alarm timer interrupt is enabled, that an interrupt
> + * occurs
> + */
> +static void check_alarm_interrupt_day_of_week(void)
> +{
> +
> + /* Set an alarm for midnight */
> + uint8_t buf[3];
> +
> + buf[0] = bin2bcd(0); /* minutes */
> + buf[1] = bin2bcd(0); /* hours */
> + buf[2] = 0x01 << 2; /* day */
> +
> + write_registers(ALARM_MINUTE, buf, 3);
> +
> + /* Set alarm to day of week mode */
> + clear_bits_in_register(EXTENSION_REGISTER, EXT_MASK_WADA);
> +
> + /* Enable the alarm interrupt */
> + set_bits_in_register(CONTROL_REGISTER, CTRL_MASK_AIE);
> +
> + /* Wait for the clock to rollover */
> + set_time(59, 59, 23, 1, 29, 2, 16);
> +
> + count_reset();
> + wait_for(2 * 1000000, 1000);
> +
> + /* Disable the alarm interrupt */
> + clear_bits_in_register(CONTROL_REGISTER, CTRL_MASK_AIE);
> +
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_UF], ==, 0);
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_AF], ==, 1);
> +}
> +
> +/**
> + * Check that when the alarm timer interrupt is enabled, that an interrupt
> + * does not occur
> + */
> +static void check_alarm_interrupt_day_of_week_negative(void)
> +{
> +
> + /* Set an alarm for midnight */
> + uint8_t buf[3];
> +
> + buf[0] = bin2bcd(0); /* minutes */
> + buf[1] = bin2bcd(0); /* hours */
> + buf[2] = 0x01 << 2; /* day */
> +
> + write_registers(ALARM_MINUTE, buf, 3);
> +
> + /* Set alarm to day of week mode */
> + clear_bits_in_register(EXTENSION_REGISTER, EXT_MASK_WADA);
> +
> + /* Enable the alarm interrupt */
> + set_bits_in_register(CONTROL_REGISTER, CTRL_MASK_AIE);
> +
> + /* Wait for the clock to rollover */
> + set_time(59, 59, 23, 3, 29, 2, 16);
> +
> + count_reset();
> + wait_for(2 * 1000000, 1000);
> +
> + /* Disable the alarm interrupt */
> + clear_bits_in_register(CONTROL_REGISTER, CTRL_MASK_AIE);
> +
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_UF], ==, 0);
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_AF], ==, 0);
> +}
> +
> +/**
> + * Check that the reset function
> + */
> +static void check_reset(void)
> +{
> + set_bits_in_register(FLAG_REGISTER, FLAG_MASK_UF);
> + set_bits_in_register(CONTROL_REGISTER, CTRL_MASK_RESET);
> +
> + g_assert_cmpuint(read_register(FLAG_REGISTER), ==,
> + 0x00);
> +}
> +
> +/**
> + * Check that Fout operates at 1Hz
> + */
> +static void check_fout_1hz(void)
> +{
> + uint8_t ext_reg = read_register(EXTENSION_REGISTER);
> + ext_reg |= EXT_MASK_FSEL1;
> + ext_reg &= ~EXT_MASK_FSEL0;
> + write_register(EXTENSION_REGISTER, ext_reg);
> +
> + /* Enable Fout */
> + irq_set(RX8900_TEST_ID, RX8900_FOUT_ENABLE, 0, true);
> +
> + fout_count_reset();
> + wait_cycles(2 * 1000000000ULL, 1000000);
> +
> + /* disable Fout */
> + irq_set(RX8900_TEST_ID, RX8900_FOUT_ENABLE, 0, false);
> +
> + g_assert_cmpuint(fout_counts, ==, 2);
> +}
> +
> +/**
> + * Check that Fout operates at 1024Hz
> + */
> +static void check_fout_1024hz(void)
> +{
> + uint8_t ext_reg = read_register(EXTENSION_REGISTER);
> + ext_reg |= EXT_MASK_FSEL0;
> + ext_reg &= ~EXT_MASK_FSEL1;
> + write_register(EXTENSION_REGISTER, ext_reg);
> +
> + /* Enable Fout */
> + irq_set(RX8900_TEST_ID, RX8900_FOUT_ENABLE, 0, true);
> +
> + fout_count_reset();
> + wait_cycles(2 * 1000000000ULL, 100000);
> +
> + /* disable Fout */
> + irq_set(RX8900_TEST_ID, RX8900_FOUT_ENABLE, 0, false);
> +
> + g_assert_cmpuint(fout_counts, ==, 1024 * 2);
> +}
> +
> +/**
> + * Check that Fout operates at 32768Hz
> + */
> +static void check_fout_32768hz(void)
> +{
> + uint8_t ext_reg = read_register(EXTENSION_REGISTER);
> + ext_reg &= ~EXT_MASK_FSEL0;
> + ext_reg &= ~EXT_MASK_FSEL1;
> + write_register(EXTENSION_REGISTER, ext_reg);
> +
> + /* Enable Fout */
> + irq_set(RX8900_TEST_ID, RX8900_FOUT_ENABLE, 0, true);
> +
> + fout_count_reset();
> + wait_cycles(2 * 1000000000ULL, 15000);
> +
> + /* disable Fout */
> + irq_set(RX8900_TEST_ID, RX8900_FOUT_ENABLE, 0, false);
> +
> + /* There appears to be some rounding errors in the timer,
> + * we'll tolerate it for now
> + */
> + g_assert_cmpuint(fout_counts, >=, 32768 * 2);
> + g_assert_cmpuint(fout_counts, <=, 65540);
Maybe it would be more intuitive to write this as (32768 * 2 + 4) so
it's clear what the tolerance is.
> +}
> +
> +/**
> + * Check the countdown timer operates at 1 Hz
> + */
> +static void check_countdown_1hz(void)
> +{
> + uint8_t ext_reg;
> +
> + write_register(TIMER_COUNTER_0, 5);
> + write_register(TIMER_COUNTER_1, 0);
> +
> + ext_reg = read_register(EXTENSION_REGISTER);
> + ext_reg &= ~EXT_MASK_TSEL1;
> + ext_reg |= EXT_MASK_TSEL0;
> + ext_reg |= EXT_MASK_TE;
> + write_register(EXTENSION_REGISTER, ext_reg);
> + set_bits_in_register(CONTROL_REGISTER, CTRL_MASK_TIE);
> +
> + count_reset();
> + wait_cycles(5 * 1000000000ULL, 1000000);
> +
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_TF], ==, 0);
> +
> + wait_cycles(1 * 1000000000ULL, 1000000);
> +
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_TF], ==, 1);
> +}
> +
> +/**
> + * Check the countdown timer operates at 64 Hz
> + */
> +static void check_countdown_64hz(void)
> +{
> + uint8_t ext_reg;
> +
> + write_register(TIMER_COUNTER_0, 0x40);
> + write_register(TIMER_COUNTER_1, 0x01); /* 5 * 64 */
> +
> + ext_reg = read_register(EXTENSION_REGISTER);
> + ext_reg &= ~EXT_MASK_TSEL0;
> + ext_reg &= ~EXT_MASK_TSEL1;
> + ext_reg |= EXT_MASK_TE;
> + write_register(EXTENSION_REGISTER, ext_reg);
> + set_bits_in_register(CONTROL_REGISTER, CTRL_MASK_TIE);
> +
> + count_reset();
> + wait_cycles(5 * 1000000000ULL, 1000000);
> +
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_TF], ==, 0);
> +
> + wait_cycles(1 * 1000000000ULL, 1000000);
> +
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_TF], ==, 1);
> +}
> +
> +/**
> + * Check the countdown timer operates at 4096 Hz
> + */
> +static void check_countdown_4096hz(void)
> +{
> + uint8_t ext_reg;
> +
> + write_register(TIMER_COUNTER_0, 0xFF);
> + write_register(TIMER_COUNTER_1, 0x0F); /* 4095 */
> + ext_reg = read_register(EXTENSION_REGISTER);
> + ext_reg |= EXT_MASK_TSEL0;
> + ext_reg |= EXT_MASK_TSEL1;
> + ext_reg |= EXT_MASK_TE;
> + write_register(EXTENSION_REGISTER, ext_reg);
> + set_bits_in_register(CONTROL_REGISTER, CTRL_MASK_TIE);
> +
> + count_reset();
> + wait_cycles(999755859ULL, 10000);
> +
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_TF], ==, 0);
> +
> + wait_cycles(244141ULL, 10000);
> +
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_TF], ==, 1);
> +}
> +
> +/**
> + * Check the countdown timer operates at 1 minute
> + */
> +static void check_countdown_1m(void)
> +{
> + uint8_t ext_reg;
> +
> + write_register(TIMER_COUNTER_0, 0x01);
> + write_register(TIMER_COUNTER_1, 0x00);
> + ext_reg = read_register(EXTENSION_REGISTER);
> + ext_reg &= ~EXT_MASK_TSEL0;
> + ext_reg |= EXT_MASK_TSEL1;
> + ext_reg |= EXT_MASK_TE;
> + write_register(EXTENSION_REGISTER, ext_reg);
> + set_bits_in_register(CONTROL_REGISTER, CTRL_MASK_TIE);
> +
> + count_reset();
> + wait_cycles(59 * 1000000000ULL, 100000);
> +
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_TF], ==, 0);
> +
> + wait_cycles(1000000001LL, 100000);
> +
> + g_assert_cmpuint(interrupt_counts[FLAG_REG_TF], ==, 1);
> +}
> +
> +/**
> + * Check that the voltage can be altered via properties
> + */
> +static void check_voltage(void)
> +{
> + uint8_t flags = read_register(FLAG_REGISTER) &
> + (FLAG_MASK_VDET | FLAG_MASK_VLF);
> +
> + /* start from a good state */
> + g_assert_cmpuint(flags, == , 0x00);
> +
> + /* 1.9V triggers VDET but not VLF */
> + qmp_rx8900_set_voltage(RX8900_TEST_ID, 1.9f);
> +
> + flags = read_register(FLAG_REGISTER) & (FLAG_MASK_VDET | FLAG_MASK_VLF);
> + g_assert_cmpuint(flags, == , FLAG_MASK_VDET);
> +
> + /* Clearing the flag should reassert it as the voltage is still low */
> + write_register(FLAG_REGISTER, 0x00);
> +
> + flags = read_register(FLAG_REGISTER) & (FLAG_MASK_VDET | FLAG_MASK_VLF);
> + g_assert_cmpuint(flags, == , FLAG_MASK_VDET);
> +
> + /* Set the voltage to a good level, the low voltage flag should persist */
> + qmp_rx8900_set_voltage(RX8900_TEST_ID, 3.3f);
> +
> + flags = read_register(FLAG_REGISTER) & (FLAG_MASK_VDET | FLAG_MASK_VLF);
> + g_assert_cmpuint(flags, == , FLAG_MASK_VDET);
> +
> + /* We should be able to clear the flag with a good voltage */
> + write_register(FLAG_REGISTER, 0x00);
> +
> + flags = read_register(FLAG_REGISTER) & (FLAG_MASK_VDET | FLAG_MASK_VLF);
> + g_assert_cmpuint(flags, == , 0x00);
> +
> +
> + /* 1.5V should trigger both VDET & VLF */
> + qmp_rx8900_set_voltage(RX8900_TEST_ID, 1.5f);
> + flags = read_register(FLAG_REGISTER) & (FLAG_MASK_VDET | FLAG_MASK_VLF);
> + g_assert_cmpuint(flags, == , FLAG_MASK_VDET | FLAG_MASK_VLF);
> +
> +
> + /* Clearing the flag should reassert it as the voltage is still low */
> + write_register(FLAG_REGISTER, 0x00);
> +
> + flags = read_register(FLAG_REGISTER) & (FLAG_MASK_VDET | FLAG_MASK_VLF);
> + g_assert_cmpuint(flags, == , FLAG_MASK_VDET | FLAG_MASK_VLF);
> +
> + /* Set the voltage to a good level, the low voltage flag should persist */
> + qmp_rx8900_set_voltage(RX8900_TEST_ID, 3.3f);
> +
> + flags = read_register(FLAG_REGISTER) & (FLAG_MASK_VDET | FLAG_MASK_VLF);
> + g_assert_cmpuint(flags, == , FLAG_MASK_VDET | FLAG_MASK_VLF);
> +
> + /* We should be able to clear the flag with a good voltage */
> + write_register(FLAG_REGISTER, 0x00);
> +
> + flags = read_register(FLAG_REGISTER) & (FLAG_MASK_VDET | FLAG_MASK_VLF);
> + g_assert_cmpuint(flags, == , 0);
> +}
> +
> +
> +
> +int main(int argc, char **argv)
> +{
> + QTestState *s = NULL;
> + int ret;
> + char args[255];
> + snprintf(args, sizeof(args), "-display none -machine imx25-pdk "
> + "-device rx8900,bus=i2c-bus.0,address=0x%x,id=%s"
> +#ifdef RX8900_TRACE
> + " -trace events=/tmp/events"
> +#endif
> + ,
> + RX8900_ADDR, RX8900_TEST_ID);
> +
> + g_test_init(&argc, &argv, NULL);
> +
> + s = qtest_start(args);
> + i2c = imx_i2c_create(IMX25_I2C_0_BASE);
> + addr = RX8900_ADDR;
> +
> + irq_intercept_out(RX8900_TEST_ID);
> + irq_attach(RX8900_INTERRUPT_OUT, 0, handle_interrupt, NULL);
> + irq_attach(RX8900_FOUT, 0, handle_fout, NULL);
> +
> + qtest_add_func("/rx8900/reset", check_reset);
> + qtest_add_func("/rx8900/tx-rx", send_and_receive);
> + qtest_add_func("/rx8900/temperature", check_temperature);
> + qtest_add_func("/rx8900/rollover", check_rollover);
> + qtest_add_func("/rx8900/update-interrupt-disabled",
> + check_update_interrupt_disabled);
> + qtest_add_func("/rx8900/update-interrupt-seconds",
> + check_update_interrupt_seconds);
> + qtest_add_func("/rx8900/update-interrupt-minutes",
> + check_update_interrupt_minutes);
> + qtest_add_func("/rx8900/alarm-interrupt-disabled",
> + check_alarm_interrupt_disabled);
> + qtest_add_func("/rx8900/alarm-interrupt-month",
> + check_alarm_interrupt_day_of_month);
> + qtest_add_func("/rx8900/alarm-interrupt-month-negative",
> + check_alarm_interrupt_day_of_month_negative);
> + qtest_add_func("/rx8900/alarm-interrupt-week",
> + check_alarm_interrupt_day_of_week);
> + qtest_add_func("/rx8900/alarm-interrupt-week-negative",
> + check_alarm_interrupt_day_of_week_negative);
> + qtest_add_func("/rx8900/fout_1hz", check_fout_1hz);
> + qtest_add_func("/rx8900/fout_1024hz", check_fout_1024hz);
> + qtest_add_func("/rx8900/fout_32768hz", check_fout_32768hz);
> + qtest_add_func("/rx8900/countdown_1hz", check_countdown_1hz);
> + qtest_add_func("/rx8900/countdown_64hz", check_countdown_64hz);
> + qtest_add_func("/rx8900/countdown_4096hz", check_countdown_4096hz);
> + qtest_add_func("/rx8900/countdown_1m", check_countdown_1m);
> + qtest_add_func("/rx8900/low_voltage", check_voltage);
> +
> + ret = g_test_run();
> +
> + if (s) {
> + qtest_quit(s);
> + }
> + g_free(i2c);
> +
> + return ret;
> +}
Andrew
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply
* Re: [PATCH v3 5/7] net/virtio_user: add vhost kernel support
From: Yuanhan Liu @ 2017-01-04 6:13 UTC (permalink / raw)
To: Jianfeng Tan; +Cc: dev, ferruh.yigit, cunming.liang
In-Reply-To: <1483502366-140154-6-git-send-email-jianfeng.tan@intel.com>
On Wed, Jan 04, 2017 at 03:59:24AM +0000, Jianfeng Tan wrote:
> +static int
> +vhost_kernel_ioctl(struct virtio_user_dev *dev,
> + enum vhost_user_request req,
> + void *arg)
> +{
> + int i, ret = -1;
> + uint64_t req_kernel;
> + struct vhost_memory_kernel *vm = NULL;
> +
> + PMD_DRV_LOG(INFO, "%s", vhost_msg_strings[req]);
> +
> + req_kernel = vhost_req_user_to_kernel[req];
> +
> + if (req_kernel == VHOST_SET_MEM_TABLE) {
> + vm = prepare_vhost_memory_kernel();
> + if (!vm)
> + return -1;
> + arg = (void *)vm;
> + }
> +
> + /* Does not work when VIRTIO_F_IOMMU_PLATFORM now, why? */
> + if (req_kernel == VHOST_SET_FEATURES)
> + *(uint64_t *)arg &= ~(1ULL << VIRTIO_F_IOMMU_PLATFORM);
You missed my comments in last version?
--yliu
^ permalink raw reply
* Re: [ANNOUNCE] xfs-linux: xfs-4.10-misc-fixes-5 updated to ff97f23
From: Christoph Hellwig @ 2017-01-04 6:11 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: xfs
In-Reply-To: <20170104054721.GC14031@birch.djwong.org>
On Tue, Jan 03, 2017 at 09:47:21PM -0800, Darrick J. Wong wrote:
> Patches often get missed, so please check if your outstanding
> patches were in this update. If they have not been in this update,
> please resubmit them to linux-xfs@vger.kernel.org so they can be
> picked up in the next update.
>
> I intend to send these four bugfixes to Linus later this week, but
> thought I'd run it by the list first to see if anyone spots anything
> obviously broken.
I'd really like to get the minleft fixes reviewed and to Linus:
http://www.spinics.net/lists/linux-xfs/msg03036.html
^ permalink raw reply
* Re: [PATCH v3 4/7] net/virtio_user: abstract virtio user backend ops
From: Yuanhan Liu @ 2017-01-04 6:11 UTC (permalink / raw)
To: Jianfeng Tan; +Cc: dev, ferruh.yigit, cunming.liang
In-Reply-To: <1483502366-140154-5-git-send-email-jianfeng.tan@intel.com>
On Wed, Jan 04, 2017 at 03:59:23AM +0000, Jianfeng Tan wrote:
> +struct virtio_user_backend_ops ops_user;
Better to qualify it with "extern const" ...
--yliu
^ permalink raw reply
* Re: wanted: bash completion for wg(8)
From: Jason A. Donenfeld @ 2017-01-04 6:12 UTC (permalink / raw)
To: WireGuard mailing list
In-Reply-To: <CAHmME9q=3bjbDaWY3cYqm69LKhH3wnTdobBZ==qu0=N-T8T3bw@mail.gmail.com>
Nevermind. Already done.
https://git.zx2c4.com/WireGuard/commit/?id=f7dac3ca0359f6067f47d17ecd461d4d26ce6fa2
^ permalink raw reply
* adding 32 bit compatibility layer in custom kernel module
From: Pradeepa Kumar @ 2017-01-04 6:03 UTC (permalink / raw)
To: kernelnewbies
In-Reply-To: <AA9E6AEB-4932-4E62-8E3A-BFFE2E909770@gmail.com>
Please see inline below
On Wed, Jan 4, 2017 at 11:07 AM, Anish Kumar <anish198519851985@gmail.com>
wrote:
>
>
> On Jan 3, 2017, at 8:04 PM, Pradeepa Kumar <cdpradeepa@gmail.com> wrote:
>
> Hi experts
>
> down votefavorite
> <http://stackoverflow.com/questions/41455943/adding-32-bit-compatibility-layer-in-custom-kernel-module#>
>
> in my 64 bit kernel, I have a custom kernel module providing new protocol
> and providing socket system calls.
>
> it works fine when 64 bit app runs.
>
> i am seeing issues when 32 bit app runs (for exp recvmsg() call does not
> work if msg has cmsghdrs as struct size of cmsghdr is different in 32 bit
> and 64 bit).
>
> This is because my custom kernel module does not have 32 bit compatibility
> layer ( but linux kernel has this in compat.c etc).
>
> -
>
> is it simple to add compatibility layer to my custom kernel module
>
>
> All you have to do is add compat_ioctl call to your driver.
>
> my kernel module provides recvmsg() but i dont see any 'compat_recvmsg' in
struct proto_ops.
had there been 'compat_recvmsg' it would have been possible for me to
define recvmsg() for 32 bit apps.
please let me know if i am missing anything
> -
>
> how do i do this (any links ?)
>
>
> You can see many drivers supports compat call.
>
> Thanks
>
> _______________________________________________
> Kernelnewbies mailing list
> Kernelnewbies at kernelnewbies.org
> https://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.kernelnewbies.org/pipermail/kernelnewbies/attachments/20170104/e6680e3c/attachment-0001.html
^ permalink raw reply
* Re: ext4 filesystem corruption with 4.10-rc2 on ppc64le
From: Chandan Rajendra @ 2017-01-04 6:02 UTC (permalink / raw)
To: Anton Blanchard
Cc: jack, Michael Ellerman, Benjamin Herrenschmidt, Paul Mackerras,
Stephen Rothwell, axboe, linuxppc-dev, linux-kernel, linux-ext4,
linux-fsdevel
In-Reply-To: <20170104161808.5ad7b4fd@kryten>
On Wednesday, January 04, 2017 04:18:08 PM Anton Blanchard wrote:
> Hi,
>
> I'm consistently seeing ext4 filesystem corruption using a mainline
> kernel. It doesn't take much to trigger it - download a ppc64le Ubuntu
> cloud image, boot it in KVM and run:
>
> sudo apt-get update
> sudo apt-get dist-upgrade
> sudo reboot
>
> And it never makes it back up, dying with rather severe filesystem
> corruption.
Hi,
The patch at https://patchwork.kernel.org/patch/9488235/ should fix the
bug.
>
> I've narrowed it down to:
>
> 64e1c57fa474 ("ext4: Use clean_bdev_aliases() instead of iteration")
> e64855c6cfaa ("fs: Add helper to clean bdev aliases under a bh and use it")
> ce98321bf7d2 ("fs: Remove unmap_underlying_metadata")
>
> Backing these patches out fixes the issue.
>
> Anton
> --
> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
chandan
^ permalink raw reply
* [radeon-alex:amd-staging-drm-next 155/158] drivers/gpu/drm/amd/amdgpu/../display/dc/dce/dce_link_encoder.c:1066:2: warning: this 'if' clause does not guard...
From: kbuild test robot @ 2017-01-04 6:01 UTC (permalink / raw)
To: Hersen Wu; +Cc: Alex Deucher, kbuild-all, dri-devel, Zeyu Fan
[-- Attachment #1: Type: text/plain, Size: 3516 bytes --]
tree: git://people.freedesktop.org/~agd5f/linux.git amd-staging-drm-next
head: 5d8e75c019bf76889bd606a67afabf7d0b32d3fa
commit: 008cc768ebd34f1c205cd2066f6ab450d90a9022 [155/158] drm/amd/display: set HBR3 and TPS4 capable flags
config: alpha-allyesconfig (attached as .config)
compiler: alpha-linux-gnu-gcc (Debian 6.1.1-9) 6.1.1 20160705
reproduce:
wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
git checkout 008cc768ebd34f1c205cd2066f6ab450d90a9022
# save the attached .config to linux build tree
make.cross ARCH=alpha
All warnings (new ones prefixed by >>):
drivers/gpu/drm/amd/amdgpu/../display/dc/dce/dce_link_encoder.c: In function 'dce110_link_encoder_construct':
>> drivers/gpu/drm/amd/amdgpu/../display/dc/dce/dce_link_encoder.c:1066:2: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
if (BP_RESULT_OK == bp_funcs->get_encoder_cap_info(
^~
drivers/gpu/drm/amd/amdgpu/../display/dc/dce/dce_link_encoder.c:1071:3: note: ...this statement, but the latter is misleadingly indented as if it is guarded by the 'if'
enc110->base.features.flags.bits.IS_HBR3_CAPABLE =
^~~~~~
vim +/if +1066 drivers/gpu/drm/amd/amdgpu/../display/dc/dce/dce_link_encoder.c
5a0a7096 Harry Wentland 2017-01-03 1050 break;
5a0a7096 Harry Wentland 2017-01-03 1051 default:
5a0a7096 Harry Wentland 2017-01-03 1052 ASSERT_CRITICAL(false);
5a0a7096 Harry Wentland 2017-01-03 1053 enc110->base.preferred_engine = ENGINE_ID_UNKNOWN;
5a0a7096 Harry Wentland 2017-01-03 1054 }
5a0a7096 Harry Wentland 2017-01-03 1055
5a0a7096 Harry Wentland 2017-01-03 1056 dm_logger_write(init_data->ctx->logger, LOG_I2C_AUX,
5a0a7096 Harry Wentland 2017-01-03 1057 "Using channel: %s [%d]\n",
5a0a7096 Harry Wentland 2017-01-03 1058 DECODE_CHANNEL_ID(init_data->channel),
5a0a7096 Harry Wentland 2017-01-03 1059 init_data->channel);
5a0a7096 Harry Wentland 2017-01-03 1060
5a0a7096 Harry Wentland 2017-01-03 1061 /* Override features with DCE-specific values */
5a0a7096 Harry Wentland 2017-01-03 1062 {
5a0a7096 Harry Wentland 2017-01-03 1063 struct bp_encoder_cap_info bp_cap_info = {0};
5a0a7096 Harry Wentland 2017-01-03 1064 const struct dc_vbios_funcs *bp_funcs = enc110->base.ctx->dc_bios->funcs;
5a0a7096 Harry Wentland 2017-01-03 1065
5a0a7096 Harry Wentland 2017-01-03 @1066 if (BP_RESULT_OK == bp_funcs->get_encoder_cap_info(
5a0a7096 Harry Wentland 2017-01-03 1067 enc110->base.ctx->dc_bios, enc110->base.id,
5a0a7096 Harry Wentland 2017-01-03 1068 &bp_cap_info))
5a0a7096 Harry Wentland 2017-01-03 1069 enc110->base.features.flags.bits.IS_HBR2_CAPABLE =
5a0a7096 Harry Wentland 2017-01-03 1070 bp_cap_info.DP_HBR2_CAP;
008cc768 Hersen Wu 2016-12-23 1071 enc110->base.features.flags.bits.IS_HBR3_CAPABLE =
008cc768 Hersen Wu 2016-12-23 1072 bp_cap_info.DP_HBR3_EN;
008cc768 Hersen Wu 2016-12-23 1073
5a0a7096 Harry Wentland 2017-01-03 1074 }
:::::: The code at line 1066 was first introduced by commit
:::::: 5a0a709652ceaca0a36ef2d0954b8d9d3f690560 drm/amd/dc: Add dc display driver
:::::: TO: Harry Wentland <harry.wentland@amd.com>
:::::: CC: Alex Deucher <alexander.deucher@amd.com>
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 47963 bytes --]
[-- Attachment #3: Type: text/plain, Size: 160 bytes --]
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply
* Re: ext4 filesystem corruption with 4.10-rc2 on ppc64le
From: Chandan Rajendra @ 2017-01-04 6:02 UTC (permalink / raw)
To: Anton Blanchard
Cc: Stephen Rothwell, jack, linux-kernel, axboe, Paul Mackerras,
linux-fsdevel, linux-ext4, linuxppc-dev
In-Reply-To: <20170104161808.5ad7b4fd@kryten>
On Wednesday, January 04, 2017 04:18:08 PM Anton Blanchard wrote:
> Hi,
>
> I'm consistently seeing ext4 filesystem corruption using a mainline
> kernel. It doesn't take much to trigger it - download a ppc64le Ubuntu
> cloud image, boot it in KVM and run:
>
> sudo apt-get update
> sudo apt-get dist-upgrade
> sudo reboot
>
> And it never makes it back up, dying with rather severe filesystem
> corruption.
Hi,
The patch at https://patchwork.kernel.org/patch/9488235/ should fix the
bug.
>
> I've narrowed it down to:
>
> 64e1c57fa474 ("ext4: Use clean_bdev_aliases() instead of iteration")
> e64855c6cfaa ("fs: Add helper to clean bdev aliases under a bh and use it")
> ce98321bf7d2 ("fs: Remove unmap_underlying_metadata")
>
> Backing these patches out fixes the issue.
>
> Anton
> --
> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
chandan
^ permalink raw reply
* Re: [PATCH v3 3/7] net/virtio_user: move vhost user specific code
From: Yuanhan Liu @ 2017-01-04 6:02 UTC (permalink / raw)
To: Jianfeng Tan; +Cc: dev, ferruh.yigit, cunming.liang
In-Reply-To: <1483502366-140154-4-git-send-email-jianfeng.tan@intel.com>
On Wed, Jan 04, 2017 at 03:59:22AM +0000, Jianfeng Tan wrote:
> To support vhost kernel as the backend of net_virtio_user in coming
> patches, we move vhost_user specific structs and macros into
> vhost_user.c, and only keep common definitions in vhost.h.
>
> Besides, remove VHOST_USER_MQ feature check.
Again, I have to ask, why? You don't only remove the check, also, you
removed this feature setting, which seems to break the MQ support?
--yliu
^ permalink raw reply
* Re: [PATCH] Fix max_retries _show and _store functions
From: Darrick J. Wong @ 2017-01-04 5:58 UTC (permalink / raw)
To: Carlos Maiolino; +Cc: linux-xfs
In-Reply-To: <20170103175331.8089-1-cmaiolino@redhat.com>
On Tue, Jan 03, 2017 at 06:53:31PM +0100, Carlos Maiolino wrote:
> max_retries _show and _store functions should test against cfg->max_retries,
> not cfg->retry_timeout
>
> Signed-off-by: Carlos Maiolino <cmaiolino@redhat.com>
> ---
> fs/xfs/xfs_sysfs.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/fs/xfs/xfs_sysfs.c b/fs/xfs/xfs_sysfs.c
> index 276d302..de6195e 100644
> --- a/fs/xfs/xfs_sysfs.c
> +++ b/fs/xfs/xfs_sysfs.c
> @@ -396,7 +396,7 @@ max_retries_show(
> int retries;
> struct xfs_error_cfg *cfg = to_error_cfg(kobject);
>
> - if (cfg->retry_timeout == XFS_ERR_RETRY_FOREVER)
> + if (cfg->max_retries == XFS_ERR_RETRY_FOREVER)
> retries = -1;
> else
> retries = cfg->max_retries;
> @@ -422,7 +422,7 @@ max_retries_store(
> return -EINVAL;
>
> if (val == -1)
> - cfg->retry_timeout = XFS_ERR_RETRY_FOREVER;
> + cfg->max_retries = XFS_ERR_RETRY_FOREVER;
Applied, thanks.
--D
> else
> cfg->max_retries = val;
> return count;
> --
> 2.9.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH 3/6 linux-next] fs/affs: make affs exportable
From: Fabian Frederick @ 2017-01-04 5:53 UTC (permalink / raw)
To: Al Viro; +Cc: Andrew Morton, linux-kernel, Jan Kara, linux-fsdevel
In-Reply-To: <20170103222906.GC1555@ZenIV.linux.org.uk>
> On 03 January 2017 at 23:29 Al Viro <viro@ZenIV.linux.org.uk> wrote:
>
>
> On Tue, Jan 03, 2017 at 10:30:39PM +0100, Fabian Frederick wrote:
> > Add standard functions making AFFS work with NFS.
> >
> > Functions based on ext4 implementation.
> > Tested on loop device.
>
> How the hell is that supposed to work with cold dcache? You don't have
> ->get_parent() there at all...
>
> There *IS* a reference to parent directory in those suckers - not the same
> kind as in normal unix filesystems (".." is not a directory entry there -
> it's all fake), but it's doable. be32_to_cpu(AFFS_TAIL(sb, bh)->parent)
> would be the inumber you need, where bh is the inode block of directory.
>
> So it can be done, but not in this form. NAK for the time being...
I worked on that function declared optional in
Documentation/filesystems/nfs/Exporting
but was unable to test it.
Regards,
Fabian
^ permalink raw reply
* Re: [PATCH] xfs: fix crash and data corruption due to removal of busy COW extents
From: Darrick J. Wong @ 2017-01-04 5:53 UTC (permalink / raw)
To: Christoph Hellwig; +Cc: linux-xfs
In-Reply-To: <1483258387-5548-1-git-send-email-hch@lst.de>
On Sun, Jan 01, 2017 at 11:13:06AM +0300, Christoph Hellwig wrote:
> There is a race window between write_cache_pages calling
> clear_page_dirty_for_io and XFS calling set_page_writeback, in which
> the mapping for an inode is tagged neither as dirty, nor as writeback.
>
> If the COW shrinker hits in exactly that window we'll remove the delayed
> COW extents and writepages trying to write it back, which in release
> kernels will manifest as corruption of the bmap btree, and in debug
> kernels will trip the ASSERT about now calling xfs_bmapi_write with the
> COWFORK flag for holes. A complex customer load manages to hit this
> window fairly reliably, probably by always having COW writeback in flight
> while the cow shrinker runs.
>
> This patch adds another check for having the I_DIRTY_PAGES flag set,
> which is still set during this race window. While this fixes the problem
> I'm still not overly happy about the way the COW shrinker works as it
> still seems a bit fragile.
>
> Signed-off-by: Christoph Hellwig <hch@lst.de>
> ---
> fs/xfs/xfs_icache.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c
> index f295049..2d5a63a 100644
> --- a/fs/xfs/xfs_icache.c
> +++ b/fs/xfs/xfs_icache.c
> @@ -1593,7 +1593,8 @@ xfs_inode_free_cowblocks(
> * If the mapping is dirty or under writeback we cannot touch the
> * CoW fork. Leave it alone if we're in the midst of a directio.
> */
> - if (mapping_tagged(VFS_I(ip)->i_mapping, PAGECACHE_TAG_DIRTY) ||
> + if ((VFS_I(ip)->i_state & I_DIRTY_PAGES) ||
> + mapping_tagged(VFS_I(ip)->i_mapping, PAGECACHE_TAG_DIRTY) ||
> mapping_tagged(VFS_I(ip)->i_mapping, PAGECACHE_TAG_WRITEBACK) ||
> atomic_read(&VFS_I(ip)->i_dio_count))
> return 0;
Applied, thx.
--D
> --
> 2.1.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Please add fscrypt.git to linux-next
From: Theodore Ts'o @ 2017-01-04 4:44 UTC (permalink / raw)
To: Stephen Rothwell; +Cc: linux-next, linux-kernel
Could you please add:
git://git.kernel.org/pub/scm/linux/kernel/git/tytso/fscrypt.git master
To the linux-next tree? I was previously feeding fscrypt changes by
merging them into the ext4.git dev branch, but it will make life
simpler if we have a separate git tree for it.
Linus has already accepted a pull request from the for-stable branch
of fscrypt.git. I plan to send a separate pull request for the master
branch of fscrypt.git during the next merge window.
Thanks!!
- Ted
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.