Configuring Super South Bridge / VT82C686 APIC for level-sen

Hi,

I am interfacing a quad UART (Philips SC16C554) to a PC/104 CPU (CM600
from Ampro) across the ISA bus, and have OR-ed all four UART’s
interrupts to IRQ11. (Interrupt sharing on ISA bus is tricky, but I am
trying to be trickier …)

I invoke the driver like so: (The quad UART devices start at /dev/ser3;
I haven’t bothered starting /dev/ser6)

devc-ser8250 -u1 3f8,4 -u2 -b115200 2f8,3 -u3 280,11 -u4 288,11 -u5
290,11 > /ram/devc.log

Behaviour of a single port in a single direction is solid (I had it
running all weekend) however when I use a single port in two directions,
eventually the system gets into the “Out of interrupt events!” state and
is unrecoverable. When sharing interrupts in an edge-sensitive interrupt
environment (which I am fairly certain is the default), I would have
expected that the situation would eventually occur that an event is
missed, so I don’t really understand this behaviour (wouldn’t UART
communication just cease?). I thought I would try reprogramming the PIC
on my target, as it is documented as having configurable edge/level
sensitivity on the interrupt lines.

The CM600 uses the VIA VT82C686 south bridge; I wrote a small program to
reprogram these registers to give me level sensitivity.
(For reference, the document containing these register descriptions is
at http://www.viatech.com/en/resources/download-center/chipsets/, page
54-55)
At this point I can’t even read the register contents, let alone write.
Everything comes back all FF, which I would guess means there’s no
registers there.

Can anyone see what I’m doing wrong? Have I missed something in
mmap_device_memory (flags?) Has anyone programmed the VT82C686 bridge
before for level-sensitive interrupts?

Thanks for your trouble.

  • Tony

<<< Continuing conundrums in the coincidence-correlation-causality
continuum >>>

The invocation of my program:

(QNX) root - /usr/mcp/test> ./cafm_fix -v


The output of my program:

Performing VT82C686 South Bridge adjustments for CAFM UART

phys addr … 0xFEC00000
mmap returned … 0x40100000
APIC data addr … 0x40100010
APIC offset addr … 0x40100000

APIC offset … 0x0
APIC index … 0xFF
APIC ID … 0xFFFFFFFF

APIC offset … 0x1
APIC index … 0xFF
APIC Version … 0xFFFFFFFF

APIC offset … 0x26
APIC index … 0xFF
APIC data … 0xFFFFFFFF

APIC offset … 0x27
APIC index … 0xFF
APIC data … 0xFFFFFFFF

APIC index … 0xFF

The program source:

#include <sys/neutrino.h>
#include <inttypes.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>

#include <stdint.h> /* uintptr_t /
#include <hw/inout.h> /
in*(), out*() /
#include <sys/mman.h> /
mmap_device_io() /
#include <x86/intr.h> /
NMI */

//#define APIC_REGISTER_BASE ((uint64_t)0x0FEC00000)
#define APIC_REGISTER_BASE 0xFEC00000
#define APIC_REGISTER_OFFSET_ID 0x00
#define APIC_REGISTER_OFFSET_VERSION 0x01
#define APIC_REGISTER_OFFSET_IRQ_11_A 0x26
#define APIC_REGISTER_OFFSET_IRQ_11_B 0x27
#define APIC_REGISTER_RANGE 0x14
#define MAP_SIZE 4096
//#define MAP_SIZE 1024

int main(int argc, char *argv[])
{
int verbosity = 0;
int iarg;
volatile uint32_t * regbase;
volatile uint8_t * offset_p;
volatile uint32_t * data_p;

// Assert I/O privity to gain access to I/O mapping.
if (ThreadCtl( _NTO_TCTL_IO, 0 ) < 0)
{
perror(“Error in ThreadCtl”);
return(EXIT_FAILURE);
}

// Check command-line arguments
if (argc > 1)
{
for (iarg = 1; iarg < argc; ++iarg)
{
if (strcmp(argv[iarg], “-v”) == 0)
{
++verbosity;
}
}
}

regbase = mmap_device_memory( NULL,
MAP_SIZE,
PROT_READ|PROT_WRITE|PROT_NOCACHE,
0,
APIC_REGISTER_BASE);

if ( regbase == MAP_FAILED )
{
perror( “mmap device memory for physical address failed” );
return(-1);
}

offset_p = (uint8_t *)&regbase[0];
data_p = &regbase[4];

if (verbosity > 0)
{
printf("\nPerforming VT82C686 South Bridge adjustments for CAFM
UART\n\n");
printf(“phys addr … 0x%X\n”, APIC_REGISTER_BASE);
printf(“mmap returned … 0x%X\n”, regbase);
printf(“APIC data addr … 0x%X\n”, data_p);
printf(“APIC offset addr … 0x%X\n”, offset_p);
printf("========================\n");
}

/*

  • Program APIC Identification at offset 0:
  • “Software must program this value before using the APIC”
    */
    *offset_p = APIC_REGISTER_OFFSET_ID;
    *data_p = 0x0F000000;
    if (verbosity > 0)
    {
    printf("\nAPIC offset … 0x%X\n", APIC_REGISTER_OFFSET_ID);
    printf(“APIC index … 0x%X\n”, *offset_p);
    printf(“APIC ID … 0x%X\n”, *data_p);
    }

/*

  • Read APIC Version at Offset 1
    */

*offset_p = APIC_REGISTER_OFFSET_VERSION;
if (verbosity > 0)
{
printf("\nAPIC offset … 0x%X\n", APIC_REGISTER_OFFSET_VERSION);
printf(“APIC index … 0x%X\n”, *offset_p);
printf(“APIC Version … 0x%X\n”, *data_p);
}

/*

  • Read I/O Redirection settings for IRQ11 - first 32 bits
    */

*offset_p = APIC_REGISTER_OFFSET_IRQ_11_A;

if (verbosity > 0)
{
printf("\nAPIC offset … 0x%X\n",
APIC_REGISTER_OFFSET_IRQ_11_A);
printf(“APIC index … 0x%X\n”, *offset_p);
printf(“APIC data … 0x%X\n”, *data_p);
}

/*

  • Read I/O Redirection settings for IRQ11 - last 32 bits
    */

*offset_p = APIC_REGISTER_OFFSET_IRQ_11_B;

if (verbosity > 0)
{
printf("\nAPIC offset … 0x%X\n",
APIC_REGISTER_OFFSET_IRQ_11_B);
printf(“APIC index … 0x%X\n”, *offset_p);
printf(“APIC data … 0x%X\n”, *data_p);
}

/*

  • Set offset back to zero
    */

*offset_p = 0;

if (verbosity > 0)
{
printf("\nAPIC index … 0x%X\n", *offset_p);
}

if (munmap_device_memory((void *)regbase, MAP_SIZE) == (-1))
{
perror( “munmap failed” );
return(-1);
}

return 0;
}

Tony Nordstrom wrote:

Hi,

I am interfacing a quad UART (Philips SC16C554) to a PC/104 CPU (CM600
from Ampro) across the ISA bus, and have OR-ed all four UART’s
interrupts to IRQ11. (Interrupt sharing on ISA bus is tricky, but I am
trying to be trickier …)

I invoke the driver like so: (The quad UART devices start at /dev/ser3;
I haven’t bothered starting /dev/ser6)

devc-ser8250 -u1 3f8,4 -u2 -b115200 2f8,3 -u3 280,11 -u4 288,11 -u5
290,11 > /ram/devc.log

Hmmm, don’t know much about the Southbridge, but In order for the serial
driver to work with 4 ports sharing the same IRQ, you’ll need to specify
all 4 of the ports to the driver, since there will be no way for the
driver to clear an interrupt from the 4th port.

Rennie

In article <42C1A7E9.4020004@csical.com>, rallen@csical.com says…

Tony Nordstrom wrote:
Hi,

I am interfacing a quad UART (Philips SC16C554) to a PC/104 CPU (CM600
from Ampro) across the ISA bus, and have OR-ed all four UART’s
interrupts to IRQ11. (Interrupt sharing on ISA bus is tricky, but I am
trying to be trickier …)

I invoke the driver like so: (The quad UART devices start at /dev/ser3;
I haven’t bothered starting /dev/ser6)

devc-ser8250 -u1 3f8,4 -u2 -b115200 2f8,3 -u3 280,11 -u4 288,11 -u5
290,11 > /ram/devc.log

Hmmm, don’t know much about the Southbridge, but In order for the serial
driver to work with 4 ports sharing the same IRQ, you’ll need to specify
all 4 of the ports to the driver, since there will be no way for the
driver to clear an interrupt from the 4th port.

Rennie

That’s absolutly correct and I would only add please DO NOT PROGRAM
Super south south bridge. Please try this small program
http://ed1k.qnx.org.ru/picinfo.html
And if it gives your reasonable info about your interrupt lines, follow
the EISA spec to change edge to level sensitivity of PIC. Sharing
interrupts on ISA bus isn’t a trick but EISA extention available on
modern ISA bus (hmmm… punster… like PC/104 bus ;o))

Eduard.

P.S. If I remeber correctly C554 has INTA:INTD active when positive, you
have to OR them and invert result (or invert everyone then AND them) to
be PCI alike. Also provide open collector output for interrupt line on
bus (I believe interrupt lines on bus have internal pull up resistors),
in this way you will be able to share interrupt line between few your
boards if need for 8+ ports arises.

Just to add to everyone else’s comments: I think you’re being optimistic thinking the APIC is enabled, it’s not something that is, or even can be?, used on uniprocessor PCs. And even if it was in use it’d be a mistake to jump in under Neutrino and try to fiddle with the settings.


Evan

In article <d9u54u$7gs$1@inn.qnx.com>, evanh@clear.net.nz says…

Just to add to everyone else’s comments: I think you’re being optimistic thinking the APIC is enabled,

Strictly speaking it is enabled but in PIC compatible mode :slight_smile:

it’s not something that is, or even can be?, used on uniprocessor PCs.

Windows and Linux both use APIC in APIC mode even on uniprocessor PC. It
often gives a great flexibility in assigning IRQs to avoid sharing
interrupts much. Don’t be surprised to find NIC residing on IRQ19, for
example, of course in Windows or Linux. Also, there is some other
benefits of using APIC in native mode.

And even if it was in use it’d be a mistake to jump in under Neutrino and try to fiddle with the settings.

That’s why I asked to not touch APIC settings. It’s kinda dangerous
game… it’s probably possible, but it’s much more complex than just
sharing IRQ on ISA bus.

Eduard.

ed1k wrote:

Windows and Linux both use APIC in APIC mode even on uniprocessor PC. It
often gives a great flexibility in assigning IRQs to avoid sharing
interrupts much. Don’t be surprised to find NIC residing on IRQ19, for
example, of course in Windows or Linux. Also, there is some other
benefits of using APIC in native mode.

Sounds promising. What about the pairing problem, can the pairs be separated when all those extra IRQs become available?


Evan

In article <da04pi$ld3$1@inn.qnx.com>, evanh@clear.net.nz says…

Sounds promising. What about the pairing problem, can the pairs be separated when all those extra IRQs become available?

I am not quite sure I understand what are pairs, but I will try:

  1. If you mean cyclic IRQ routing across PCI slots recommended by PCI
    spec, like hardware ORing:
    INTA slot 1 - INTB slot 2 - INTC slot 3 - INTD slot 4
    INTB slot 1 - INTC slot 2 - INTD slot 3 - INTA slot 4
    etc.
    Then it’s gonna be still in place. In fact, vast majority of PCI cards
    use INTA. So, if you put 4 such cards into all PCI slots should be no
    interrupt sharing between different cards. If you have multifunction PCI
    card that’s allowed to use additional interrupt lines beside INTA and
    actually uses it, you may consider IRQ routing pointed above and
    probably you may still choose proper slot or two to put additional PCI
    card without interrupt sharing between PCI cards.

  2. If you mean interrupt sharing between PCI interrupts INTA:INTD and
    built-in devices (slot 0), then it greatly depends on quality of
    hardware design and chipset used by mainboard designer/manufacturer.
    Vast majority of cheap mainboards will have at least one internal device
    hardware ORed to PCI interrupt line even if it’s built around modern
    chipset that allows to avoid this interrupt sharing. All this is due to
    re-use of hardware designs to speed up development, re-use of software
    code to build quick’n’dirty BIOS, and sometimes lack of qualification of
    engineers involved in design.
    Technicaly pairing in this meaning could be avoided. For example,
    already old Intel 82801DB Hub4 (ICH4) I/O Controller has four additional
    interrupt lines INTE#:INTH# which may be used for PCI slots and built in
    mainboard devices. For reference, this chipset has internal LAN
    controller connected to INTE# (wrongly pointed in the PCI config space
    as connected to INTA#, must be just in order to follow the PCI spec
    which dosn’t operate any INTs but INTA:INTD), USB connected to
    INTA#:INTC#, AC’97 connected to INTB#, all legacy devices including EIDE
    controller follow the PC legacy IPQ mapping. So, there are INTD#,
    INTF#:INTH# for video and PCI cards (Note: not every of engineers I’ve
    spoken to on this issue could imagine using of those INTD,F:H pins as
    INTA:INTD across PCI slots… probably it would be much better if Intel
    used naming in reverse order or, in other words, used INTE#:INTH# for
    in-chip peripherals). Might be some mainboards (I dunno, I am not in
    this business, but I guess some brands should care) use these extra
    interrupt pins of modern chipsets, and only in this case (otherwise
    they’re hardwire ORed, not steered/multiplexed together due to lack of
    interrupts in legacy mode), switching from Non-APIC to APIC mode will
    separate the pairs.

Eduard.