Closed rroulleau closed 2 years ago
Hi,
I think interrupts = <128>; is better than interrupts = <128 4>; in the device tree. The PolarFire SoC interrupts in device-tree just take the interrupt itself, no details about level - they are all level.
I don't have docs to hand, but I suspect that you need to handle the interrupt on its own register map. I mean a combination of status and mask registers on the coreGPIO IP (working at an offset of a virt address based on 0x46000000).
I suspect the first interrupt is not cleared and remains level high.
Hello, Thanks for your feedback. I have only managed to get the interrupt thing to work by sending a "pulse" type interrupt (a clock width - edge trigger) to the MSS_INT_F2M. But in some use case we could miss out some events and I was therefore trying to use the high level-sensitive interrupt but then I am not able to clear my interrupt in the UIO driver, even though I am clearing the source interrupt signal to 0. Do you have a pseudo code that would explain the sequence to acknowledge and clear the UIO driver correctly? In my software wait_irq() function I am doing the following and to be true I retreived this code from forums but I have no spec that explains it:
fd = open("/dev/uiox", O_RDWR | O_SYNC);
wait_irq(){
write(fd,&reenable,...); // to activate the UIO ?
...
struct pollfd fds = (fd, POLLIN);
stat = poll (fds, 1, timeout); // wait for an event
if (stat>0){
if (fds.revents & POLLIN){
read(fd, &reenable, ...); // acknowledge the event - reenable value = total number of events
write(fd, &reenable,...); // reenable the UIO - is it Ok to do so here?
}
}
}
This above code works "ok" with edge trigger interrupt (pulse) but NOT when I am using level-sensitive interrupt.
Hi, just to give you some additional info you may find it useful. The interrupt controller works only on level-high sensitive interrupt triggering. So I guess the issue is somewhere else.
Hi, can you be more explicit on what you call the "interrupt controller". Is it the PLIC within the soc-polarfire?
Yes, I refer to the PLIC. The acknowledgement is done at low level by the irqchip driver. The UIO generic driver disable irqs before handing off control to user who is in charge to re-enable it. There is a CAN example here if u find it useful: https://github.com/polarfire-soc/polarfire-soc-linux-examples/blob/master/can/uio-can-example.c
@eppidei Thanks for the link. Now looking in the DTS file, the CAN periph is declared like this:
canx: can@2010**** {
compatible ="microchip, mpfs-can-uio";
...
interrupt-parent = <&plic>;
interrupts = <PLIC_INT_CANx>;
status = "disabled";
}
So I conclude in the CAN example the interrupt is handle by a "mpfs-can-uio" driver when in my case I use the generic-uio (see the top of the thread).
compatible = "generic-uio";
Could it be an issue on the generic-uio driver on the linux distrib of the MPFS ?
If I look in the source code in the linux build. When I use generic-uio in my dts it is using the uio_pdrv_genirq driver/module. within this driver the irq handler function in uio_pdrv_genirq.c:
static irqreturn_t uio_pdrv_genirq_handler(int irq, struct uio_info *dev_info)
{
struct uio_pdrv_genirq_platdata *priv = dev_info->priv;
/* Just disable the interrupt in the interrupt controller, and
* remember the state so we can allow user space to enable it later.
*/
spin_lock(&priv->lock);
if (!__test_and_set_bit(UIO_IRQ_DISABLED, &priv->flags))
disable_irq_nosync(irq);
spin_unlock(&priv->lock);
return IRQ_HANDLED;
}
In the CAN exemple my understanding microchip wrote their own specific driver
compatible ="microchip, mpfs-can-uio";
and in the uio_microchip-can.c the handler is doing the following:
static irqreturn_t mss_can_handler(int irq, struct uio_info *info)
{
struct uio_mss_can_dev *dev_info = info->priv;
int val;
void __iomem *base = dev_info->mss_can_io_vaddr + dev_info->pintc_base;
void __iomem *intren_reg = base + CAN_INT_ENABLE;
void __iomem *intrstat_reg = base + CAN_INT_STATUS;
val = ioread32(intren_reg);
/* Is interrupt enabled and active ? */
if (!(val & 0xffff) && (ioread32(intrstat_reg) & 0xffff))
return IRQ_NONE;
return IRQ_HANDLED;
}
In the case of the CAN irq handler it is referencing to *base=dev_info->mss_can_io_vaddr... This seems to be hardware specific to the MPFS and therefore not in the generic-uio driver. That make me think if I want to use the MSS interrupt form the Fabric I will have no option but to write my own IRQ handler like microchip did for the CAN, SPI, I2C, etc... I am not a linux guru, so any hint/clue is welcome :-) thanks.
yes, I think that would certainly be a reasonable way forward. You could start by copying the UIO CAN driver, including the Kconfig / Makefile in the same directory along with its device-tree stanza.
Alternatively, you could try using the generic-uio driver and doing those writes in userspace. There are examples in /opt/microchip that show you how to access hardware registers from userspace.
Hello,
I am trying to trigger an interrupt level high using the uio driver, I have written the dts entry as follow:
For the field interrupts 128 = interrupt ID and the 4 = active high level-sensitive. Connected to the MSS_INT_F2M in the fabric I used the coreGPIO IP (mapped at 0x46000000) from libero with interrupt port enable set and my Input interrupt type set to 'Level High'.
The first interrupt is catched ok but not the second or following interrupt
In the linux when doing
and the counter is stuck at 1 on CPU0
I am guessing I am not clearing/acknowledging the UIO driver correctly. Can someone help?