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 *)®base[0];
data_p = ®base[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;
}