Commit 6cfe08d0 authored by Linus Torvalds's avatar Linus Torvalds

Linux 2.1.95

This is finally the kind of feature-freeze patch I like: it only contains
fixes for outright bugs. The fixes are:
 - SMP-safe disk drivers (more on this below)
 - various PCI fixes: /proc/bus/pci works again, and it should compile and
   work on Alpha with TGA.
 - parport interrupt detection uses the standard probe routines, and
   doesn't leave bogus "probe" entries hanging around to confuse people
   (and make other device registration fail)
 - the ever-popular PCI ne netdriver fix
 - the getcwd() system call works again.
 - "mb()" does the right thing on x86 too. Few drivers use it, but more of
   them should. Right now there are drivers that depend on luck making
   sure that the memory accesses will be in the same order outside the CPU
   as inside it.

The conceptually big one is the SMP-safe disk driver change: it's not a
very big patch, but it's fairly subtle. And it still requires help from
the disk drivers themselves, although all of them should be safe in UP,
and I made sure the BusLogic and the NCR driver are safe on SMP.
The change is really a change in locking defaults: we used to default to
no locking, and depended on the disk driver getting the locking right.
None of them did so on SMP, for understandable reasons (there really
wasn't any support for getting it right).

The new default is to do the locking for the driver, and the driver
actually has to do some work if it wants to do anything outside the lock.
This has the obvious advantage that it _defaults_ to being safe, and
people who know what they are doing can choose to thread the driver if
they want to.

The only change needed to drivers is to make sure they get the lock on an
interrupt, which usually involves just doing the following around the
low/level interrupt handler (the same handler that you register using
"request_irq()"):

        void handle_irq(int irq, void *dev, struct pt_regs *regs)
        {
+               unsigned long flags;
+               spin_lock_irqsave(&io_request_lock, flags);
                ... call to the proper action routines ...
+               spin_unlock_irqrestore(&io_request_lock, flags);
        }

which guarantees that everything inside the driver is correctly locked
from the outside world (with the exception of ioctl's etc things that the
driver traps - they need to be protected too).

                Linus
parent 2dcb1dcf
......@@ -641,61 +641,6 @@ static int parport_ECPPS2_supported(struct parport *pb)
/* --- IRQ detection -------------------------------------- */
/* This code is for detecting ECP interrupts (due to problems with the
* monolithic interrupt probing routines).
*
* In short this is a voting system where the interrupt with the most
* "votes" is the elected interrupt (it SHOULD work...)
*
* This is horribly x86-specific at the moment. I'm not convinced it
* belongs at all.
*/
static int intr_vote[16];
static void parport_vote_intr_func(int irq, void *dev_id, struct pt_regs *regs)
{
intr_vote[irq]++;
return;
}
static long open_intr_election(void)
{
long tmp = 0;
int i;
/* We ignore the timer - irq 0 */
for (i = 1; i < 16; i++) {
intr_vote[i] = 0;
if (request_irq(i, parport_vote_intr_func,
SA_INTERRUPT, "probe", intr_vote) == 0)
tmp |= 1 << i;
}
return tmp;
}
static int close_intr_election(long tmp)
{
int irq = PARPORT_IRQ_NONE;
int i, valid = 1;
/* We ignore the timer - irq 0 */
for (i = 1; i < 16; i++)
if (tmp & (1 << i)) {
if (intr_vote[i]) {
if (irq != PARPORT_IRQ_NONE)
/* More than one interrupt */
valid = 0;
irq = i;
}
free_irq(i, intr_vote);
}
if(valid)
return irq;
else
return PARPORT_IRQ_NONE;
}
/* Only if supports ECP mode */
static int programmable_irq_support(struct parport *pb)
{
......@@ -717,20 +662,23 @@ static int programmable_irq_support(struct parport *pb)
static int irq_probe_ECP(struct parport *pb)
{
int irqs, i;
unsigned char oecr = parport_pc_read_econtrol(pb);
probe_irq_off(probe_irq_on()); /* Clear any interrupts */
irqs = open_intr_election();
sti();
irqs = probe_irq_on();
parport_pc_write_econtrol(pb, 0x00); /* Reset FIFO */
parport_pc_write_econtrol(pb, 0xd0); /* TEST FIFO + nErrIntrEn */
parport_pc_write_econtrol(pb, 0x00); /* Reset FIFO */
parport_pc_write_econtrol(pb, 0xd0); /* TEST FIFO + nErrIntrEn */
/* If Full FIFO sure that WriteIntrThresold is generated */
for (i=0; i < 1024 && !(parport_pc_read_econtrol(pb) & 0x02) ; i++)
parport_pc_write_fifo(pb, 0xaa);
pb->irq = close_intr_election(irqs);
parport_pc_write_econtrol(pb, oecr);
pb->irq = probe_irq_off(irqs);
parport_pc_write_econtrol(pb, 0x00);
if (pb->irq <= 0)
pb->irq = PARPORT_IRQ_NONE;
return pb->irq;
}
......@@ -748,26 +696,30 @@ static int irq_probe_EPP(struct parport *pb)
return PARPORT_IRQ_NONE;
#endif
probe_irq_off(probe_irq_on()); /* Clear any interrupts */
irqs = open_intr_election();
sti();
irqs = probe_irq_on();
if (pb->modes & PARPORT_MODE_PCECR)
parport_pc_write_econtrol(pb, parport_pc_read_econtrol(pb) | 0x10);
parport_pc_frob_econtrol (pb, 0x10, 0x10);
epp_clear_timeout(pb);
parport_pc_write_control(pb, parport_pc_read_control(pb) | 0x20);
parport_pc_write_control(pb, parport_pc_read_control(pb) | 0x10);
parport_pc_frob_control (pb, 0x20, 0x20);
parport_pc_frob_control (pb, 0x10, 0x10);
epp_clear_timeout(pb);
/* Device isn't expecting an EPP read
/* Device isn't expecting an EPP read
* and generates an IRQ.
*/
parport_pc_read_epp(pb);
udelay(20);
pb->irq = close_intr_election(irqs);
pb->irq = probe_irq_off (irqs);
parport_pc_write_econtrol(pb, oecr);
parport_pc_write_control(pb, octr);
if (pb->irq <= 0)
pb->irq = PARPORT_IRQ_NONE;
return pb->irq;
}
......@@ -818,16 +770,19 @@ static int irq_probe_SPP(struct parport *pb)
*/
static int parport_irq_probe(struct parport *pb)
{
if (pb->modes & PARPORT_MODE_PCECR)
unsigned char oecr = parport_pc_read_econtrol (pb);
if (pb->modes & PARPORT_MODE_PCECR) {
pb->irq = programmable_irq_support(pb);
if (pb->irq != PARPORT_IRQ_NONE)
goto out;
}
if (pb->modes & PARPORT_MODE_PCECP)
pb->irq = irq_probe_ECP(pb);
if (pb->irq == PARPORT_IRQ_NONE &&
(pb->modes & PARPORT_MODE_PCECPEPP)) {
unsigned char oecr = parport_pc_read_econtrol(pb);
parport_pc_write_econtrol(pb, 0x80);
pb->irq = irq_probe_EPP(pb);
parport_pc_write_econtrol(pb, oecr);
}
......@@ -842,6 +797,8 @@ static int parport_irq_probe(struct parport *pb)
if (pb->irq == PARPORT_IRQ_NONE)
pb->irq = irq_probe_SPP(pb);
out:
parport_pc_write_econtrol (pb, oecr);
return pb->irq;
}
......
/*
* eata.c - Low-level driver for EATA/DMA SCSI host adapters.
*
* 10 Apr 1998 rev. 4.04 for linux 2.0.33 and 2.1.95
* Improved SMP support (if linux version >= 2.1.95).
*
* 9 Apr 1998 rev. 4.03 for linux 2.0.33 and 2.1.94
* Added support for new PCI code and IO-APIC remapping of irqs.
* Performance improvement: when sequential i/o is detected,
* always use direct sort instead of reverse sort.
*
* 4 Apr 1998 rev. 4.02 for linux 2.0.33 and 2.1.92
* io_port is now unsigned long.
*
......@@ -280,11 +288,14 @@
* the driver sets host->wish_block = TRUE for all ISA boards.
*/
#include <linux/version.h>
#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
#define MAX_INT_PARAM 10
#if defined(MODULE)
#include <linux/module.h>
#include <linux/version.h>
#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,26)
MODULE_PARM(io_port, "1-" __MODULE_STRING(MAX_INT_PARAM) "i");
MODULE_PARM(linked_comm, "i");
......@@ -294,6 +305,7 @@ MODULE_PARM(max_queue_depth, "i");
MODULE_PARM(tag_mode, "i");
MODULE_AUTHOR("Dario Ballabio");
#endif
#endif
#include <linux/string.h>
......@@ -314,9 +326,12 @@ MODULE_AUTHOR("Dario Ballabio");
#include "eata.h"
#include <linux/stat.h>
#include <linux/config.h>
#include <linux/bios32.h>
#include <linux/pci.h>
#if LINUX_VERSION_CODE < LinuxVersionCode(2,1,93)
#include <linux/bios32.h>
#endif
#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,36)
#include <linux/init.h>
#else
......@@ -338,6 +353,7 @@ struct proc_dir_entry proc_scsi_eata2x = {
#undef DEBUG_LINKED_COMMANDS
#undef DEBUG_DETECT
#undef DEBUG_PCI_DETECT
#undef DEBUG_INTERRUPT
#undef DEBUG_RESET
......@@ -583,7 +599,7 @@ static unsigned long io_port[] __initdata = {
#define V2DEV(addr) ((addr) ? H2DEV(virt_to_bus((void *)addr)) : 0)
#define DEV2V(addr) ((addr) ? DEV2H(bus_to_virt((unsigned long)addr)) : 0)
static void eata2x_interrupt_handler(int, void *, struct pt_regs *);
static void interrupt_handler(int, void *, struct pt_regs *);
static void flush_dev(Scsi_Device *, unsigned long, unsigned int, unsigned int);
static int do_trace = FALSE;
static int setup_done = FALSE;
......@@ -715,10 +731,48 @@ static inline int read_pio(unsigned long iobase, ushort *start, ushort *end) {
return FALSE;
}
__initfunc (static inline int
get_pci_irq(unsigned long port_base, unsigned char *apic_irq)) {
#if defined(CONFIG_PCI)
#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
unsigned int addr;
struct pci_dev *dev = NULL;
if (!pci_present()) return FALSE;
while((dev = pci_find_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) {
if (pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &addr)) continue;
#if defined(DEBUG_PCI_DETECT)
printk("%s: get_pci_irq, bus %d, devfn 0x%x, addr 0x%x, apic_irq %u.\n",
driver_name, dev->bus->number, dev->devfn, addr, dev->irq);
#endif
if ((addr & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
continue;
if ((addr & PCI_BASE_ADDRESS_IO_MASK) + PCI_BASE_ADDRESS_0 == port_base) {
*apic_irq = dev->irq;
return TRUE;
}
}
#endif /* end new style PCI code */
#endif /* end CONFIG_PCI */
return FALSE;
}
__initfunc (static inline int port_detect \
(unsigned long port_base, unsigned int j, Scsi_Host_Template *tpnt)) {
unsigned char irq, dma_channel, subversion, i;
unsigned char protocol_rev;
unsigned char protocol_rev, apic_irq;
struct eata_info info;
char *bus_type, dma_name[16], tag_type;
......@@ -812,8 +866,13 @@ __initfunc (static inline int port_detect \
printk("%s: warning, LEVEL triggering is suggested for IRQ %u.\n",
name, irq);
if (get_pci_irq(port_base, &apic_irq) && (irq != apic_irq)) {
printk("%s: IRQ %u mapped to IO-APIC IRQ %u.\n", name, irq, apic_irq);
irq = apic_irq;
}
/* Board detected, allocate its IRQ */
if (request_irq(irq, eata2x_interrupt_handler,
if (request_irq(irq, interrupt_handler,
SA_INTERRUPT | ((subversion == ESA) ? SA_SHIRQ : 0),
driver_name, (void *) &sha[j])) {
printk("%s: unable to allocate IRQ %u, detaching.\n", name, irq);
......@@ -1016,12 +1075,40 @@ __initfunc (static void add_pci_ports(void)) {
#if defined(CONFIG_PCI)
unsigned short i = 0;
unsigned char bus, devfn;
unsigned int addr, k;
#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
struct pci_dev *dev = NULL;
if (!pci_present()) return;
for (k = 0; k < MAX_PCI; k++) {
if (!(dev = pci_find_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) break;
if (pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &addr)) continue;
#if defined(DEBUG_PCI_DETECT)
printk("%s: detect, seq. %d, bus %d, devfn 0x%x, addr 0x%x.\n",
driver_name, k, dev->bus->number, dev->devfn, addr);
#endif
if ((addr & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
continue;
/* Reverse the returned address order */
io_port[MAX_INT_PARAM + MAX_PCI - k] =
(addr & PCI_BASE_ADDRESS_IO_MASK) + PCI_BASE_ADDRESS_0;
}
#else /* else old style PCI code */
unsigned short i = 0;
unsigned char bus, devfn;
if (!pcibios_present()) return;
for (k = 0; k < MAX_PCI; k++) {
if (pcibios_find_class(PCI_CLASS_STORAGE_SCSI << 8, i++, &bus, &devfn)
......@@ -1030,7 +1117,7 @@ __initfunc (static void add_pci_ports(void)) {
if (pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &addr)
!= PCIBIOS_SUCCESSFUL) continue;
#if defined(DEBUG_DETECT)
#if defined(DEBUG_PCI_DETECT)
printk("%s: detect, seq. %d, bus %d, devfn 0x%x, addr 0x%x.\n",
driver_name, k, bus, devfn, addr);
#endif
......@@ -1042,7 +1129,10 @@ __initfunc (static void add_pci_ports(void)) {
io_port[MAX_INT_PARAM + MAX_PCI - k] =
(addr & PCI_BASE_ADDRESS_IO_MASK) + PCI_BASE_ADDRESS_0;
}
#endif
#endif /* end old style PCI code */
#endif /* end CONFIG_PCI */
return;
}
......@@ -1523,6 +1613,7 @@ static inline void reorder(unsigned int j, unsigned long cursec,
unsigned int input_only = TRUE, overlap = FALSE;
unsigned long sl[n_ready], pl[n_ready], ll[n_ready];
unsigned long maxsec = 0, minsec = ULONG_MAX, seek = 0, iseek = 0;
unsigned long ioseek = 0;
static unsigned int flushcount = 0, batchcount = 0, sortcount = 0;
static unsigned int readycount = 0, ovlcount = 0, inputcount = 0;
......@@ -1547,6 +1638,7 @@ static inline void reorder(unsigned int j, unsigned long cursec,
if (SCpnt->request.sector > maxsec) maxsec = SCpnt->request.sector;
sl[n] = SCpnt->request.sector;
ioseek += SCpnt->request.nr_sectors;
if (!n) continue;
......@@ -1568,6 +1660,8 @@ static inline void reorder(unsigned int j, unsigned long cursec,
if (cursec > ((maxsec + minsec) / 2)) rev = TRUE;
if (ioseek > ((maxsec - minsec) / 2)) rev = FALSE;
if (!((rev && r) || (!rev && s))) sort(sl, il, n_ready, rev);
if (!input_only) for (n = 0; n < n_ready; n++) {
......@@ -1644,8 +1738,7 @@ static void flush_dev(Scsi_Device *dev, unsigned long cursec, unsigned int j,
}
static void eata2x_interrupt_handler(int irq, void *shap,
struct pt_regs *regs) {
static inline void ihdlr(int irq, void *shap, struct pt_regs *regs) {
Scsi_Cmnd *SCpnt;
unsigned int i, j, k, c, status, tstatus, reg;
unsigned int n, n_ready, il[MAX_MAILBOXES];
......@@ -1703,7 +1796,8 @@ static void eata2x_interrupt_handler(int irq, void *shap,
else if (HD(j)->cp_stat[i] == IN_RESET)
printk("%s: ihdlr, mbox %d is in reset.\n", BN(j), i);
else if (HD(j)->cp_stat[i] != IN_USE)
panic("%s: ihdlr, mbox %d, invalid cp_stat.\n", BN(j), i);
panic("%s: ihdlr, mbox %d, invalid cp_stat: %d.\n",
BN(j), i, HD(j)->cp_stat[i]);
HD(j)->cp_stat[i] = FREE;
cpp = &HD(j)->cp[i];
......@@ -1841,6 +1935,22 @@ static void eata2x_interrupt_handler(int irq, void *shap,
return;
}
static void interrupt_handler(int irq, void *shap, struct pt_regs *regs) {
#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,95)
unsigned long flags;
spin_lock_irqsave(&io_request_lock, flags);
ihdlr(irq, shap, regs);
spin_unlock_irqrestore(&io_request_lock, flags);
#else
ihdlr(irq, shap, regs);
#endif
}
int eata2x_release(struct Scsi_Host *shpnt) {
unsigned long flags;
unsigned int i, j;
......
......@@ -5,6 +5,7 @@
#define _EATA_H
#include <scsi/scsicam.h>
#include <linux/version.h>
int eata2x_detect(Scsi_Host_Template *);
int eata2x_release(struct Scsi_Host *);
......@@ -12,7 +13,7 @@ int eata2x_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int eata2x_abort(Scsi_Cmnd *);
int eata2x_reset(Scsi_Cmnd *, unsigned int);
#define EATA_VERSION "4.02.00"
#define EATA_VERSION "4.04.00"
#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
......
/*
* u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters.
*
* 10 Apr 1998 rev. 4.04 for linux 2.0.33 and 2.1.95
* Improved SMP support (if linux version >= 2.1.95).
*
* 9 Apr 1998 rev. 4.03 for linux 2.0.33 and 2.1.94
* Performance improvement: when sequential i/o is detected,
* always use direct sort instead of reverse sort.
*
* 4 Apr 1998 rev. 4.02 for linux 2.0.33 and 2.1.92
* io_port is now unsigned long.
*
......@@ -266,11 +273,14 @@
* the driver sets host->wish_block = TRUE for all ISA boards.
*/
#include <linux/version.h>
#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
#define MAX_INT_PARAM 10
#if defined(MODULE)
#include <linux/module.h>
#include <linux/version.h>
#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,26)
MODULE_PARM(io_port, "1-" __MODULE_STRING(MAX_INT_PARAM) "i");
MODULE_PARM(linked_comm, "i");
......@@ -279,6 +289,7 @@ MODULE_PARM(link_statistics, "i");
MODULE_PARM(max_queue_depth, "i");
MODULE_AUTHOR("Dario Ballabio");
#endif
#endif
#include <linux/string.h>
......@@ -483,7 +494,7 @@ static unsigned long io_port[] __initdata = {
#define V2DEV(addr) ((addr) ? H2DEV(virt_to_bus((void *)addr)) : 0)
#define DEV2V(addr) ((addr) ? DEV2H(bus_to_virt((unsigned long)addr)) : 0)
static void u14_34f_interrupt_handler(int, void *, struct pt_regs *);
static void interrupt_handler(int, void *, struct pt_regs *);
static void flush_dev(Scsi_Device *, unsigned long, unsigned int, unsigned int);
static int do_trace = FALSE;
static int setup_done = FALSE;
......@@ -683,7 +694,7 @@ __initfunc (static inline int port_detect \
subversion = (in_byte & 0x0f);
/* Board detected, allocate its IRQ */
if (request_irq(irq, u14_34f_interrupt_handler,
if (request_irq(irq, interrupt_handler,
SA_INTERRUPT | ((subversion == ESA) ? SA_SHIRQ : 0),
driver_name, (void *) &sha[j])) {
printk("%s: unable to allocate IRQ %u, detaching.\n", name, irq);
......@@ -1309,6 +1320,7 @@ static inline void reorder(unsigned int j, unsigned long cursec,
unsigned int input_only = TRUE, overlap = FALSE;
unsigned long sl[n_ready], pl[n_ready], ll[n_ready];
unsigned long maxsec = 0, minsec = ULONG_MAX, seek = 0, iseek = 0;
unsigned long ioseek = 0;
static unsigned int flushcount = 0, batchcount = 0, sortcount = 0;
static unsigned int readycount = 0, ovlcount = 0, inputcount = 0;
......@@ -1333,6 +1345,7 @@ static inline void reorder(unsigned int j, unsigned long cursec,
if (SCpnt->request.sector > maxsec) maxsec = SCpnt->request.sector;
sl[n] = SCpnt->request.sector;
ioseek += SCpnt->request.nr_sectors;
if (!n) continue;
......@@ -1354,6 +1367,8 @@ static inline void reorder(unsigned int j, unsigned long cursec,
if (cursec > ((maxsec + minsec) / 2)) rev = TRUE;
if (ioseek > ((maxsec - minsec) / 2)) rev = FALSE;
if (!((rev && r) || (!rev && s))) sort(sl, il, n_ready, rev);
if (!input_only) for (n = 0; n < n_ready; n++) {
......@@ -1431,8 +1446,7 @@ static void flush_dev(Scsi_Device *dev, unsigned long cursec, unsigned int j,
}
}
static void u14_34f_interrupt_handler(int irq, void *shap,
struct pt_regs *regs) {
static inline void ihdlr(int irq, void *shap, struct pt_regs *regs) {
Scsi_Cmnd *SCpnt;
unsigned int i, j, k, c, status, tstatus, reg, ret;
struct mscp *spp;
......@@ -1479,7 +1493,8 @@ static void u14_34f_interrupt_handler(int irq, void *shap,
else if (HD(j)->cp_stat[i] == IN_RESET)
printk("%s: ihdlr, mbox %d is in reset.\n", BN(j), i);
else if (HD(j)->cp_stat[i] != IN_USE)
panic("%s: ihdlr, mbox %d, invalid cp_stat.\n", BN(j), i);
panic("%s: ihdlr, mbox %d, invalid cp_stat: %d.\n",
BN(j), i, HD(j)->cp_stat[i]);
HD(j)->cp_stat[i] = FREE;
SCpnt = spp->SCpnt;
......@@ -1610,6 +1625,22 @@ static void u14_34f_interrupt_handler(int irq, void *shap,
return;
}
static void interrupt_handler(int irq, void *shap, struct pt_regs *regs) {
#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,95)
unsigned long flags;
spin_lock_irqsave(&io_request_lock, flags);
ihdlr(irq, shap, regs);
spin_unlock_irqrestore(&io_request_lock, flags);
#else
ihdlr(irq, shap, regs);
#endif
}
int u14_34f_release(struct Scsi_Host *shpnt) {
unsigned long flags;
unsigned int i, j;
......
......@@ -4,6 +4,8 @@
#ifndef _U14_34F_H
#define _U14_34F_H
#include <linux/version.h>
int u14_34f_detect(Scsi_Host_Template *);
int u14_34f_release(struct Scsi_Host *);
int u14_34f_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
......@@ -11,7 +13,7 @@ int u14_34f_abort(Scsi_Cmnd *);
int u14_34f_reset(Scsi_Cmnd *, unsigned int);
int u14_34f_biosparam(Disk *, kdev_t, int *);
#define U14_34F_VERSION "4.02.00"
#define U14_34F_VERSION "4.04.00"
#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
......
......@@ -215,7 +215,12 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
return x;
}
#define mb() __asm__ __volatile__ ("" : : :"memory")
/*
* Force strict CPU ordering.
* And yes, this is required on UP too when we're talking
* to devices.
*/
#define mb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")
/* interrupt control.. */
#define __sti() __asm__ __volatile__ ("sti": : :"memory")
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment