ast@cs.vu.nl (Andy Tanenbaum) (01/17/89)
I sort of take back what I said earlier about the 8259A. I went and found a data sheet and tried to make some sense out of it. I am not a programmable interrupt controller wizard, so take this with a metric ton of salt. The data sheet says: "The interrupt request must be removed before the EOI command is issued or the CPU interrupt is enabled to prevent a second interrupt from occurring." I suspect what they are trying to say is that if the EOI is issued when the level-triggered interrupt is still asserted, you get another interrupt. Thus, there is no way to have the 8259A fix the problem. The floppy disk controller must be given some sort of command to tell it to negate the interrupt. Furthermore, every other device (clock, hard disk, network, etc) that can generate interrupts has the same problem. I wonder if somebody over in comp.sys.ibm can help. I'll post a query there. Andy Tanenbaum (ast@cs.vu.nl)
srw%pws1@Sun.COM (Scott Wiesner) (01/18/89)
From article <1907@ast.cs.vu.nl>, by ast@cs.vu.nl (Andy Tanenbaum): > I suspect what they are trying to say is that if the EOI is issued when the > level-triggered interrupt is still asserted, you get another interrupt. > Thus, there is no way to have the 8259A fix the problem. The floppy disk > controller must be given some sort of command to tell it to negate the > interrupt. Furthermore, every other device (clock, hard disk, network, > etc) that can generate interrupts has the same problem. Yes! That's what my earlier article was trying to say. For the floppy, the command happens to be a sense interrupt status command, which has a value of 8. On some devices (like the serial port), just reading the status (which you do anyway) causes the interrupt to reset. Scott
wheels@mks.UUCP (Gerry Wheeler) (01/19/89)
In article <1907@ast.cs.vu.nl>, ast@cs.vu.nl (Andy Tanenbaum) writes: > I suspect what they are trying to say is that if the EOI is issued when the > level-triggered interrupt is still asserted, you get another interrupt. > The floppy disk > controller must be given some sort of command to tell it to negate the > interrupt. While I'm not familiar with the PS/2 family, that sounds similar to other computers I have used, and is really the essence of using level sensitive interrupts. If you have several IO boards connected to a single interrupt line, perhaps several serial ports, there may be more that one asserting the interrupt at one time. You get the interrupt, poll the devices to find who caused it, service the first device found, it releases the interrupt, you send EOI, and get another interrupt to remind you there is someone else still awaiting service. In theory, this seems far superior to edge sensitive interrupts, because in that case you cannot have more than one device on an interrupt. In practice, when it can't be made to work, the superiority may not be appreciated. :-) -- Gerry Wheeler Phone: (519)884-2251 Mortice Kern Systems Inc. UUCP: uunet!watmath!mks!wheels 35 King St. North BIX: join mks Waterloo, Ontario N2J 2W9 CompuServe: 73260,1043
jms@systime.UUCP (John Skelton) (01/23/89)
In article <1907@ast.cs.vu.nl> you write: >I suspect what they are trying to say is that if the EOI is issued when the >level-triggered interrupt is still asserted, you get another interrupt. This is correct. Approximately the opposite occurs with edge-triggered interrupts. In an interrupt routine, if you do nothing to remove the interrupt request from the I/O device, issue an EOI, and return (IRET, most likely)... Result: no more interrupts from that device, unless/until the device removes its interrupt request and re-asserts it. The Intel/NEC data sheets for the 8272/765 mention using Sense Interrupt Status multiple times until you get an error (value 0x80, I recall). This is so that you know that the chip has told you of every event it had outstanding -- including any that happened while you were in your interrupt routine. Given that at some time the chip had no more to say, it will have removed its interrupt request. Another event may, of course, happen while you are finishing off processing in your interrupt routine. So long as you get the software handling the interaction between 765 and 8259A right things will work, whether another event occurs before your IRET or not. (If another event does occur, another interrupt will come in after you leave your interrupt routine. Well, actually, the request will be pending as soon as the event occurs... you'll get the interrupt when you re-enable interrupts, which is normally done by the IRET.) The problem is getting the interaction between 765 and 8259A right. With edge-triggering, it's usually enough to issue a non-specific EOI as soon as the interrupt routine starts; you don't need to persuade the I/O device to remove its interrupt request until later. If there can be multiple reasons for the interrupt (e.g. several I/O events recognised by one device, or several I/O devices sharing an interrupt line -- OR'ed together, that is), you *MAY* need to service every event. The *MAY* is there to allow for devices which dutifully lower and raise their interrupt request every time you service ONE event. Note that the 765 does NOT do this -- if it has several things to tell you about, it just leaves its request outstanding. In fact, many chips used with Intel micros leave their interrupt requests raised in just this way. Level-triggering is better/worse/different... What you certainly must *NOT* do is to issue the EOI before servicing the device. Doing this is likely to result in the 8259A seeing what it thinks is a new request. Worse, this request will probably vanish when you service the actual I/O device. The 8259A issues a type 7 interrupt in this situation -- in theory (i.e. as if the device attached to its interrupt request 7 pin had interrupted). It is possible to get these type 7 interrupts in edge-triggering, but not quite so easy :-). An example would be doing I/O with interrupts temporarily disabled, and re-enabling at just the wrong time. This would be when the non-interrupt-driven code had nearly finished servicing the cause of the interrupt request (i.e. has just satisfied the I/O hardware), and then re-enables interrupts very promptly. Normally, this possibility can be ignored, but devices with high interrupt rates (e.g. RS232) can be the cause, as can very fast CPU's. The "in theory" above is because the 8259A doesn't do much in the way of latching interrupt requests. In fact, I think it ONLY latches requests when it sees the CPU circuitry issuing Interrupt Acknowledge cycles. In a sense, the 8259A is a priority-encoder asking the CPU for an interrupt sequence. The Intel '86 family CPU's don't latch interrupt request, so if the 8259A experiences an interrupt request which vanishes, the CPU will never notice it if its interrupt recognition was disabled at the time. If, however, the CPU does "see" and act on the interrupt request from the 8259, it will do some special hardware Interrupt Acknowledge cycles. The 8259A *HAS* to respond to these with *SOMETHING*. In the sad case where you caused a transient interrupt request to the 8259A from some I/O device, and no other device on that particular 8259A happens to need an interrupt servicing at the instant when the Interrupt Acknowledge cycles come in, the 8259A just pretends that it was a type 7 interrupt. Personally, I don't like the way Intel do interrupts; the PDP-11 was much nicer. However, the Intel way does work 100% given exactly correct code. It's such a shame that the code is hard to get right, and that the data sheets for such devices as the 8259A and NEC 765 / Intel 8272 are so bad!! Enough. Sorry. Hope this is some use. I have Intel-produced flowchart(s) of sense interrupt status, etc. code somewhere if you want copies.
stevel@eleazar.dartmouth.edu (Steve Ligett) (01/25/89)
I think the best way of fixing the interrupt problem for floppy disks is to call fdc_results within disk_int and return the status bytes in the message. Or, read out the first status byte *only*, in disk_int. It is reading this status byte that turns off the interrupt request from the fdc. My PC isn't yet up to running Minix, but here's what I'd try: 1. On receiving an interrupt, read the main status reg (3f4). If both bits 4 and 5 (NON_DMA & FDC_BUSY) are zero, a Seek or Recalibrate caused the interrupt, so issue the Sense Interrupt Status command. 2. Either call fdc-results or read out status reg 0 to turn off the interrupt. Return the result(s) in the message to the floppy task. 3. Modify the code after each receive (HARDWARE, &mess); in the floppy task to handle the results properly. Steve Ligett steve.ligett@dartmouth.edu or (decvax harvard linus true)!dartvax!steve.ligett
steve@basser.oz (Stephen Russell) (01/25/89)
In article <11932@dartvax.Dartmouth.EDU> stevel@eleazar.dartmouth.edu (Steve Ligett) writes: >I think the best way of fixing the interrupt problem for floppy disks is >to call fdc_results within disk_int and return the status bytes in the >message. > [ rest deleted ] Although this may fix the floppy driver, it becomes real messy when adding drivers for mice, network boards, hi-res graphics, et.al. If the problem is that the _drivers_ are the only code that can reset the interrupting device properly, then the only solution seems to be to abandon the "all interrupts go through one place" strategy. One (reasonably) clean solution may be something like this: - Use a common interrupt handler only for the purposes of saving the registers. The common handler then does an indirect call through a local table of interrupt handler addresses. This assumes that the common handler has some _quick_ way to identify the source of the interrupt (the 8259?). - Device drivers "register" a handler at start-up for their interrupt number. The private handler looks after reading the status, etc, clears the interrupt request, re-enables interrupts (which have been disabled long enough by now), and returns to the common handler, which sends the message to the driver task. - Until a handler is registered, the call table contains the address of a panic routine. This is probably a bit drastic - can the interrupt just be ignored, at least initially? - Where do the private handlers save the device status? I guess static storage in the driver code would be fine, so long as there are no overruns. These are only likely for keyboard and RS232 input - the rest of the devices won't interrupt again until given something to do by the driver task. Drivers that experience overruns could disable the device input interrupt until the task is activated. Incrementing a counter each time the interrupt handler is called, which is reset by the task, allows overruns to be detected. The advantage of this approach is that the device interrupt handling logic is where it should be: in the code for each device driver, not in the interrupt handler. If the cost of the indirect call is too much extra burden, then we are stuck with lots of little bits of assembler for each device, which are triggered directly by the interrupt. This maximises speed, at the cost of duplication of effort among the drivers. [It's been a while since I looked at Minix. If lots has changed since 1.1, and the above comments are a heap of noise, my apologies.]
ast@cs.vu.nl (Andy Tanenbaum) (01/26/89)
In article <11932@dartvax.Dartmouth.EDU> stevel@eleazar.dartmouth.edu (Steve Ligett) writes: >I think the best way of fixing the interrupt problem for floppy disks is >to call fdc_results within disk_int and return the status bytes in the >message. I am not sure if this is a suitable solution in general, i.e., one probably needs analogous hacks for the printer, ethernet, hard disk, serial port, etc., and that comes close to putting a fair amount of the logic in the interrupt routine, something that has been avoided so far. Andy Tanenbaum (ast@cs.vu.nl)
stevel@eleazar.dartmouth.edu (Steve Ligett) (01/30/89)
In article <1974@ast.cs.vu.nl> ast@cs.vu.nl (Andy Tanenbaum) writes: >In article <11932@dartvax.Dartmouth.EDU> stevel@eleazar.dartmouth.edu (Steve Ligett) writes: >>I think the best way of fixing the interrupt problem for floppy disks is >>to call fdc_results within disk_int and return the status bytes in the >>message. > >I am not sure if this is a suitable solution in general, i.e., one probably >needs analogous hacks for the printer, ethernet, hard disk, serial port, etc., >and that comes close to putting a fair amount of the logic in the interrupt >routine, something that has been avoided so far. > >Andy Tanenbaum (ast@cs.vu.nl) I should have said why I suggested that option. There were 4 options that I looked at: 1. Read out the main status reg of the fdc. Sadly, that didn't affect the INT line. 2. Mask interrupts in the 8259. That's what Steve Ackerman has working, I believe. The problem with that is that you've now thrown away the reason for level-sensitive interrupts, and I thought it was too early in the game to give them up. 3. Read out a status reg as I suggested above. I didn't mean to say I thought it was a great idea, just that I hadn't found one better. 4. Set the bit in the DOR (3f2) to mask interrupts. Now, this one sounds good. However, it didn't seem to work, when I tried it in DEBUG. But, I think I goofed in my testing, and will try again later this week, unless someone else has tried and posts results. This way sounds like the best way that I can see - it masks interrupts from the fdc, but nothing else. More later. Steve Ligett steve.ligett@dartmouth.edu or (decvax harvard linus true)!dartvax!steve.ligett
ast@cs.vu.nl (Andy Tanenbaum) (01/30/89)
In article <12009@dartvax.Dartmouth.EDU> stevel@eleazar.dartmouth.edu (Steve Ligett) writes: >2. Mask interrupts in the 8259. That's what Steve Ackerman has >working, I believe. The problem with that is that you've now thrown >away the reason for level-sensitive interrupts, and I thought it was too >early in the game to give them up. That is also the solution I proposed a couple of days ago. I don't think it defeats the purpose of level-triggered interrupts. Its purpose is to get around the fact that there aren't enough interrupt lines. By masking out interrupt 14 until the floppy disk task runs, it is true that you inhibit interrupts by any other device on that line. However, when the floppy disk task runs and senses the FDC and sends the EOI, the other device will then generate its interrupt. I don't think anything is lost. The solution proposed by Steve Ligett, which is also what Adrie Koolen did, has the disadvantage of requiring the interrupt routine to do whatever magic thing is needed to cause it to negate the interrupt. For the floppy it is a sense. Heaven knows what it is for an Ethernet board or a laser printer. I prefer not to have a lot of device specific code in the interrupt handlers if possible. Another point is that for some devices it may take a fair amount of work to make the thing shut up, which means running for a long time with interrupts disabled. More discussion on the pros and cons of the various methods is welcome. Andy Tanenbaum (ast@cs.vu.nl)