----- Original Message ----- From: "(Eric W. Biederman)" ebiederman@lnxi.com To: "Ronald G. Minnich" rminnich@lanl.gov Cc: riskin@263.net,linuxbios@clustermatic.org Sent: 2003-02-12 20:44:11 Subject: Re: rtl8139 NIC IRQ is 0 on m758lmr+ mainboard
2.2 was o.k. with an SMP kernel, and an MP table in LinuxBIOS. The other cases it failed with. We were just happy when we could load 2.2 and we quickly switched to 2.3.x. The 2.4.x kernel code for assigning interrupts from irqs is not to bad, if you want to look at putting it into LinuxBIOS to support your 2.2.x kernel....
We're going to have to get linuxbios to set this stuff up.
I made a first stab but ran out of time, will have to try again later.
The interesting variant which is coming up is MSI. Interrupts over the pci bus, as specified in pci 2.3, pci-x 2.0 and pci-express.
The interrupt story keeps getting more complicated, not less...
Eric
Does your mainboad support APIC?
I think that if The SMP kernel is ok,the mainboard must support APIC. If the mainboad doesn't support APIC,maybe the kernel need support IRQ route table. But the 2.2.x kernel doesn't support parsing the IRQ route table supplied by LinuxBIOS. But the mainboad(sis630 chip set) used by me doesn't support it,according to ollie.( ollie@sis.com.tw)
Is the sis630 chip set wired as following?
* INTA INTB INTC INTD * ---------------------------- * slot 1: dev=0x9 wiring: PIRQ_C PIRQ_D PIRQ_A PIRQ_B * slot 2: dev=0xb wiring: PIRQ_B PIRQ_C PIRQ_D PIRQ_A * slot 3: dev=0xd wiring: PIRQ_A PIRQ_B PIRQ_C PIRQ_D
In "freebios/src/northsouthbridge/sis/630/southbridge.c"
.........
#ifdef OLD_KERNEL_HACK struct pci_dev *pcidev;
pcidev = pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, (void *)NULL); if (pcidev != NULL) { printk_info("Remapping IRQ on southbridge for OLD_KERNEL_HACK\n"); // remap IRQ for PCI -- this is exactly what the BIOS does now. pci_write_config_byte(pcidev, 0x42, 0xa); pci_write_config_byte(pcidev, 0x43, 0xb); pci_write_config_byte(pcidev, 0x44, 0xc); } // ethernet fixup. This should all work, and doesn't, yet. // so we hack it for now. // need a manifest constant for the enet device. pcidev = pci_find_device(PCI_VENDOR_ID_SI, 0x0900, (void *)NULL); if (pcidev != NULL) { u32 bar0 = 0xb001; // set the BAR 0 to 0xb000. Safe, high value, known good. // pci config set doesn't work for reasons we don't understand. pci_write_config_dword(pcidev, PCI_BASE_ADDRESS_0, bar0);
// Make sure bus mastering is on. The tried-and-true probe in linuxpci.c // doesn't set this for some reason. pci_write_config_byte(pcidev, PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
// set the interrupt to 'b' pci_write_config_byte(pcidev, PCI_INTERRUPT_LINE, 0xb); } else { printk_err("Can't find ethernet interface\n"); } #endif /* OLD_KERNEL_HACK */ ........
So, I modified mainboard.c in "freebios/src/mainboard/pcchips/m758lmr+" as following:
/**********************************************************************/ #include <printk.h> #include <pci.h> #include <pci_ids.h> #include <cpu/p5/io.h> #include <arch/pirq_routing.h> #include <types.h>
#define IRQ1 11 #define IRQ2 12 #define IRQ3 10
#define CONFIG_CMD(bus,devfn, where) (0x80000000 | (bus << 16) | (devfn << 8) | (where & ~3)) #define INTERRUPT_PIN 0x3d #define INTERRUPT_LINE 0x3c #define BUS 0
extern struct irq_routing_table intel_irq_routing_table; void mainboard_fixup(void) { }
static int pci_conf1_read_config_word(unsigned char bus, int devfn, int where, u16 * value) { outl(CONFIG_CMD(bus, devfn, where), 0xCF8); *value = inw(0xCFC + (where & 2)); return 0; }
static int pci_conf1_write_config_byte(unsigned char bus, int devfn, int where, u8 value) { outl(CONFIG_CMD(bus, devfn, where), 0xCF8); outb(value, 0xCFC + (where & 3)); return 0; }
static int pci_conf1_read_config_byte(unsigned char bus, int devfn, int where, u8 * value) { outl(CONFIG_CMD(bus, devfn, where), 0xCF8); *value = inb(0xCFC + (where & 3)); return 0; } // // calculate the irq_tables checksum // int calc_checksum(struct irq_routing_table *rt) { long i; u8 *addr,sum2=0; addr= (u8 *) rt; for (i=0;i<rt->size;i++) sum2 += addr[i]; return(sum2); } static void pci_irq_route_fixup() { u8 pin, devfn, irq, irq_written, stpc_reg; u8 irq_list[] = { IRQ1, IRQ2, IRQ3 }; // pirq(slot,pin); slot[0:2] pin[0:3] u8 pirq[3][4] = { {2,3,0,1},{1,2,3,0},{0,1,2,3}}; u16 vendor_id, mask; int i,j; printk_debug("pci_irq_route_fixup()\n");
mask = (1<<irq_list[0]) | (1<<irq_list[1]) | (1<<irq_list[2]);
// search all 3 slots for a device and program the pci INTERRUPT_LINE register // note: not needed by 2.4 but used by 2.2 // also program the stpc pirq routing registers // and set the value in the bios-style routing table used by linux. // When done, calculate and store the routing table checksum. // j=0; for (i=0;i<3;i++) { // i= slot# -1 // read the pin if the device exists devfn = PCI_DEVFN(0x9+i*2,0); pci_conf1_read_config_word(BUS,devfn,0,&vendor_id); if (vendor_id == 0xffff) continue;
pci_conf1_read_config_byte(BUS,devfn,INTERRUPT_PIN,&pin); if (!pin) continue;
printk_debug("sis630 pci_irq_route_fixup(): found INT pin for dev 0x%x -> pin %d\n",0x9+i,pin); pin--; // we start at 0: pin 0-3 -> INTA-D
// get the next irq in our list irq = irq_list[j++];
// program the pci registers pci_conf1_write_config_byte(BUS,devfn,INTERRUPT_LINE,irq); pci_conf1_read_config_byte(BUS,devfn,INTERRUPT_LINE,&irq_written); printk_debug("sis630 pci_irq_route_fixup(): wrote pci INTERRUPT_LINE for dev 0x%x -> irq %d (%d)\n", PCI_SLOT(devfn),irq,irq_written);
// set the routing table // The 0xf0 causes linux to consider the irq hard-wired and use the link value // as the actual irq, so it does not need a router for the stpc. // Otherwise a kernel patch would be needed to add the stpc router into arch/i386/kernel/pci-irq.c intel_irq_routing_table.slots[i+2].irq[pin].link = irq | 0xf0; intel_irq_routing_table.slots[i+2].irq[pin].bitmap = mask; printk_debug("irq routing_table.slots[%d].irq[%d].link,mask = 0x%x,0x%x\n",i+2,pin, intel_irq_routing_table.slots[i+2].irq[pin].link, intel_irq_routing_table.slots[i+2].irq[pin].bitmap ); }
// // Now... // set the checksum in the routing table; // intel_irq_routing_table.checksum = 0; intel_irq_routing_table.checksum = -calc_checksum( (struct irq_routing_table *) &intel_irq_routing_table); printk_debug("sis630 pci_irq_route_fixup(): checksum calculated= 0x%x\n",intel_irq_routing_table.checksum);
printk_debug("sis630 pci_irq_route_fixup complete.\n"); }
void final_mainboard_fixup(void) { void final_southbridge_fixup(void); void final_superio_fixup(void);
printk_info("PCCHIPS m758lmr+ (and similar)...");
final_southbridge_fixup(); pci_irq_route_fixup(); #ifndef USE_NEW_SUPERIO_INTERFACE final_superio_fixup(); #endif }
/************************************************/
Then,I pluged my RTL8139 NIC into slot#1(PCI1). After my box started,the IRQ of RTL8139 is 11. But when I did "ping",I got following messages:
/**************************************************/
#ifconfig eth1 192.168.0.165 up eth1: RTL8139 Interrupt line blocked, status 1. #ping 192.168.0.1 PING 192.168.0.1 (192.168.0.1) from 192.168.0.165 : 72(100) bytes of data. --- 192.168.0.1 ping statistics --- 21 packets transmitted, 0 packets received, 100% packet loss #neighbour table overflow neighbour table overflow neighbour table overflow
#ping 192.168.0.1 PING 192.168.0.1 (192.168.0.1) from 192.168.0.165 : 72(100) bytes of data. --- 192.168.0.1 ping statistics --- 20 packets transmitted, 0 packets received, 100% packet loss
#ping 192.168.0.1 PING 192.168.0.1 (192.168.0.1) from 192.168.0.165 : 72(100) bytes of data. neighbour table overflow neighbour table overflow neighbour table overflow
--- 192.168.0.1 ping statistics --- 21 packets transmitted, 0 packets received, 100% packet loss
#neighbour table overflow neighbour table overflow neighbour table overflow ping 192.168.0.1 PING 192.168.0.1 (192.168.0.1) from 192.168.0.165 : 72(100) bytes of data. --- 192.168.0.1 ping statistics --- 14 packets transmitted, 0 packets received, 100% packet loss #eth1: Transmit timeout, status 0c 0005 media 18. eth1: Tx queue start entry 4 dirty entry 0. neighbour table overflow neighbour table overflow neighbour table overflow
#ping 192.168.0.1 PING 192.168.0.1 (192.168.0.1) from 192.168.0.165 : 72(100) bytes of data.
--- 192.168.0.1 ping statistics --- 15 packets transmitted, 0 packets received, 100% packet loss #eth1: Transmit timeout, status 0c 0005 media 18. eth1: Tx queue start entry 4 dirty entry 0. neighbour table overflow #ping 192.168.0.1 PING 192.168.0.1 (192.168.0.1) from 192.168.0.165 : 72(100) bytes of data.
--- 192.168.0.1 ping statistics --- 17 packets transmitted, 0 packets received, 100% packet loss #NET: 2 messages suppressed. neighbour table overflow eth1: Transmit timeout, status 0c 0005 media 18. eth1: Tx queue start entry 4 dirty entry 0. ping 192.168.0.1 PING 192.168.0.1 (192.168.0.1) from 192.168.0.165 : 72(100) bytes of data.
--- 192.168.0.1 ping statistics --- 14 packets transmitted, 0 packets received, 100% packet loss
#NET: 2 messages suppressed. neighbour table overflow ping 192.168.0.1 PING 192.168.0.1 (192.168.0.1) from 192.168.0.165 : 72(100) bytes of data. eth1: Transmit timeout, status 0c 0005 media 18. eth1: Tx queue start entry 4 dirty entry 0.
--- 192.168.0.1 ping statistics --- 20 packets transmitted, 0 packets received, 100% packet loss
#ping 192.168.0.1 PING 192.168.0.1 (192.168.0.1) from 192.168.0.165 : 72(100) bytes of data. eth1: Transmit timeout, status 0c 0005 media 18. eth1: Tx queue start entry 4 dirty entry 0.
--- 192.168.0.1 ping statistics --- 21 packets transmitted, 0 packets received, 100% packet loss
#NET: 5 messages suppressed. neighbour table overflow eth1: Transmit timeout, status 0c 0005 media 18. eth1: Tx queue start entry 4 dirty entry 0.
#ping 192.168.0.1 PING 192.168.0.1 (192.168.0.1) from 192.168.0.165 : 72(100) bytes of data.
--- 192.168.0.1 ping statistics --- 21 packets transmitted, 0 packets received, 100% packet loss
#NET: 2 messages suppressed. neighbour table overflow neighbour table overflow eth1: Transmit timeout, status 0c 0005 media 18. eth1: Tx queue start entry 4 dirty entry 0.
#ping 192.168.0.1 PING 192.168.0.1 (192.168.0.1) from 192.168.0.165 : 72(100) bytes of data. eth1: Transmit timeout, status 0c 0005 media 18. eth1: Tx queue start entry 4 dirty entry 0. eth1: RTL8139 Interrupt line blocked, status 5.
--- 192.168.0.1 ping statistics --- 18 packets transmitted, 0 packets received, 100% packet loss
#ping 192.168.0.1 PING 192.168.0.1 (192.168.0.1) from 192.168.0.165 : 72(100) bytes of data. eth1: Transmit timeout, status 0c 0005 media 18. eth1: Tx queue start entry 8 dirty entry 4. eth1: Transmit timeout, status 0c 0005 media 18. eth1: Tx queue start entry 4 dirty entry 0. eth1: Transmit timeout, status 0c 0005 media 18. eth1: Tx queue start entry 4 dirty entry 0. eth1: Transmit timeout, status 0c 0005 media 18. eth1: Tx queue start entry 4 dirty entry 0. eth1: Transmit timeout, status 0c 0005 media 18. eth1: Tx queue start entry 4 dirty entry 0. /*************************************************/
The critical messages are:
eth1: RTL8139 Interrupt line blocked, status 1. eth1: Transmit timeout, status 0c 0005 media 18. eth1: Tx queue start entry 8 dirty entry 4. eth1: Transmit timeout, status 0c 0005 media 18. eth1: Tx queue start entry 4 dirty entry 0. eth1: Transmit timeout, status 0c 0005 media 18. eth1: Tx queue start entry 4 dirty entry 0. eth1: Transmit timeout, status 0c 0005 media 18. eth1: Tx queue start entry 4 dirty entry 0. eth1: Transmit timeout, status 0c 0005 media 18. eth1: Tx queue start entry 4 dirty entry 0.
Could you give me some advice to resolve them?
Thanks.
riskin
========================== 263电子邮件-信赖邮自专业
On Thu, 2003-02-13 at 09:53, riskin@263.net wrote:
Does your mainboad support APIC?
I think that if The SMP kernel is ok,the mainboard must support APIC. If the mainboad doesn't support APIC,maybe the kernel need support IRQ route table. But the 2.2.x kernel doesn't support parsing the IRQ route table supplied by LinuxBIOS. But the mainboad(sis630 chip set) used by me doesn't support it,according to ollie.( ollie@sis.com.tw)
Is the sis630 chip set wired as following?
* INTA INTB INTC INTD * ---------------------------- * slot 1: dev=0x9 wiring: PIRQ_C PIRQ_D PIRQ_A PIRQ_B * slot 2: dev=0xb wiring: PIRQ_B PIRQ_C PIRQ_D PIRQ_A * slot 3: dev=0xd wiring: PIRQ_A PIRQ_B PIRQ_C PIRQ_D
The IRQ routing depends on the layout of the mainboard and has nothing to do with chipset (in general). You can not use the SiS 630 hack designed for winfast 6300 for your board.
Ollie
On Thu, 2003-02-13 at 09:53, riskin@263.net wrote:
----- Original Message ----- From: "(Eric W. Biederman)" ebiederman@lnxi.com To: "Ronald G. Minnich" rminnich@lanl.gov Cc: riskin@263.net,linuxbios@clustermatic.org Sent: 2003-02-12 20:44:11 Subject: Re: rtl8139 NIC IRQ is 0 on m758lmr+ mainboard
2.2 was o.k. with an SMP kernel, and an MP table in LinuxBIOS. The other cases it failed with. We were just happy when we could load 2.2 and we quickly switched to 2.3.x. The 2.4.x kernel code for assigning interrupts from irqs is not to bad, if you want to look at putting it into LinuxBIOS to support your 2.2.x kernel....
We're going to have to get linuxbios to set this stuff up.
I made a first stab but ran out of time, will have to try again later.
The interesting variant which is coming up is MSI. Interrupts over the pci bus, as specified in pci 2.3, pci-x 2.0 and pci-express.
The interrupt story keeps getting more complicated, not less...
Eric
Does your mainboad support APIC?
I think that if The SMP kernel is ok,the mainboard must support APIC. If the mainboad doesn't support APIC,maybe the kernel need support IRQ route table. But the 2.2.x kernel doesn't support parsing the IRQ route table supplied by LinuxBIOS. But the mainboad(sis630 chip set) used by me doesn't support it,according to ollie.( ollie@sis.com.tw)
Is the sis630 chip set wired as following?
* INTA INTB INTC INTD * ---------------------------- * slot 1: dev=0x9 wiring: PIRQ_C PIRQ_D PIRQ_A PIRQ_B * slot 2: dev=0xb wiring: PIRQ_B PIRQ_C PIRQ_D PIRQ_A * slot 3: dev=0xd wiring: PIRQ_A PIRQ_B PIRQ_C PIRQ_D
BTW, I don' think 2.2.x kernel has the code to program th IRQ router in the chipset neither.
eth1: RTL8139 Interrupt line blocked, status 1.
Could you give me some advice to resolve them?
riskin
You can delete the route table stuff as it is not used in 2.2 and will work as per standard linuxbios (irq_tables.c) in 2.4. The forced routing was only necessary for the stpc which the Linux kernel does not support.
As for INTA/B/C/D, this is strictly a motherboard wiring issue. Each PCI plug-in card connects to an interrupt line (if it uses one), these are called in the pci spec as PIRQA,B,C,D. The plug in card usually only uses one, typically. That line is wired from the slot on the motherboard to a corresponding INT line of the bridge (ie, the sis630), these are called INTA,B,C,D. For example, on the Sis630, INTA is pin K5, INTB is pin J5, etc. The wiring is cycled around on the motherboard and the slots to equalize the use of the interrupts. Which PIRQ the card hooks to depends on the card design. You need to program the sis630 to tell it which INTA,B,C,D should be hooked to which conventional interrupt line, irq 10,11, etc (this is calling routing). Further, you need to inform the Linux driver which irq to use as well.
Reading the INTERRUPT_PIN PCI register (of the plug-in card) reports which PIRQ is being used by the card, if it is non-zero. You then program the INTERRUPT_LINE register (on the card), based on the motherboard wiring, and router programming, to indicate which IRQ this PIRQ ultimately leads to. It appears to me that the INTERRUPT_LINE register as programmed for 2.2 is simply informational to the Linux driver, and not actually used by the card. I may have that wrong, though, I am not an expert on PCI. But it does not seem to be used on 2.4 at all.
I think the problem is you have programmed the RTL8139 PCI register, but you have not programmed the routing of PIRQ->interrupt in the bridge, and you really don't know the motherboard wiring. So the driver gets the IRQ, but it doesn't actually work (not routed). You are not sure whether it is INTA,B,C or D. You could figure this out by running 2.4 and getting the routing table, but you could also experiment and figure it out. Net cards are perfect for this experiment since they simply won't work without an IRQ but yet they don't seem to hang or crash Linux otherwise.
The bridge can be programmed as detailed in the 2.4 kernel, in arch/i386/kernel/pci_irq.c, for the sis chip. The vendor id is 1039H and the device id is 0008H, known as the LPC Bridge portion of the sis630, and the registers are 0x41-44 corresponding to INTA-D.
The 2.4 code relevant to the sis is pretty short, and is quoted below. I think the comment about values 1-4 is how the BIOS routing table is written, and has nothing to do with the sis bridge.
/* * PIRQ routing for SiS 85C503 router used in several SiS chipsets * According to the SiS 5595 datasheet (preliminary V1.0, 12/24/1997) * the related registers work as follows: * * general: one byte per re-routable IRQ, * bit 7 IRQ mapping enabled (0) or disabled (1) * bits [6:4] reserved * bits [3:0] IRQ to map to * allowed: 3-7, 9-12, 14-15 * reserved: 0, 1, 2, 8, 13 * * individual registers in device config space: * * 0x41/0x42/0x43/0x44: PCI INT A/B/C/D - bits as in general case * * 0x61: IDEIRQ: bits as in general case - but: * bits [6:5] must be written 01 * bit 4 channel-select primary (0), secondary (1) * * 0x62: USBIRQ: bits as in general case - but: * bit 4 OHCI function disabled (0), enabled (1) * * 0x6a: ACPI/SCI IRQ - bits as in general case * * 0x7e: Data Acq. Module IRQ - bits as in general case * * Apparently there are systems implementing PCI routing table using both * link values 0x01-0x04 and 0x41-0x44 for PCI INTA..D, but register offsets * like 0x62 as link values for USBIRQ e.g. So there is no simple * "register = offset + pirq" relation. * Currently we support PCI INTA..D and USBIRQ and try our best to handle * both link mappings. * IDE/ACPI/DAQ mapping is currently unsupported (left untouched as set by BIOS). */ static int pirq_sis_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) { u8 x; int reg = pirq;
switch(pirq) { case 0x01: case 0x02: case 0x03: case 0x04: reg += 0x40; case 0x41: case 0x42: case 0x43: case 0x44: case 0x62: x = (irq&0x0f) ? (irq&0x0f) : 0x80; if (reg != 0x62) break; /* always mark OHCI enabled, as nothing else knows about this */ x |= 0x40; break; case 0x61: case 0x6a: case 0x7e: printk(KERN_INFO "advanced SiS pirq mapping not yet implemented\n"); return 0; default: printk(KERN_INFO "SiS router pirq escape (%d)\n", pirq); return 0; } pci_write_config_byte(router, reg, x);
return 1; }
Hope I got all this right, I am sure if I didn't someone will point it out.
Basically, set INTA-D to irq11, program irq11 on the card, and it should work. Or, set A to 9, B to 10, etc., and then try setting the irqs on the card one at a time until it works. Do this on all slots and you can get the wiring. Very tedious, though.
-Steve