Skip to contentSkip to conversation

MPC5200 VIRQ question

DISCUSSION Gary Thomas 4 participants 9 messages Dec 4, 2008 – Dec 11, 2008

lore
Share & tools
lore
#0 lore raw

I have a MPC5200 based board which has an FPGA for external I/O, etc. This FPGA also funnels interrupts from the various external devices through to the CPU.

I've defined this structure in my DTS:

	fpga@f8000000 {
		device_type = "board-control";
		#address-cells = <1>;
		#size-cells = <1>;
		// Note: includes sub-devices like CAN, A/D, etc
		reg = <0xf8000000 0x100000>;

		fpga_ic: fpga_ic@f8000000 {
			device_type = "fpga-int-ctlr";
			interrupt-controller;
			#address-cells = <0>;
			#interrupt-cells = <2>;
			interrupts = <2 26 3>; // IRQ2
			interrupt-parent = <&mpc5200_pic>;
		};
		can@f8010000 {
			compatible = "am,can";
			device_type = "can";
			interrupts = <0 0>;
			interrupt_parent = <&fpga_ic>;
			reg = <0xf8010000 0x200>;
		};
	};

Of course, there will be more devices and interrupts later on, this is just the first of many.

Now the questions:
* How do I choose the VIRQ range supported by my FPGA?
I'm interested in this in particular for the MPC5200, but also for other chips (I have many such board configurations).
* How do I pass this information along to my drivers? I would think that the interrupts value for the can interface above would use a [logical] IRQ (an offset from the base VIRQ), so how does the driver get the actual number (VIRQ+offset) when probing the tree?
* I know how to define the interrupt controller using irq_alloc_host() (once I have the VIRQ range) but it's not clear to me where to stick this initialization when bringing up my platform.

Thanks for any pointers/ideas

n.b. I've read all the arguments about not using "device_type" and this will be resolved. At the moment, I'm basing my code on a slightly older kernel codebase (2.6.26), so those entries remain.

Signature · 4 lines
------------------------------------------------------------
Gary Thomas                 |  Consulting for the
MLB Associates              |    Embedded world
------------------------------------------------------------
#1 lore raw
Quoted 30 lines · Gary Thomas

I have a MPC5200 based board which has an FPGA for external I/O, etc. This FPGA also funnels interrupts from the various external devices through to the CPU.

I've defined this structure in my DTS:

	fpga@f8000000 {
		device_type = "board-control";
		#address-cells = <1>;
		#size-cells = <1>;
		// Note: includes sub-devices like CAN, A/D, etc
		reg = <0xf8000000 0x100000>;

		fpga_ic: fpga_ic@f8000000 {
			device_type = "fpga-int-ctlr";
			interrupt-controller;
			#address-cells = <0>;
			#interrupt-cells = <2>;
			interrupts = <2 26 3>; // IRQ2
			interrupt-parent = <&mpc5200_pic>;
		};
		can@f8010000 {
			compatible = "am,can";
			device_type = "can";
			interrupts = <0 0>;
			interrupt_parent = <&fpga_ic>;
			reg = <0xf8010000 0x200>;
		};
	};
Quoted 2 lines

Of course, there will be more devices and interrupts later on, this is just the first of many.

Nothing obviously wrong so far other than you should use "compatible" properties to identify your devices, including (especially) the fpga & its pic, and maybe use slightly more verbose entries than "am,can" :-)

Quoted 2 lines

Now the questions:
* How do I choose the VIRQ range supported by my FPGA?

You don't. Linux virtual numbers are allocated sparsely and on the fly.

You basically create an irq_host data structure, specifying what kind of reverse mapping you want (typically in your case I suspect linear since your HW interrupt space won't be huge), provide the appropriate callbacks, all I can suggest here is to look at what others do.

Quoted 7 lines

I'm interested in this in particular for the MPC5200, but also for other chips (I have many such board configurations).
* How do I pass this information along to my drivers? I would think that the interrupts value for the can interface above would use a [logical] IRQ (an offset from the base VIRQ), so how does the driver get the actual number (VIRQ+offset) when probing the tree?

Depends on the driver. But if they use an OF node, they can do of_irq_parse_and_map() or something like that. It will walk the tree, find the controller, map it to an irq_host (via the callbacks your provided), allocate a virq if not done yet, establish a virq->hw mapping etc... all for you, and return the virq.

If they are PCI devices, the PCI code does it all for you.

Quoted 3 lines

* I know how to define the interrupt controller using irq_alloc_host() (once I have the VIRQ range) but it's not clear to me where to stick this initialization when bringing up my platform.

You don't provide a virq range to irq_alloc_host. You provide a type of reverse mapping (depending on how sparse your HW numbering scheme is) and for a linear map, how many entries it contains (which is the size of your -physical- range).

virqs are allocated on the fly.

Quoted 7 lines

Thanks for any pointers/ideas

n.b. I've read all the arguments about not using "device_type" and this will be resolved. At the moment, I'm basing my code on a slightly older kernel codebase (2.6.26), so those entries remain.

Cheers,
Ben.

#2 lore raw
Quoted 14 lines · Benjamin Herrenschmidt
Quoted 13 lines · Gary Thomas

I have a MPC5200 based board which has an FPGA for external I/O, etc. This FPGA also funnels interrupts from the various external devices through to the CPU.

I've defined this structure in my DTS:

	fpga@f8000000 {
		device_type = "board-control";
		#address-cells = <1>;
		#size-cells = <1>;
		// Note: includes sub-devices like CAN, A/D, etc
		reg = <0xf8000000 0x100000>;
Quoted 6 lines
Quoted 6 lines
		fpga_ic: fpga_ic@f8000000 {
			device_type = "fpga-int-ctlr";
			interrupt-controller;
			#address-cells = <0>;
			#interrupt-cells = <2>;
			interrupts = <2 26 3>; // IRQ2

BTW, this is wrong! Are the IRQ mappings on the MPC5200 documented somewhere? I've looked and looked without much joy. Only by experimentation did I discover that "<1 2 3>" corresponds to IRQ2.

Quoted 11 lines
Quoted 11 lines
			interrupt-parent = <&mpc5200_pic>;
		};
		can@f8010000 {
			compatible = "am,can";
			device_type = "can";
			interrupts = <0 0>;
			interrupt_parent = <&fpga_ic>;
			reg = <0xf8010000 0x200>;
		};
	};
Quoted 6 lines
Quoted 2 lines

Of course, there will be more devices and interrupts later on, this is just the first of many.

Nothing obviously wrong so far other than you should use "compatible" properties to identify your devices, including (especially) the fpga & its pic, and maybe use slightly more verbose entries than "am,can" :-)

Fair enough, but these are 100% internal devices. I'm only using the OF tree for them as that seems to be the accepted method (IMO, it's a bit wrong-headed, but that's another discussion...)

Quoted 19 lines
Quoted 3 lines

Now the questions:
* How do I choose the VIRQ range supported by my FPGA?

You don't. Linux virtual numbers are allocated sparsely and on the fly.

You basically create an irq_host data structure, specifying what kind of reverse mapping you want (typically in your case I suspect linear since your HW interrupt space won't be huge), provide the appropriate callbacks, all I can suggest here is to look at what others do.

Quoted 7 lines

I'm interested in this in particular for the MPC5200, but also for other chips (I have many such board configurations).
* How do I pass this information along to my drivers? I would think that the interrupts value for the can interface above would use a [logical] IRQ (an offset from the base VIRQ), so how does the driver get the actual number (VIRQ+offset) when probing the tree?

Quoted 6 lines

Depends on the driver. But if they use an OF node, they can do of_irq_parse_and_map() or something like that. It will walk the tree, find the controller, map it to an irq_host (via the callbacks your provided), allocate a virq if not done yet, establish a virq->hw mapping etc... all for you, and return the virq.

This part is still a bit fuzzy. Where/how does my interrupt controller driver get this VIRQ? Here's how I created my controller:

    fpga_can_irq = irq_of_parse_and_map(fpga_ic, 0);
    D_printk(("%s: fpga_irq = %d\n", __func__, (u32) fpga_can_irq));
    if (fpga_can_irq == 0) {
        printk(KERN_ERR "%s: Can't find FPGA Interrupt Controller IRQ", __func__);
        return -EINVAL;
    }
    if (request_irq(fpga_can_irq, &fpga_irq_cascade, 0, "FPGA CAN", 0)) {
        printk(KERN_ERR "%s: Can't attach to FPGA Interrupt Controller IRQ", __func__);
        return -EINVAL;
    }
    fpga_irq_host = irq_alloc_host(of_node_get(fpga_node), IRQ_HOST_MAP_LINEAR,
                                           16, &fpga_irq_host_ops, -1);

When I try to get the interrupt number for the CAN sub-device, I always get zero :-(

    for_each_compatible_node(np, "can", "am,can") {
        memset(r, 0, sizeof(r));
        rc = of_address_to_resource(np, 0, &r[0]);
        if (rc) {
            return rc;
        }
        rc = of_irq_to_resource(np, 0, &r[1]);
        if (rc) {
            return rc;
        }
    }

Note: the of_address_to_resource() call works fine, but the of_irq_to_resource() fails - always returns 0. Any ideas what I'm doing wrong?

Quoted 1 line

If they are PCI devices, the PCI code does it all for you.

Sadly, 100% home grown, not PCI.

Quoted 5 lines
Quoted 4 lines

* I know how to define the interrupt controller using irq_alloc_host() (once I have the VIRQ range) but it's not clear to me where to stick this initialization when bringing up my platform.

Quoted 7 lines

You don't provide a virq range to irq_alloc_host. You provide a type of reverse mapping (depending on how sparse your HW numbering scheme is) and for a linear map, how many entries it contains (which is the size of your -physical- range).

virqs are allocated on the fly.

Once I get the above call to work, I'll have to figure out how to get at the VIRQ (so my cascade handler can signal the right interrupt)

n.b. I only ask these questions after much investigation and experimentation; I'm not asking you to do my job for me, just help through the maze of twisty little passages!

Signature · 4 lines
------------------------------------------------------------
Gary Thomas                 |  Consulting for the
MLB Associates              |    Embedded world
------------------------------------------------------------
#3 lore raw
Quoted 15 lines
Quoted 8 lines
Quoted 8 lines
	fpga@f8000000 {
		device_type = "board-control";
		#address-cells = <1>;
		#size-cells = <1>;
		// Note: includes sub-devices like CAN, A/D, etc
		reg = <0xf8000000 0x100000>;
Quoted 6 lines
Quoted 6 lines
		fpga_ic: fpga_ic@f8000000 {
			device_type = "fpga-int-ctlr";
			interrupt-controller;
			#address-cells = <0>;
			#interrupt-cells = <2>;
			interrupts = <2 26 3>; // IRQ2
Quoted 3 lines

BTW, this is wrong! Are the IRQ mappings on the MPC5200 documented somewhere? I've looked and looked without much joy. Only by experimentation did I discover that "<1 2 3>" corresponds to IRQ2.

The content of the interrupts property depends on a given PIC binding. I don't know if Grant or Sylvain published their binding but in the meantime, you can look at the code that decodes that stuff :-) It's in arch/powerpc/platforms/mpc52xx_pic.c : mpc52xx_irqhost_xlate().

My understanding from a quick look at the code is that the first number (called L1) is the "category" (0 = CRIT, 1 = MAIN, 2 = PERP, ...) since I think inside the 52xx, interrupts are divided into such categories coming from different sources. The second number would thus be the number within that category.

It looks to me that the external IRQs 1..3 are of type "main" (1) and number 1 to 3. That would give you a binding of <1 <n> <s>> where n is 1..3 and s is the sense code

For mpc52xx, the sense code is 0=high level,1=rising edge,2=falling edge and 3=low level (still from looking at the code).

The mpc52xx irq binding is indeed more complicated than most :-)

Quoted 31 lines

This part is still a bit fuzzy. Where/how does my interrupt controller driver get this VIRQ? Here's how I created my controller:

    fpga_can_irq = irq_of_parse_and_map(fpga_ic, 0);
    D_printk(("%s: fpga_irq = %d\n", __func__, (u32) fpga_can_irq));
    if (fpga_can_irq == 0) {
        printk(KERN_ERR "%s: Can't find FPGA Interrupt Controller IRQ", __func__);
        return -EINVAL;
    }
    if (request_irq(fpga_can_irq, &fpga_irq_cascade, 0, "FPGA CAN", 0)) {
        printk(KERN_ERR "%s: Can't attach to FPGA Interrupt Controller IRQ", __func__);
        return -EINVAL;
    }
    fpga_irq_host = irq_alloc_host(of_node_get(fpga_node), IRQ_HOST_MAP_LINEAR,
                                           16, &fpga_irq_host_ops, -1);

When I try to get the interrupt number for the CAN sub-device, I always get zero :-(

    for_each_compatible_node(np, "can", "am,can") {
        memset(r, 0, sizeof(r));
        rc = of_address_to_resource(np, 0, &r[0]);
        if (rc) {
            return rc;
        }
        rc = of_irq_to_resource(np, 0, &r[1]);
        if (rc) {
            return rc;
        }
    }
Quoted 3 lines

Note: the of_address_to_resource() call works fine, but the of_irq_to_resource() fails - always returns 0. Any ideas what I'm doing wrong?

We should trace what your fpga_irq_host_ops are doing.

Add some debug to irq_of_parse_and_map() first. This function first calls of_irq_map_one() which will walk the device-tree to match your interrupt to a controller node (going through all the interrupt-map's on the way if any, but you don't have any) and should return with oirq.controller being the device-node of your fpga_ic. If not, then we missed a bogon in the device-tree.

At this stage, if it hasn't failed, it will call
irq_create_of_mapping().

That function will then try to find an irq_host matching the device node passed in. This is achieved by calling the ->match() callback all the irq_host's in the system. So verify that your fpga irq host "match" function properly checks that the device-tree node it's passed indeed matches the fpga_ic and returns 1 if it does.

It will then call your host xlate() callback to translate the device-tree specifier (in your case <0 0> into a hw interrupt number. I don't know why you are using 2 cells for your interrupts, you want to encode a sense code ? If not, I suggest using only one cell and make it the local HW interrupt number in your FPGA.

At this point, all your xlate has to do is to return inspec[0] in hwirq and then return 0. Again, look at what mpc52xx_pic.c or mpic.c do here.

The code then establishes the virq -> hwirq mapping with irq_create_mapping() which will allocate a virq for you.

Cheers,
Ben.

#4 lore raw
Quoted 28 lines · Benjamin Herrenschmidt
Quoted 13 lines
Quoted 7 lines
Quoted 7 lines
	fpga@f8000000 {
		device_type = "board-control";
		#address-cells = <1>;
		#size-cells = <1>;
		// Note: includes sub-devices like CAN, A/D, etc
		reg = <0xf8000000 0x100000>;
Quoted 6 lines
Quoted 6 lines
		fpga_ic: fpga_ic@f8000000 {
			device_type = "fpga-int-ctlr";
			interrupt-controller;
			#address-cells = <0>;
			#interrupt-cells = <2>;
			interrupts = <2 26 3>; // IRQ2
Quoted 3 lines

BTW, this is wrong! Are the IRQ mappings on the MPC5200 documented somewhere? I've looked and looked without much joy. Only by experimentation did I discover that "<1 2 3>" corresponds to IRQ2.

The content of the interrupts property depends on a given PIC binding. I don't know if Grant or Sylvain published their binding but in the meantime, you can look at the code that decodes that stuff :-) It's in arch/powerpc/platforms/mpc52xx_pic.c : mpc52xx_irqhost_xlate().

My understanding from a quick look at the code is that the first number (called L1) is the "category" (0 = CRIT, 1 = MAIN, 2 = PERP, ...) since I think inside the 52xx, interrupts are divided into such categories coming from different sources. The second number would thus be the number within that category.

Quoted 8 lines

It looks to me that the external IRQs 1..3 are of type "main" (1) and number 1 to 3. That would give you a binding of <1 <n> <s>> where n is 1..3 and s is the sense code

For mpc52xx, the sense code is 0=high level,1=rising edge,2=falling edge and 3=low level (still from looking at the code).

The mpc52xx irq binding is indeed more complicated than most :-)

Thanks for the elucidation; I would think it useful to have this spelled out somewhere - without having to dig through the [truly] awful MPC5200 manual! A simple bit of documentation can go a long way... e.g.

IRQ1 = <1 1 n>
IRQ2 = <1 2 n>

    ...
  CAN0 = <2 11 0>
    ... etc
Quoted 44 lines
Quoted 31 lines

This part is still a bit fuzzy. Where/how does my interrupt controller driver get this VIRQ? Here's how I created my controller:

    fpga_can_irq = irq_of_parse_and_map(fpga_ic, 0);
    D_printk(("%s: fpga_irq = %d\n", __func__, (u32) fpga_can_irq));
    if (fpga_can_irq == 0) {
        printk(KERN_ERR "%s: Can't find FPGA Interrupt Controller IRQ", __func__);
        return -EINVAL;
    }
    if (request_irq(fpga_can_irq, &fpga_irq_cascade, 0, "FPGA CAN", 0)) {
        printk(KERN_ERR "%s: Can't attach to FPGA Interrupt Controller IRQ", __func__);
        return -EINVAL;
    }
    fpga_irq_host = irq_alloc_host(of_node_get(fpga_node), IRQ_HOST_MAP_LINEAR,
                                           16, &fpga_irq_host_ops, -1);

When I try to get the interrupt number for the CAN sub-device, I always get zero :-(

    for_each_compatible_node(np, "can", "am,can") {
        memset(r, 0, sizeof(r));
        rc = of_address_to_resource(np, 0, &r[0]);
        if (rc) {
            return rc;
        }
        rc = of_irq_to_resource(np, 0, &r[1]);
        if (rc) {
            return rc;
        }
    }
Quoted 3 lines

Note: the of_address_to_resource() call works fine, but the of_irq_to_resource() fails - always returns 0. Any ideas what I'm doing wrong?

We should trace what your fpga_irq_host_ops are doing.

Add some debug to irq_of_parse_and_map() first. This function first calls of_irq_map_one() which will walk the device-tree to match your interrupt to a controller node (going through all the interrupt-map's on the way if any, but you don't have any) and should return with oirq.controller being the device-node of your fpga_ic. If not, then we missed a bogon in the device-tree.

Quoted 3 lines

At this stage, if it hasn't failed, it will call
irq_create_of_mapping().

I traced through this and this is where it was failing.

unsigned int irq_of_parse_and_map(struct device_node *dev, int index)

{
	struct of_irq oirq;

	if (of_irq_map_one(dev, index, &oirq))
		return NO_IRQ;

	return irq_create_of_mapping(oirq.controller, oirq.specifier,
				     oirq.size);
}

Notice that of_irq_map_one() can fail for a myriad of reasons - all quiet (without debugging on). This function simply masks those into "sorry..."

After a lot of looking I found this in mt DTS:

		can@f8010000 {
			compatible = "am,can";
			device_type = "can";
			interrupts = <0>;
			cell-index = <0>;
			interrupt_parent = <&fpga_ic>;
			reg = <0xf8010000 0x200>;
		};

See the bug? Truly not obvious, is it? and the fact that 'irq_of_parse_and_map()' just tossed a "sorry == NO_IRQ" didn't help find it.

This line:

			interrupt_parent = <&fpga_ic>;
should read:
			interrupt-parent = <&fpga_ic>;

I fixed that and got the rest figured out.

Thanks for the help.

Signature · 4 lines
------------------------------------------------------------
Gary Thomas                 |  Consulting for the
MLB Associates              |    Embedded world
------------------------------------------------------------
#5 lore raw
Quoted 3 lines · Gary Thomas

Notice that of_irq_map_one() can fail for a myriad of reasons - all quiet (without debugging on). This function simply masks those into "sorry..."

Right, it's not verbose on failure for various reasons. Most failures because something went wrong -before- the failure. IE. Your missing interrupt parent would make it go to the parent etc... and it would fail later on for a totally different reason than the original missing interrupt parent.

Also, there's a number of older machines out there with crap device-trees on which we know it will fail. The PCI code has a fallback mechanism for them.

However, there's pretty extensive debug output that you can enable explicitely in that file.

Cheers,
Ben.

#6 lore raw
In reply to Gary Thomas
Quoted 5 lines · Gary Thomas
Quoted 4 lines · Benjamin Herrenschmidt
Quoted 3 lines · Gary Thomas

I have a MPC5200 based board which has an FPGA for external I/O, etc. This FPGA also funnels interrupts from the various external devices through to the CPU.

This thread may give you some clues.
http://www.mail-archive.com/[email protected]/msg24077.html

The code from that thread was never finished and may not be correct.

Quoted 139 lines
Quoted 10 lines
Quoted 10 lines

I've defined this structure in my DTS:

     fpga@f8000000 {
             device_type = "board-control";
             #address-cells = <1>;
             #size-cells = <1>;
             // Note: includes sub-devices like CAN, A/D, etc
             reg = <0xf8000000 0x100000>;
Quoted 6 lines
Quoted 6 lines
             fpga_ic: fpga_ic@f8000000 {
                     device_type = "fpga-int-ctlr";
                     interrupt-controller;
                     #address-cells = <0>;
                     #interrupt-cells = <2>;
                     interrupts = <2 26 3>; // IRQ2

BTW, this is wrong! Are the IRQ mappings on the MPC5200 documented somewhere? I've looked and looked without much joy. Only by experimentation did I discover that "<1 2 3>" corresponds to IRQ2.

Quoted 11 lines
Quoted 11 lines
                     interrupt-parent = <&mpc5200_pic>;
             };
             can@f8010000 {
                     compatible = "am,can";
                     device_type = "can";
                     interrupts = <0 0>;
                     interrupt_parent = <&fpga_ic>;
                     reg = <0xf8010000 0x200>;
             };
     };
Quoted 6 lines
Quoted 2 lines

Of course, there will be more devices and interrupts later on, this is just the first of many.

Nothing obviously wrong so far other than you should use "compatible" properties to identify your devices, including (especially) the fpga & its pic, and maybe use slightly more verbose entries than "am,can" :-)

Fair enough, but these are 100% internal devices. I'm only using the OF tree for them as that seems to be the accepted method (IMO, it's a bit wrong-headed, but that's another discussion...)

Quoted 19 lines
Quoted 3 lines

Now the questions:
* How do I choose the VIRQ range supported by my FPGA?

You don't. Linux virtual numbers are allocated sparsely and on the fly.

You basically create an irq_host data structure, specifying what kind of reverse mapping you want (typically in your case I suspect linear since your HW interrupt space won't be huge), provide the appropriate callbacks, all I can suggest here is to look at what others do.

Quoted 7 lines

I'm interested in this in particular for the MPC5200, but also for other chips (I have many such board configurations).
* How do I pass this information along to my drivers? I would think that the interrupts value for the can interface above would use a [logical] IRQ (an offset from the base VIRQ), so how does the driver get the actual number (VIRQ+offset) when probing the tree?

Quoted 6 lines

Depends on the driver. But if they use an OF node, they can do of_irq_parse_and_map() or something like that. It will walk the tree, find the controller, map it to an irq_host (via the callbacks your provided), allocate a virq if not done yet, establish a virq->hw mapping etc... all for you, and return the virq.

This part is still a bit fuzzy. Where/how does my interrupt controller driver get this VIRQ? Here's how I created my controller:

   fpga_can_irq = irq_of_parse_and_map(fpga_ic, 0);
   D_printk(("%s: fpga_irq = %d\n", __func__, (u32) fpga_can_irq));
   if (fpga_can_irq == 0) {
       printk(KERN_ERR "%s: Can't find FPGA Interrupt Controller IRQ", __func__);
       return -EINVAL;
   }
   if (request_irq(fpga_can_irq, &fpga_irq_cascade, 0, "FPGA CAN", 0)) {
       printk(KERN_ERR "%s: Can't attach to FPGA Interrupt Controller IRQ", __func__);
       return -EINVAL;
   }
   fpga_irq_host = irq_alloc_host(of_node_get(fpga_node), IRQ_HOST_MAP_LINEAR,
                                          16, &fpga_irq_host_ops, -1);

When I try to get the interrupt number for the CAN sub-device, I always get zero :-(

   for_each_compatible_node(np, "can", "am,can") {
       memset(r, 0, sizeof(r));
       rc = of_address_to_resource(np, 0, &r[0]);
       if (rc) {
           return rc;
       }
       rc = of_irq_to_resource(np, 0, &r[1]);
       if (rc) {
           return rc;
       }
   }

Note: the of_address_to_resource() call works fine, but the of_irq_to_resource() fails - always returns 0. Any ideas what I'm doing wrong?

Quoted 1 line

If they are PCI devices, the PCI code does it all for you.

Sadly, 100% home grown, not PCI.

Quoted 5 lines
Quoted 4 lines

* I know how to define the interrupt controller using irq_alloc_host() (once I have the VIRQ range) but it's not clear to me where to stick this initialization when bringing up my platform.

Quoted 7 lines

You don't provide a virq range to irq_alloc_host. You provide a type of reverse mapping (depending on how sparse your HW numbering scheme is) and for a linear map, how many entries it contains (which is the size of your -physical- range).

virqs are allocated on the fly.

Once I get the above call to work, I'll have to figure out how to get at the VIRQ (so my cascade handler can signal the right interrupt)

n.b. I only ask these questions after much investigation and experimentation; I'm not asking you to do my job for me, just help through the maze of twisty little passages!

--
------------------------------------------------------------
Gary Thomas | Consulting for the
MLB Associates | Embedded world
------------------------------------------------------------
_______________________________________________
Linuxppc-dev mailing list
[email protected]
https://ozlabs.org/mailman/listinfo/linuxppc-dev

Signature · 2 lines
Jon Smirl
[email protected]
#7 lore raw
In reply to Gary Thomas
Quoted 22 lines · Gary Thomas
Quoted 14 lines · Benjamin Herrenschmidt
Quoted 13 lines · Gary Thomas

I have a MPC5200 based board which has an FPGA for external I/O, etc. This FPGA also funnels interrupts from the various external devices through to the CPU.

I've defined this structure in my DTS:

     fpga@f8000000 {
             device_type = "board-control";
             #address-cells = <1>;
             #size-cells = <1>;
             // Note: includes sub-devices like CAN, A/D, etc
             reg = <0xf8000000 0x100000>;
Quoted 6 lines
Quoted 6 lines
             fpga_ic: fpga_ic@f8000000 {
                     device_type = "fpga-int-ctlr";
                     interrupt-controller;
                     #address-cells = <0>;
                     #interrupt-cells = <2>;
                     interrupts = <2 26 3>; // IRQ2
Quoted 3 lines

BTW, this is wrong! Are the IRQ mappings on the MPC5200 documented somewhere? I've looked and looked without much joy. Only by experimentation did I discover that "<1 2 3>" corresponds to IRQ2.

Documentation/powerpc/mpc52xx-device-tree-bindings.txt

1. Interrupt mapping
--------------------
The mpc5200 pic driver splits hardware IRQ numbers into two levels. The split reflects the layout of the PIC hardware itself, which groups interrupts into one of three groups; CRIT, MAIN or PERP. Also, the Bestcomm dma engine has it's own set of interrupt sources which are cascaded off of peripheral interrupt 0, which the driver interprets as a fourth group, SDMA.

The interrupts property for device nodes using the mpc5200 pic consists of three cells; <L1 L2 level>

L1 := [CRIT=0, MAIN=1, PERP=2, SDMA=3]
L2 := interrupt number; directly mapped from the value in the
"ICTL PerStat, MainStat, CritStat Encoded Register"
level := [LEVEL_HIGH=0, EDGE_RISING=1, EDGE_FALLING=2, LEVEL_LOW=3]

Quoted 119 lines
Quoted 12 lines
Quoted 12 lines
                     interrupt-parent = <&mpc5200_pic>;
             };
             can@f8010000 {
                     compatible = "am,can";
                     device_type = "can";
                     interrupts = <0 0>;
                     interrupt_parent = <&fpga_ic>;
                     reg = <0xf8010000 0x200>;
             };
     };
Quoted 6 lines
Quoted 2 lines

Of course, there will be more devices and interrupts later on, this is just the first of many.

Nothing obviously wrong so far other than you should use "compatible" properties to identify your devices, including (especially) the fpga & its pic, and maybe use slightly more verbose entries than "am,can" :-)

Fair enough, but these are 100% internal devices. I'm only using the OF tree for them as that seems to be the accepted method (IMO, it's a bit wrong-headed, but that's another discussion...)

Quoted 19 lines
Quoted 3 lines

Now the questions:
* How do I choose the VIRQ range supported by my FPGA?

You don't. Linux virtual numbers are allocated sparsely and on the fly.

You basically create an irq_host data structure, specifying what kind of reverse mapping you want (typically in your case I suspect linear since your HW interrupt space won't be huge), provide the appropriate callbacks, all I can suggest here is to look at what others do.

Quoted 7 lines

I'm interested in this in particular for the MPC5200, but also for other chips (I have many such board configurations).
* How do I pass this information along to my drivers? I would think that the interrupts value for the can interface above would use a [logical] IRQ (an offset from the base VIRQ), so how does the driver get the actual number (VIRQ+offset) when probing the tree?

Quoted 6 lines

Depends on the driver. But if they use an OF node, they can do of_irq_parse_and_map() or something like that. It will walk the tree, find the controller, map it to an irq_host (via the callbacks your provided), allocate a virq if not done yet, establish a virq->hw mapping etc... all for you, and return the virq.

This part is still a bit fuzzy. Where/how does my interrupt controller driver get this VIRQ? Here's how I created my controller:

   fpga_can_irq = irq_of_parse_and_map(fpga_ic, 0);
   D_printk(("%s: fpga_irq = %d\n", __func__, (u32) fpga_can_irq));
   if (fpga_can_irq == 0) {
       printk(KERN_ERR "%s: Can't find FPGA Interrupt Controller IRQ", __func__);
       return -EINVAL;
   }
   if (request_irq(fpga_can_irq, &fpga_irq_cascade, 0, "FPGA CAN", 0)) {
       printk(KERN_ERR "%s: Can't attach to FPGA Interrupt Controller IRQ", __func__);
       return -EINVAL;
   }
   fpga_irq_host = irq_alloc_host(of_node_get(fpga_node), IRQ_HOST_MAP_LINEAR,
                                          16, &fpga_irq_host_ops, -1);

When I try to get the interrupt number for the CAN sub-device, I always get zero :-(

   for_each_compatible_node(np, "can", "am,can") {
       memset(r, 0, sizeof(r));
       rc = of_address_to_resource(np, 0, &r[0]);
       if (rc) {
           return rc;
       }
       rc = of_irq_to_resource(np, 0, &r[1]);
       if (rc) {
           return rc;
       }
   }

Note: the of_address_to_resource() call works fine, but the of_irq_to_resource() fails - always returns 0. Any ideas what I'm doing wrong?

Quoted 1 line

If they are PCI devices, the PCI code does it all for you.

Sadly, 100% home grown, not PCI.

Quoted 5 lines
Quoted 4 lines

* I know how to define the interrupt controller using irq_alloc_host() (once I have the VIRQ range) but it's not clear to me where to stick this initialization when bringing up my platform.

Quoted 7 lines

You don't provide a virq range to irq_alloc_host. You provide a type of reverse mapping (depending on how sparse your HW numbering scheme is) and for a linear map, how many entries it contains (which is the size of your -physical- range).

virqs are allocated on the fly.

Once I get the above call to work, I'll have to figure out how to get at the VIRQ (so my cascade handler can signal the right interrupt)

n.b. I only ask these questions after much investigation and experimentation; I'm not asking you to do my job for me, just help through the maze of twisty little passages!

--
------------------------------------------------------------
Gary Thomas | Consulting for the
MLB Associates | Embedded world
------------------------------------------------------------
_______________________________________________
Linuxppc-dev mailing list
[email protected]
https://ozlabs.org/mailman/listinfo/linuxppc-dev

Signature · 2 lines
Jon Smirl
[email protected]
#8 lore raw
In reply to Gary Thomas
Quoted 22 lines · Gary Thomas
Quoted 14 lines · Benjamin Herrenschmidt
Quoted 13 lines · Gary Thomas

I have a MPC5200 based board which has an FPGA for external I/O, etc. This FPGA also funnels interrupts from the various external devices through to the CPU.

I've defined this structure in my DTS:

     fpga@f8000000 {
             device_type = "board-control";
             #address-cells = <1>;
             #size-cells = <1>;
             // Note: includes sub-devices like CAN, A/D, etc
             reg = <0xf8000000 0x100000>;
Quoted 6 lines
Quoted 6 lines
             fpga_ic: fpga_ic@f8000000 {
                     device_type = "fpga-int-ctlr";
                     interrupt-controller;
                     #address-cells = <0>;
                     #interrupt-cells = <2>;
                     interrupts = <2 26 3>; // IRQ2
Quoted 3 lines

BTW, this is wrong! Are the IRQ mappings on the MPC5200 documented somewhere? I've looked and looked without much joy. Only by experimentation did I discover that "<1 2 3>" corresponds to IRQ2.

http://www.nabble.com/-PATCH--powerpc-mpc5200:-Document-and-tidy-irq-driver-td20740376.html

This should be going in for 2.6.29. There is also some documentation about it in Documentation/powerpc/mpc52xx-device-tree-bindings.txt

g.