This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Documentation for C6678 queue interrupts

I have been trying to find a usable description of how interrupts can be generated when descriptors get pushed onto the various queues the C6678 supports (for example, when an output transfer has completed). I wish to understand what is happening at the register level and am not interested in this being hidden behind a raft of software. So far, all I have been able to find is a disconnected series of documents that no more than hint at what's going on without ever giving a straightforward description of the registers involved and their settings. In other words, I am looking for a document that says something like: to get an interrupt when a descriptor is pushed onto the TX free queue, set these registers to these values. Even better, but less likely, would be an example that sets the registers to handle simple, real, non-loopback, cases. So far, all the examples I have found either hide everything interesting in numerous layers of software or are doing incredibly complicated things.

I am not looking for a description of the C6000 interrupt structure as I understand that. What I need to know is what queue events can be made to generate interrupts, how to enable that end of the mechanism, and what the events so generated are (there are so many different documents involved and so many mappings and subtle name changes of events along the way that I find it almost impossible to make head or tail of what must be inherently a simple mechanism).

  • Hi,

    It seems to be there is not a document with all the required info. In general, you have to look at the data manual and the specific device manual to discover if the interrupt is connected to a DSP event or to the interrupt controller.

    Look at srugr9 (Keystone multicore navigator), para.5.3 interrupt maps. Some queues generate a DSP event, (accumulators) while some other are connected to the interrupc controller.

    So, for instance, I use queue 655 for my ethernet rx. In table 5-7 you can see it is connected to the CPINTC qm_int_pass_txq_pend_15, CPINTC0 Input Event 95. I setup the CPINTC0 to map the input event 95 to channel 1 (see sprugw4 CIC interrupt controller). This channel is mapped to the DSP event 103 (see SPRS691 C6678 data manual para.7.9).

    In the CIC manual there is th description of all the registers but I never tried to use them directly. I use the CSL.

    In general, for every interrupt source, you have to see if it is directly connected to a DSP event or to an CIC.

  • Thanks for the response. It is a continual problem I face. Everything seems to be described in terms of separate physical components rather than the often simpler operational structure,  the very thing that is needed to use the hardware system.

    I understand the CIC, but the problem is always tracing through the documents to see how it is actually to be used.

    All it would need is a single one-page diagram for each logical system (made up from multiple hardware components) and many of these issues would become clear.

  • After reading the documents yet again, I am none the wiser; they seem to have been written by someone who would have a career as a setter of cryptic crosswords.

    For example, table 7-38 in SPRS691C shows that event 32 is mapped to QM_INT_LOW_0. This latter symbol does not seem to be defined anywhere. The closest I can find is in a header file where CSL_GEM_QM_INT_LOW_0 is defined as 32. This cannot be correct, as this is the same as the interrupt event mapped to event number 21!

    What interrupt/event is generated by pushing a descriptor onto (say) queue 158?

    Does this needs to be enabled at the queue?

    What interrupt/event is this mapped to?

    There's no point in referencing symbolic names as they are often undefined; numerical values are explicit.

    if only TI had put in a simple diagram showing exactly how all of these multiple mappings fit together.

  • Here are some of my problems. You refer to  table 5-7 of SPRUGR9 (I'm using ...e) and say it shows queue 665 is connected to event 95. In my copy, the only events mentioned are 48..55.

    Take table 7-38 in SPRS691C. The only entries that make sense are for event numbers 21-31 as they have expressions for the interrupt events. What is the value of QM_INT_LOW_0 for example? I can't find it defined anywhere! I suspect it must be, but probably with a different name.

    Can anyone seriously claim that this documentation is anything but obscure?

  • I was using the version C. In version E the table is 5-12, that is under the para.5.2.2 TCI660x, C667x devices. The other paragraphs are about other chips.

    Anyway I agree with you: is very hard to glue together all the info. For instance, after no less then 5 or 6 re-reading, I can suppose QM_INT_LOW_0 refer to low priority accumulator queues (that are directly mapped to events and not requires the additional step of CIC programming).

    I didn't find that name elsewhere, but the description say "QM intr 0..31". sprugr9 table 5.9 (revsion E) give a more clear mapping info. Even so, to find out how to attach a DSP interrupt to my queue 655 take me a week!

  • Hi Alberto, Peter,

     So, the confusion here is what is the mapping of what pin goes to what event, and etc. The reason why the documents get so confusing is that the design specs are made up where the pins have multiple names, privacy issues, etc, and the engineers working on it get confused, too. I'll try to help you guys get a clear understanding of the documents.

    To start from the top,

     "What I need to know is what queue events can be made to generate interrupts, how to enable that end of the mechanism, and what the events so generated are."

     Okay, so that 7-38 table is a good resource to what interrupts can occur on the queue. I actually had a coworker work on a similar issue in another fourm post (link http://e2e.ti.com/support/embedded/bios/f/355/t/134420.aspx?pi71485=2 , which I believe answer some more of your questions as well), and I'm going to quote him since, well, he did the best you could to describe it (please forgive me if I'm reiterating things you already are aware of. However, this might help).  

    "Inside each C66x CorePac is the C66x DSP core, plus local L1/L2 memories, plus some special control and logic modules. The C66x DSP core can only accept 16 interrupts, and 4 of those are hard-coded for certain functions, leave only 12 user-controlled interrupt inputs. There are many more than 12 possible interrupt sources, even just within the CorePac itself. So one of the special modules is the internal Interrupt Controller (INTC). This internal INTC accepts 124 events and selects among those 124 events or even combinations of those 124 events, and then generates 12 possible interrupt sources to the C66x DSP core.

    Some of the event inputs to the internal INTC come from within the CorePac, such as the "PMC memory protection fault event", number 121. Some of the event inputs to the internal INTC come from outside the CorePac but inside the C6678, such as TINT8L "Timer [8] interrupt low", number 66. In SPRS691a starting on page 146, Table 7-39 "TMS320C6678 System Event Mapping - C66x CorePac Primary Interrupts" lists the 128 events that are the selectable interrupt sources for a CorePac. Each CorePac has one of these internal INTC's. This is what you programmed in SYS/BIOS, and that is why it is limited to 128.

    But 128 is not enough. There are many more events that get generated by peripherals and pins and modules in the C6678 from outside the CorePacs. More than 40 events are generated by the combination of the three EDMA3 modules; more than 16 come from the SRIO.

    To allow for many more events to be routed through, ultimately to one of a C66x DSP's 12 user interrupts, we added device-level Interrupt Controllers (INTC), or "my other brother Darryl". The device INTC accepts how ever many interrupt sources the device design engineer decided were needed. INTC0 and INTC1 have 160 events numbered, although some are Reserved.

    In SPRS691a on page 149, Tables 7-39 through 7-42 lists the events that can be selected by the device INTCs. Those events (or combination of events) are then forwarded to each of the CorePacs and to the internal INTC in a CorePac.

    I am sorry that our documentation uses the exact same name for two different modules in the same device. We solved this in the C6474 by calling the internal one the INTC and the device one the Chip Interrupt Controller (CIC). It looks like we forgot some goods ideas from the past. My apologies, because I felt your same confusion as I was reading through the documents trying to figure this out."

    Now, Alberto is correct is that most of the information is split (badly) between two documents. If you want to configure the device level interrupts in BIOS/SYS you can use the   ti.sysbios.family.c66.tci66xx.CpIntc  module. In the forum post I mention, another person gives a great example of it:

    In this example, I'm mapping System interrupt 15 to Host interrupt 8.  Then I'm configuraing Hwi 4 with Host interrupt 8.  CpIntc_getEventId() API with the latest 6.32.04 release is correct but has a bug in earlier 6.32 releases.

        CpIntc_mapSysIntToHostInt(0, 15, 8);
        CpIntc_dispatchPlug(15, &event15Fxn, 15, TRUE);
        CpIntc_enableHostInt(0, 8);
        eventId = CpIntc_getEventId(8);

        Hwi_Params_init(&params);
        params.arg = 8;
        params.eventId = eventId;
        params.enableInt = TRUE;
        Hwi_create(4, &CpIntc_dispatch, &params, NULL);

    So, yes this is a software overlap which you mentioned before you weren't looking for. But, this is a way that you can configure those interrupts and maybe gain more understanding.

     

    "For example, table 7-38 in SPRS691C shows that event 32 is mapped to QM_INT_LOW_0. This latter symbol does not seem to be defined anywhere." This is a problem we've had in the past. Basically it seems either so obvious, or the definition is old enough that it gets forgotten to define, or that the internal name isn't what the public name is. It happens, and I apologize.

     But! I can tell you that QM_INT_LOW_N is the qmss_intr0[N] and the QM_INT_HIGH_N is the qmss_intr1[N] from the Queue Manager. The exact mapping of event x to event name y is different for each device. However for a good chunk of the C66x (such as 6678) 32 is QM_INT_LOW_0 and  event 21 is INTC0_OUT(32+0+11*n)^7 or etc. I just confirmed this with our internal specs.

    "What interrupt/event is generated by pushing a descriptor onto (say) queue 158?"

      Well, one option is to map this interrupt to a configurable channel. I've included a wiki page with some information that shows you how to on Keystone devices. But. these 512 queues are divided into 16 groups (each with 32) and each of these groups is montiored with one interrupt. You can assign this interrupt in your code to cause another process to happen. Group 0 gets the (now infamous) QM_INIT_HIGH_0 signal, and etc for the 15 other groups.

    "Does this needs to be enabled at the queue?What interrupt/event is this mapped to?"

    Nope, and see above.

    "Can anyone seriously claim that this documentation is anything but obscure?"

    ...I plead the fifth. :D

     

    I realize this is a lot of information, but I hope this answers your concerns. Feel free to ask again if you have any other questions. I know what it's like to have confusing documentation, and I'm happy to assist.

     

    Regards,

    Kat Kelsch

     

    Resources:

    1. http://processors.wiki.ti.com/index.php/Configuring_Interrupts_on_Keystone_Devices

    2, http://e2e.ti.com/support/dsp/c6000_multi-core_dsps/f/639/t/217653.aspx

    3. http://learningmedia.ti.com/public/hpmp/KeyStone/05_QMSS/index.html (slide 13)

  • Thanks for the information; I shall plough through it and see if things start to make some sort of sense.

    I think TI could save a great deal of grief by taking a really serious look at all its documentation. I find it particularly galling that you imply that the documentation and design of the hardware happen in parallel and drift apart. Don't you have anyone in charge of quality & configuration control?

    I can make some (I hope, helpful) suggestions:

    1. You need to have two sets of documentation targetted at the different consumers: hardware designers and software developers. Nothing irritates software people more than having to wade through page after page of (useless to them) pinouts and timing diagrams looking for information on actually programming the device.
    2. Part of the reason I believe the documentation doesn't get fixed is the assumption that everyone is using BIOS/CSL and that hides many of the errors. Most may use them, but I do not. Given a correct description of the actual hardware at the register level, moving to BIOS/CSL would be almost trivial; going the other way round isn't.
    3. Have the software part written by real software engineers who have programmed the part (but NOT developed it, see #5). Too much of the supposedly 'software' description sounds like it's been written by a hardware engineer (no slight intended, they just think in different ways).
    4. Start with an OVERVIEW that actually says what the device is supposed to do and how all the bits fit together, and not that is support this signalling standard and that electrical option. Look at the Hyperlink description. Nowhere does it actually say what it does or how you use it from a software perspective.
    5. Put in meaningful examples, starting with the most trivial and SLOWLY building up to the the complex and obscure. You make a telling comment about things being obvious. This is a classic documentation problem: if the writer has been involved with the target for too long, EVERYTHING is obvious and so only the more obscure/interesting things get described (and then in language that assumes you fully understand everything else).
    6. Add LOTS of useful diagrams, not the trivial ones currently presented. As an example, I have a one-page diagram that shows the convoluted mapping between an actual event and the CPU being interrupted, showing every stage involved and referencing the (far too numerous) corresponding documents. If I had had that diagram at the start, weeks of wasted effort would have been saved, and pages of useless description would have been rendered unnecessary.
    7. Finally more of an irritation: all of the documentation is formatted forbooks/paper copies. How many of those do you actually produce nowadays? I suspect that the vast majority of your customers read documentation on-line. Given that, it's an absolute pain to have to scroll through page after page after page of tables of contents, tables of diagrams etc. These are utterly useless on-line. If you really must have them, put them at the end of the document along with all the legal twaddle and other weasel words.

    Peter

  • Hi Peter,

    We absolutely do like getting feedback so that we're able to improve our documentation. I'll immediately forward this to someone on both our documentation team and my personal team to make sure it gets heard.

    Just so you know, it has been suggested in the past to have a separate software and hardware user guides (aka, PA User Guide and PA LLD user guide). I think there were issues of more of the ability of getting it done in time. However, I definitely see the benefits you suggest.

     

    If you have any other theory or INTC based questions, feel free to ask. I'll do my best to answer them.

    Regards,

    Kat Kelsch

  • I've taken a look at the Wiki and I'm afraid it suffers from all the problems we've discussed before.

    For example, there is a diagram headed by "The following diagram summarizes the key process flow for interrupt handling on Keystone devices." This shows 208 System Interrupts going into INTC and coming out as 114 Host interrupts (no mention of CIC).

    The very next diagram shows the System interrupts going into the CIC and coming out as Host interrupts which then go into the INTC having mysteriously changed into Event IDs (same value/different value?) and the outputs from INTC are no longer Host interrupts but "Cpu Interrupt Vector".

    If that's not confusing I don't know what is! What does go into INTC? Is it a system interrupt or a host interrupt or an Event ID or a Martian quasi-system interrupt or ...?

    The code examples are not at all helpful in understanding what's going on because they hide what is actually happening behind layers of software. If you had one example that showed exectly how you map one System interrupt all the way through to any CPU interrupt AT THE REGISTER LEVEL it would make everything so much clearer. I'm not suggesting that higher-level descriptions aren't useful, just that the low-level ones remove any possibility of confusion and also remove the need to go to yet another document (there are so many) to discover what the high-level functions actually do.

    From my code that successfully sets up DMA interrupts, I see that it involves just 3 register writes to map the event in CIC, 2 to enable it, 1 for the global enable, and 1 to set the INTMUX. That's a total of 7 register writes that would show the actual mechanism to be used. The issue is then knowing the magic numbers for the confusingly-named signals as they pass through the various components.

    As soon as the descriptions resort to hand waving (saying that something should be done whithout saying how) you've lost your reader.

    You say "The exact mapping of event x to event name y is different for each device. However for a good chunk of the C66x (such as 6678) 32 is QM_INT_LOW_0 and  event 21 is INTC0_OUT(32+0+11*n)^7 or etc. I just confirmed this with our internal specs.". That is useful to know, but as I don't have your internal specs it doesn't help in the general case of working out what these numbers could possibly be.

    It seems that you have so many levels of indirection here that you have run out of names to describe the various stages and have re-used names like host and system to mean different things in different contexts. I suspect that this is so complicated (and if history is anything to go by, will increase in complexity in the next device) that it's a mistake to try to give meaningful names (system, host, ...) to these signals as they will be arbitrary. Instead, it would probably be better simply to label each stage in the path S1, S2, S3, ... and then name the signals with those labels: S1_GPINT1, or whatever. Then you could make it clear in tables what the mapping is (from S1 to S2, from S3 to S5, etc) and what values various registers are expected to take(S1, S2,...) without any possibility of misunderstanding where event 99 actually comes from or goes to.

    Yet another thing that is utterly perplexing is why all the related events/signals are labelled TXQ. What happened to the RQX signals one would expect for input?

    I am still no closer to being able to understand how to get the placing of an input packet on a queue to interrupt a core. From private messages I have received, it appears that I am not alone in my confusion.

  • After abandoning this topic to deal with more pressing issues, I have come back to it in the hope that I can at last get some clear answers.

    To avoid unnecessary responses, I understand how interrupts work in the C6678 - this is not the issue as I have large amounts of code working with interrupts. My problem is working out how to get the system to generate the particular interrupt events of interest that will be routed through the labyrinthine complexity of the device (and determining what those events are).

    To be specific, I have working code that writes a well-formed Ethernet packet by pushing a descriptor onto a queue (648), polling the return queue (903) until the descriptor appears and returning the descriptor to the free list. I need to remove the polling, so I need an interrupt event to be generated when the transfer has completed and the descriptor is pushed onto the return queue. How precisely can I do this?

    I am polling the RX queue in a similar way to wait for an incoming packet. How can I generate an interrupt event for that rather than polling?

  • Hi,

    According to SPRUGR9C, table 5-7, only queue 652-671generates specific interrupt on the interrupt controller so as far as I know you cannot use the queue 903 for this purpose.

    If for istance you choose queue 654 for tx free packets and 655 for rx you will get CPINTC0 input event 93 (tx) and 95 (rx). These events have to be mapped to two CIC output channel that will be captured as DSP events. According to data C6678 sheet table 7-38, you can map them to CIC0_OUT0=DSP event 102 and CIC0_OUT1=DSP event 103.

      CSL_CPINTC_Handle ci=CSL_CPINTC_open(0); //CIC0

      CSL_CPINTC_disableAllHostInterrupt(ci);
      CSL_CPINTC_disableHostInterrupt(ci, 0);
      CSL_CPINTC_disableSysInterrupt(ci, 93);
      CSL_CPINTC_disableHostInterrupt(ci, 1);
      CSL_CPINTC_disableSysInterrupt(ci, 95);

      //queue 654 -> ch0 -> DSP event 102
      CSL_CPINTC_mapSystemIntrToChannel(ci, 93, 1);
      CSL_CPINTC_enableSysInterrupt(ci, 93);
      CSL_CPINTC_enableHostInterrupt(ci, 0);
     
      //queue 655 -> ch1 -> DSP event 103
      CSL_CPINTC_mapSystemIntrToChannel(ci, 95, 1);
      CSL_CPINTC_enableSysInterrupt(ci, 95);
      CSL_CPINTC_enableHostInterrupt(ci, 1);
     
      CSL_CPINTC_enableAllHostInterrupt(ci);

      //Now enable DSP event 102 and 103 and map them to a DSP interrupt INT4-INT15

    When servicing the interrupt you have to clear it at CIC level:  CSL_CPINTC_clearSysInterrupt(ci, 95);

  • Thanks for that. I had tried using queues in the range you mention, but still couldn't get any interrupt.

    I'll give it yet another go in case some finger trouble stopped it working, but I have yet to see a twitch from any queue.

  • Peter Robertson said:

    Thanks for that. I had tried using queues in the range you mention, but still couldn't get any interrupt.

    Well, I can only suggest to verify where the interrupt is lost, that see look at the status of then event (at core level) or sys interrupt level (CIC0) using the CSL routine to see if interupts are pending and mybe simulating it by writing in the CIC0 registers.

    I also set the CIC in non nesting mode:

        CSL_CPINTC_setNestingMode (ci, CPINTC_NO_NESTING);

    This works for me at least for the RX interrupt (I don't use the TX interrupt).

  • It is working now.

    It must have been my finger touble when trying the other queues (not difficult considering the complexity of the device).

    Thanks for your help.