Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 18 Mar 1995 16:18:46 +1000
From:      Bruce Evans <bde@zeta.org.au>
To:        freebsd-hackers@freefall.cdrom.com, uhclem@nemesis.lonestar.org
Subject:   Re: Multiport serial cards
Message-ID:  <199503180618.QAA10402@godzilla.zeta.org.au>

next in thread | raw e-mail | index | archive | help
>[1]A 1-char "FIFO" as found on 8250's should be adequate provided you have
>[1]no bus-hogging devices.  sio can handle continuous data in both directions
>[1]at once at 115.2 on 2 ports (but not 3) on a 486DX/33 with 8250's.  The
>[1]system load for this is about 60% (too high for continuous use).  A
>[1]486DX2/66 with 16550's can probably handle about 6 times as many ports.

>It should be worse than that.  1/2880 cps = 347usec/character
>and if you have four ports on a board that means a characters is available
>on that board every 86usec worst case (the best case is 347usec). 
>And divide the times by two if the data is moving in both directions
>(43usec worst - 173.5usec best).

The factor of 6 is partly from assuming 16550's so that the worst case
latency requirement can be reduced by a factor of 16 if desired.  sio
currently sets the fifo trigger level to 14 (code to reduce it if an
overrun occurs was found to be braindamaged and is currently disabled),
so the worse case latency requirement is only reduced by a factor of
16 - 14) = 2.  Other overheads would become more restrictive than latency
if the fifo trigger level was set lower than 14.  That's part of the
reson why a DX2/66 with 16550's can only be expected to be 6 times
better.

The latency doesn't scale linearly with the number of boards.  A latency
of about 327usec could be made to work if required.  The driver would have
to read one character from each of 4 ports within (347 - 327) = 20usec of
receiving the interrupt.  This is possible, but it would increase overhead
to look for serial events in the right order.  The worst case for the
current sio order is about 30usec per port instead of 5usec (25 extra for
transmitting 16 chars).  Latency is less of a problem than efficiency so
I've optimized efficiency.  (I've also optimized too much for the non-
multiport case because that's all I have :-).

The latency for output is smaller than for input.  Output has less overhead,
and can wait (at the cost of throughput).  The driver has to be careful not
to let output processing increase input latency too much.

All this assumes that only one driver requires low latency and that
polling all ports is acceptable (it is acceptable for xx(x)50s on the
isa bus because the interface is braindamaged enough to require lots of
polling even for one port).  If there is more than one, then giving each
a fair share is like the problem of looking for serial events in the
right order, but harder.

>If you are using 8250s and must service an interrupt every 86usec, it
>just isn't going to work.  The ISA bus timing (I/O cycle is two 8.3MHz
>clocks long plus wait states and chip access-recovery timing) even
>becomes a limiting factor.

This was challenging on 8088's, but the same techniques that make
interrupt driven serial i/o at 19200bps possible on 8088's make it easy
on anything faster than a 386/20.  The ISA bus timing indeed becomes the
limiting factor.  I didn't notice it on a 386/20, but on 486's my rule
for writing efficient serial drivers is to minimise the number of i/o's
and don't worry much about minimising the number of integer instructions.

>How long does it take for the kernel to even
>poll the 8259 and figure out which interrupt it is?  The kernel might also
>want to save some state and a few other things before jumping to a driver.

It actually polls the UARTs.  Polling the 8259 isn't necessary because
interrupts are vectored.  Non-shared interrupts may be more efficient
because no polling is required to decide the device.  OTOH it may be
good to poll the 8259 and/or other UARTs before returning from an
interrupt.  Currently, the UART that caused the interrupt has to be
polled before returning because of edge triggered interrupt braindamage.
I'd like to be able to poll the relevant 8259 instead, so as to poll
all the other devices on the same 8259 for free, but the same edge
trigger braindamage stops the 8259 from keeping useful information
for the interrupt that is currently in service (the interrupt request
register gives the latched value).

The kernel saves a smaller than usual amount of state before entering
the serial driver.  The i386 saves a lot more state (too much) before
giving control to the kernel.  The worst case is when interrupts were
disabled for some reason (most often for the kernel entering another
handler) before a serial interrupt can be accepted.  The average
latency is 5-10usec on a DX2/66 and the worst case is (I hope) < 20usec.

>I promise that you aren't going to keep up with constant serial interrupts
>every 86usec (or less) in an ISA system.  Not without some intelligent

This is routine...

>The 8250's simply won't be reliable unless you ban all disk or tape
>I/O, and some brands of video boards that have to turn interrupts
>off for a msec or so here and there.

...at least with non-braindamaged other hardware :-).

Fortunately, braindamaged other hardware doesn't seem to be very common:
disk: - scsi drivers never disable interrupts
        (except ncr5380.c disables interrupts and then busy-waits :-(:-().
      - the wd driver never disables interrupts.  Not disabling them
        apparently causes problems for some drive/controllers under
        linux, so this may be a bug.  The linux disk driver now disables
        them by default, so everyone with 16450's suffers from serial
        overruns to allow the broken drive/controllers to work.
      - even the mcd driver only disables interrupts for about 10usec :-)
        (while it does a sequence of outb's).
      - some busmastering devices hog the bus, and of course the number
        of cycles available for processing is reduced while DMA is
        occurring).
tape: - scsi drivers never disable interrupts (except see above).
video: - syscons.c never disables interrupts.  This may be a bug.
       - the X server disables interrupts for a looong time while
         starting up.  A 20K fifo would be necessary to fix this.
other: - joy.c disables interrupts and then polls.  Hard to avoid :-(.
       - other drivers in sys/i386/isa either don't disable interrupts,
         or disable them only for short periods (< 10usec).

Anyway, for a special application, just don't run braindamaged h/w
simultaneously.

Bruce



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199503180618.QAA10402>