Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
From: Rene Herman
Date: Tue Jan 01 2008 - 16:38:08 EST
On 01-01-08 22:15, H. Peter Anvin wrote:
I have mentioned this before... I think writing zero to port 0xf0 would
be an acceptable pause interface (to the extent where we need an I/O
port) except on 386 with 387 present; on those systems we can fall back
to 0x80.
PII 400 / Intel 440 BX (PIIX4):
rene@6bap:~/port80$ su -c ./portime
out 0x80: 544 cycles
in 0x80: 254 cycles
in 0x61: 254 cycles
out 0xf0: 544 cycles
The Intel PIIX/PIIX3 datasheet specifically mentions that both reads and
writes at 0xf0 "flow through to the ISA bus".
However, more complete, it says:
"Writing to this register causes the PIIX/PIIX3 to assert IGNNE#. The
PIIX/PIIX3 also negates IRQ13 (internal to the PIIX). Note that IGNNE# is
not asserted unless FERR# is active. Reads/writes flow through to the ISA bus".
We don't want the side-effects, do we?
Rene.
/* gcc -W -Wall -O2 -o portime portime.c */
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <sys/io.h>
#define LOOPS 10000
inline uint64_t rdtsc(void)
{
uint32_t hi, lo;
asm ("rdtsc": "=d" (hi), "=a" (lo));
return (uint64_t)hi << 32 | lo;
}
inline void serialize(void)
{
asm ("cpuid": : : "eax", "ebx", "ecx", "edx");
}
int main(void)
{
uint64_t tsc0, tsc1, tsc2, tsc3, tsc4, tsc5;
uint64_t out80, in80, in61, outf0;
int i;
if (iopl(3) < 0) {
perror("iopl");
return EXIT_FAILURE;
}
asm ("cli");
tsc0 = rdtsc();
for (i = 0; i < LOOPS; i++) {
serialize();
serialize();
}
tsc1 = rdtsc();
for (i = 0; i < LOOPS; i++) {
serialize();
asm ("outb %al, $0x80");
serialize();
}
tsc2 = rdtsc();
for (i = 0; i < LOOPS; i++) {
serialize();
asm ("inb $0x80, %%al": : : "al");
serialize();
}
tsc3 = rdtsc();
for (i = 0; i < LOOPS; i++) {
serialize();
asm ("inb $0x61, %%al": : : "al");
serialize();
}
tsc4 = rdtsc();
for (i = 0; i < LOOPS; i++) {
serialize();
asm ("outb %b0, $0xf0": : "a" (0));
serialize();
}
tsc5 = rdtsc();
asm ("sti");
out80 = ((tsc2 - tsc1) - (tsc1 - tsc0)) / LOOPS;
in80 = ((tsc3 - tsc2) - (tsc1 - tsc0)) / LOOPS;
in61 = ((tsc4 - tsc3) - (tsc1 - tsc0)) / LOOPS;
outf0 = ((tsc5 - tsc4) - (tsc1 - tsc0)) / LOOPS;
printf("out 0x80: %llu cycles\n", out80);
printf("in 0x80: %llu cycles\n", in80);
printf("in 0x61: %llu cycles\n", in61);
printf("out 0xf0: %llu cycles\n", outf0);
return EXIT_SUCCESS;
}