Skip to content

Conversation

@nategraff-sifive
Copy link
Contributor

@nategraff-sifive nategraff-sifive commented Oct 7, 2019

Update the SiFive GPIO driver for the new GPIO API, including replacing deprecated flag names, implementing the port_* API surface, and moving interrupt configuration to pin_interrupt_configure.

One of the drivers tracked in #18530

@zephyrbot
Copy link

zephyrbot commented Oct 7, 2019

All checks are passing now.

checkpatch (informational only, not a failure)

-:308: WARNING:LONG_LINE_COMMENT: line over 80 characters
#308: FILE: drivers/gpio/gpio_sifive.c:340:
+		/* TODO: The interrupt functionality of this driver is incomplete,

-:310: WARNING:LONG_LINE_COMMENT: line over 80 characters
#310: FILE: drivers/gpio/gpio_sifive.c:342:
+		 * I'm just returning -ENOTSUP until we can track down the issue.

-:329: WARNING:LONG_LINE_COMMENT: line over 80 characters
#329: FILE: drivers/gpio/gpio_sifive.c:361:
+		/* TODO: The interrupt functionality of this driver is incomplete,

-:331: WARNING:LONG_LINE_COMMENT: line over 80 characters
#331: FILE: drivers/gpio/gpio_sifive.c:363:
+		 * I'm just returning -ENOTSUP until we can track down the issue.

- total: 0 errors, 4 warnings, 404 lines checked

NOTE: For some of the reported defects, checkpatch may be able to
      mechanically convert to the typical style using --fix or --fix-inplace.

Your patch has style problems, please review.

NOTE: Ignored message types: AVOID_EXTERNS BRACES CONFIG_EXPERIMENTAL CONST_STRUCT DATE_TIME FILE_PATH_CHANGES MINMAX NETWORKING_BLOCK_COMMENT_STYLE PRINTK_WITHOUT_KERN_LEVEL SPLIT_STRING VOLATILE

NOTE: If any of the errors are false positives, please report
      them to the maintainers.

Tip: The bot edits this comment instead of posting a new one, so you can check the comment's history to see earlier messages.

@carlescufi
Copy link
Member

@nategraff-sifive
The topic branch has been rebased. Could you please rebase this PR against it?

@nategraff-sifive
Copy link
Contributor Author

@carlescufi rebased 👍

@mnkp mnkp self-requested a review October 13, 2019 17:51
@nategraff-sifive
Copy link
Contributor Author

@mnkp, thanks for your feedback! I've updated the PR based on your suggestions. What do you think of the new configure? I'm setting/clearing all of the bits with the WRITE_BIT macro now.

Copy link
Member

@mnkp mnkp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! LGTM with one remark.

It would be great if you could verify that the driver is passing tests/drivers/gpio/gpio_api_1pin/ testcase. You need to run it on the board which has LED0 defined in the board DTS file.

@nategraff-sifive
Copy link
Contributor Author

I'm getting some test failures on tests/drivers/gpio/gpio_api_1pin/ on hifive1_revb

***** Booting Zephyr OS build zephyr-v2.0.0-1178-gfb2acd99d9d8 *****
Running test suite gpio_api_1pin_test
===================================================================
starting test - test_gpio_pin_configure_push_pull
Running test on port=gpio_0, pin=19
PASS - test_gpio_pin_configure_push_pull
===================================================================
starting test - test_gpio_pin_configure_single_ended
Running test on port=gpio_0, pin=19
Pull Up / Pull Down pin bias is not supported
SKIP - test_gpio_pin_configure_single_ended
===================================================================
starting test - test_gpio_pin_set_get_raw
Running test on port=gpio_0, pin=19
PASS - test_gpio_pin_set_get_raw
===================================================================
starting test - test_gpio_pin_set_get
Running test on port=gpio_0, pin=19
PASS - test_gpio_pin_set_get
===================================================================
starting test - test_gpio_pin_set_get_active_high
Running test on port=gpio_0, pin=19
Step 1: Set logical, get logical and physical pin value
Step 2: Set physical, get logical and physical pin value
PASS - test_gpio_pin_set_get_active_high
===================================================================
starting test - test_gpio_pin_set_get_active_low
Running test on port=gpio_0, pin=19
Step 1: Set logical, get logical and physical pin value
Step 2: Set physical, get logical and physical pin value
PASS - test_gpio_pin_set_get_active_low
===================================================================
starting test - test_gpio_pin_toggle
Running test on port=gpio_0, pin=19
PASS - test_gpio_pin_toggle
===================================================================
starting test - test_gpio_port_set_masked_get_raw
Running test on port=gpio_0, pin=19
PASS - test_gpio_port_set_masked_get_raw
===================================================================
starting test - test_gpio_port_set_masked_get
Running test on port=gpio_0, pin=19
PASS - test_gpio_port_set_masked_get
===================================================================
starting test - test_gpio_port_set_masked_get_active_high
Running test on port=gpio_0, pin=19
Step 1: Set logical, get logical and physical port value
Step 2: Set physical, get logical and physical port value
PASS - test_gpio_port_set_masked_get_active_high
===================================================================
starting test - test_gpio_port_set_masked_get_active_low
Running test on port=gpio_0, pin=19
Step 1: Set logical, get logical and physical port value
Step 2: Set physical, get logical and physical port value
PASS - test_gpio_port_set_masked_get_active_low
===================================================================
starting test - test_gpio_port_set_bits_clear_bits_raw
Running test on port=gpio_0, pin=19
PASS - test_gpio_port_set_bits_clear_bits_raw
===================================================================
starting test - test_gpio_port_set_bits_clear_bits
Running test on port=gpio_0, pin=19
PASS - test_gpio_port_set_bits_clear_bits
===================================================================
starting test - test_gpio_port_set_clr_bits_raw
Running test on port=gpio_0, pin=19
PASS - test_gpio_port_set_clr_bits_raw
===================================================================
starting test - test_gpio_port_set_clr_bits
Running test on port=gpio_0, pin=19
PASS - test_gpio_port_set_clr_bits
===================================================================
starting test - test_gpio_port_toggle
Running test on port=gpio_0, pin=19
PASS - test_gpio_port_toggle
===================================================================
starting test - test_gpio_int_edge_rising
Running test on port=gpio_0, pin=19

    Assertion failed at ZEPHYR_BASE/tests/drivers/gpio/gpio_api_1pin/src/test_pin_interrupt.c:105: test_gpio_pin_interrupt_edge: (cb_count not equal to cb_count_expected)
Test point 0: Pin interrupt triggered invalid number of times on rising/to active edge
FAIL - test_gpio_int_edge_rising
===================================================================
starting test - test_gpio_int_edge_falling
Running test on port=gpio_0, pin=19

    Assertion failed at ZEPHYR_BASE/tests/drivers/gpio/gpio_api_1pin/src/test_pin_interrupt.c:113: test_gpio_pin_interrupt_edge: (cb_count not equal to cb_count_expected)
Test point 0: Pin interrupt triggered invalid number of times on falling/to inactive edge
FAIL - test_gpio_int_edge_falling
===================================================================
starting test - test_gpio_int_edge_both
Running test on port=gpio_0, pin=19

    Assertion failed at ZEPHYR_BASE/tests/drivers/gpio/gpio_api_1pin/src/test_pin_interrupt.c:105: test_gpio_pin_interrupt_edge: (cb_count not equal to cb_count_expected)
Test point 0: Pin interrupt triggered invalid number of times on rising/to active edge
FAIL - test_gpio_int_edge_both
===================================================================
starting test - test_gpio_int_edge_to_active
Step 1: Configure pin as active high
Running test on port=gpio_0, pin=19

    Assertion failed at ZEPHYR_BASE/tests/drivers/gpio/gpio_api_1pin/src/test_pin_interrupt.c:105: test_gpio_pin_interrupt_edge: (cb_count not equal to cb_count_expected)
Test point 0: Pin interrupt triggered invalid number of times on rising/to active edge
FAIL - test_gpio_int_edge_to_active
===================================================================
starting test - test_gpio_int_edge_to_inactive
Step 1: Configure pin as active high
Running test on port=gpio_0, pin=19

    Assertion failed at ZEPHYR_BASE/tests/drivers/gpio/gpio_api_1pin/src/test_pin_interrupt.c:113: test_gpio_pin_interrupt_edge: (cb_count not equal to cb_count_expected)
Test point 0: Pin interrupt triggered invalid number of times on falling/to inactive edge
FAIL - test_gpio_int_edge_to_inactive
===================================================================
starting test - test_gpio_int_level_high
Running test on port=gpio_0, pin=19

    Assertion failed at ZEPHYR_BASE/tests/drivers/gpio/gpio_api_1pin/src/test_pin_interrupt.c:186: test_gpio_pin_interrupt_level: (cb_count not equal to cb_count_expected)
Test point 0: Pin interrupt triggered invalid number of times on level 1
FAIL - test_gpio_int_level_high
===================================================================
starting test - test_gpio_int_level_low
Running test on port=gpio_0, pin=19

    Assertion failed at ZEPHYR_BASE/tests/drivers/gpio/gpio_api_1pin/src/test_pin_interrupt.c:186: test_gpio_pin_interrupt_level: (cb_count not equal to cb_count_expected)
Test point 0: Pin interrupt triggered invalid number of times on level 0
FAIL - test_gpio_int_level_low
===================================================================
starting test - test_gpio_int_level_active
Step 1: Configure pin as active high
Running test on port=gpio_0, pin=19

    Assertion failed at ZEPHYR_BASE/tests/drivers/gpio/gpio_api_1pin/src/test_pin_interrupt.c:186: test_gpio_pin_interrupt_level: (cb_count not equal to cb_count_expected)
Test point 0: Pin interrupt triggered invalid number of times on level 1
FAIL - test_gpio_int_level_active
===================================================================
starting test - test_gpio_int_level_inactive
Step 1: Configure pin as active high
Running test on port=gpio_0, pin=19

    Assertion failed at ZEPHYR_BASE/tests/drivers/gpio/gpio_api_1pin/src/test_pin_interrupt.c:186: test_gpio_pin_interrupt_level: (cb_count not equal to cb_count_expected)
Test point 0: Pin interrupt triggered invalid number of times on level 0
FAIL - test_gpio_int_level_inactive
===================================================================
starting test - test_gpio_pin_toggle_visual
Running test on port=gpio_0, pin=19
LED ON
LED OFF
LED ON
LED OFF
PASS - test_gpio_pin_toggle_visual
===================================================================
Test suite gpio_api_1pin_test failed.
===================================================================
PROJECT EXECUTION FAILED

@nategraff-sifive
Copy link
Contributor Author

One other thing I noticed while running the test is that the LED polarity is inverted from what the test thinks. The LED0 GPIO pin is on the cathode of the LED, so when the GPIO is driven low the LED is turned on. During test_gpio_pin_toggle_visual, the LED is ON when the test says it's OFF.

Schematic for the HiFive1 Rev B LEDs (Go to page 3)

What are the odds this is the cause of the interrupt failures in the test?

@mnkp
Copy link
Member

mnkp commented Oct 14, 2019

According to the testcase log the interrupts are not triggered at all. Since test for GPIO_INT_EDGE_BOTH also fails, so it's not polarity related. Does the button sample samples/basic/button/ work?

The trace messages printed by the testcase are not very good at the moment since they don't print actual and expected values. I didn't do it explicitly in the testcase hoping that this issue will be solved globally. The assert macros should print actual and expected values automatically, always. Unfortunately, that's not so easy to implement.

@mnkp
Copy link
Member

mnkp commented Oct 14, 2019

To fix the LED polarity you need to add GPIO_ACTIVE_LOW to the board dts file boards/riscv/hifive1_revb/hifive1_revb.dts. Look e.g. at boards/arm/sam_e70_xplained/sam_e70_xplained.dts as an example.

@mnkp
Copy link
Member

mnkp commented Oct 14, 2019

There is one more issue I overlooked, in the gpio_sifive_irq_handler function the interrupt status has to be cleared first, before gpio_fire_callbacks function is called. Otherwise a second edge interrupt that happens when the callback is being executed will be missed.

@mnkp mnkp self-requested a review October 14, 2019 22:18
@mnkp
Copy link
Member

mnkp commented Oct 14, 2019

I will re-review the code when the pending issues are solved.

@carlescufi
Copy link
Member

@nategraff-sifive could you address the remaining issues please?

@nategraff-sifive
Copy link
Contributor Author

@carlescufi I'm working on it!

@carlescufi
Copy link
Member

@carlescufi I'm working on it!

Thanks Nate.

@mnkp
Copy link
Member

mnkp commented Oct 15, 2019

It would be probably best if you ask a question on #devicetree channel in Slack.

Just to double check, you could run a quick test and modify IRQ_CONNECT macro in gpio_sifive.c to something like.

-IRQ_CONNECT(DT_INST_0_SIFIVE_GPIO0_IRQ_##n,    \
+IRQ_CONNECT((8 + n),   \

and verify that after the modification the interrupts are firing correctly.

@nategraff-sifive
Copy link
Contributor Author

The devicetree channel is a good idea, I'll ask there.

So the PLIC IRQ numbers are actually offset by 12, so the change to IRQ_CONNECT is

-IRQ_CONNECT(DT_INST_0_SIFIVE_GPIO0_IRQ_##n,    \
+IRQ_CONNECT((12 + 8 + n),   \

...which doesn't work, even though the generated _sw_isr_table has the SiFive GPIO irq_handlers at the right offsets 20-51.

@nategraff-sifive
Copy link
Contributor Author

The weird IRQ numbers are said to be a result of multi-level IRQ handling, so the issue still lies elsewhere.

@nategraff-sifive
Copy link
Contributor Author

nategraff-sifive commented Oct 15, 2019

I found it!

gpio_sifive_enable_callback calls irq_enable(cfg->gpio_irq_base + pin);, which no longer works because of the multi-level IRQ numbers.

Edit: lots of stuff in the driver suffers from the assumption that gpio_irq_base does what it used to. Anyway, I have some work to do. :)

@mnkp
Copy link
Member

mnkp commented Oct 15, 2019

Nice! Good job! :)

But it reminds me that there is one more thing to fix. The gpio_sifive_pin_interrupt_configure function needs to enable / disable interrupt line as instructed by the mode parameter. So it needs to call irq_enable / irq_disable. The gpio_sifive_enable_callback / gpio_sifive_disable_callback functions will be deprecated.

@nategraff-sifive
Copy link
Contributor Author

Progress update:

I just pushed a new commit with my work so far to update the driver for multi-level interrupts.

It still fails all of the interrupt tests in tests/drivers/gpio/gpio_api_1pin, except it gets to step 2 on test_gpio_int_edge_to_active

===================================================================
starting test - test_gpio_int_edge_to_active
Step 1: Configure pin as active high
Running test on port=gpio_0, pin=19
Step 2: Configure pin as active low
Running test on port=gpio_0, pin=19

    Assertion failed at ZEPHYR_BASE/tests/drivers/gpio/gpio_api_1pin/src/test_pin_interrupt.c:105: test_gpio_pin_interrupt_edge: (cb_count not equal to cb_count_expected)
Test point 0: Pin interrupt triggered invalid number of times on rising/to active edge
FAIL - test_gpio_int_edge_to_active

@carlescufi
Copy link
Member

@nategraff-sifive could you fix the CI issues and reply to @mnkp 's comment above about the interrupt handling?

@nategraff-sifive
Copy link
Contributor Author

Clearing the pending register before enabling the GPIO interrupt didn't fix it. I'm still digging around. The problem is definitely spurious interrupts, I can confirm that the callbacks are firing too much, not too little.

@galak
Copy link
Contributor

galak commented Oct 25, 2019

We rebased the topic-gpio branch against master, so this PR needs to be rebased on the updated topic-gpio branch.

@nategraff-sifive
Copy link
Contributor Author

Rebased on topic-gpio, still getting some spurious interrupts, still digging.

@galak
Copy link
Contributor

galak commented Oct 29, 2019

Rebased on topic-gpio, still getting some spurious interrupts, still digging.

Any luck? This is one of the few remaining GPIO drivers that needs to get converted. Thanks.

@nategraff-sifive
Copy link
Contributor Author

@galak I have to admit I'm pretty stuck. Is it worth just disabling interrupts for this driver (which I'm pretty sure were already broken) to get the API change merged?

@pabigot
Copy link
Contributor

pabigot commented Oct 30, 2019

I think that'd be appropriate. We can continue to work on it after everything's merged to master.

Update the Sifive GPIO driver for new API

Signed-off-by: Nathaniel Graff <[email protected]>
The interrupt functionality of this driver is incomplete,
but for the sake of not slowing down the GPIO API refactor,
I'm just returning -ENOTSUP until we can track down the issue.

Signed-off-by: Nathaniel Graff <[email protected]>
@nategraff-sifive
Copy link
Contributor Author

@galak, @pabigot, @mnkp tests/drivers/gpio/gpio_api_1pin passes now with the interrupt tests skipped

@pabigot
Copy link
Contributor

pabigot commented Oct 31, 2019

@nategraff-sifive Have you tried tests/drivers/gpio/gpio_basic_api (the 2-pin test)?

Copy link
Member

@mnkp mnkp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with a minor comment.

}

/* Given gpio_irq_base and the pin number, return the IRQ number for the pin */
static inline unsigned int gpio_sifive_pin_irq(unsigned int base_irq, int pin)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general we use static inline only for the functions placed in a header. If the function is internal to the source file it's usually better to leave the decision weather to inline a function (or not) to the compiler. If the function is small, used once the compiler will inline a function even without the inline keyword.

#define DEV_GPIO_DATA(dev) \
((struct gpio_sifive_data *)(dev)->driver_data)

/* _irq_level and _level2_irq are copied from
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's prefix this paragraph with TODO:.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added

@galak galak merged commit 1097995 into zephyrproject-rtos:topic-gpio Nov 4, 2019
@galak
Copy link
Contributor

galak commented Nov 4, 2019

Going ahead and merging this and will open some issues for the TODO items.

@nategraff-sifive nategraff-sifive deleted the sifive-gpio-api-update branch November 4, 2019 17:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants