ia64/xen-unstable

changeset 1253:34aaad33c28d

bitkeeper revision 1.825.3.14 (40683680NZjB1f8PmpgffnMdcNdBjQ)

Many files:
Final IRQ and PCI-access virtualisation fixes.
author kaf24@scramble.cl.cam.ac.uk
date Mon Mar 29 14:45:20 2004 +0000 (2004-03-29)
parents 771b47a23e3d
children 0d13d6c5ab80 f293c0d41be2
files xen/arch/i386/irq.c xen/common/event_channel.c xen/common/physdev.c xen/include/hypervisor-ifs/event_channel.h xen/include/xen/irq.h xen/include/xen/sched.h xenolinux-2.4.25-sparse/arch/xen/Makefile xenolinux-2.4.25-sparse/arch/xen/defconfig-physdev xenolinux-2.4.25-sparse/arch/xen/kernel/evtchn.c xenolinux-2.4.25-sparse/arch/xen/kernel/irq.c
line diff
     1.1 --- a/xen/arch/i386/irq.c	Sun Mar 28 20:22:50 2004 +0000
     1.2 +++ b/xen/arch/i386/irq.c	Mon Mar 29 14:45:20 2004 +0000
     1.3 @@ -941,8 +941,9 @@ int setup_irq(unsigned int irq, struct i
     1.4  
     1.5  #define IRQ_MAX_GUESTS 7
     1.6  typedef struct {
     1.7 -    unsigned short nr_guests;
     1.8 -    unsigned short in_flight;
     1.9 +    u8 nr_guests;
    1.10 +    u8 in_flight;
    1.11 +    u8 shareable;
    1.12      struct task_struct *guest[IRQ_MAX_GUESTS];
    1.13  } irq_guest_action_t;
    1.14  
    1.15 @@ -989,7 +990,7 @@ int pirq_guest_unmask(struct task_struct
    1.16      return 0;
    1.17  }
    1.18  
    1.19 -int pirq_guest_bind(struct task_struct *p, int irq)
    1.20 +int pirq_guest_bind(struct task_struct *p, int irq, int will_share)
    1.21  {
    1.22      unsigned long flags;
    1.23      irq_desc_t *desc = &irq_desc[irq];
    1.24 @@ -1001,6 +1002,8 @@ int pirq_guest_bind(struct task_struct *
    1.25  
    1.26      spin_lock_irqsave(&desc->lock, flags);
    1.27  
    1.28 +    action = (irq_guest_action_t *)desc->action;
    1.29 +
    1.30      if ( !(desc->status & IRQ_GUEST) )
    1.31      {
    1.32          rc = -EBUSY;
    1.33 @@ -1021,14 +1024,19 @@ int pirq_guest_bind(struct task_struct *
    1.34  
    1.35          action->nr_guests = 0;
    1.36          action->in_flight = 0;
    1.37 +        action->shareable = will_share;
    1.38          
    1.39          desc->depth = 0;
    1.40          desc->status |= IRQ_GUEST;
    1.41          desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING);
    1.42          desc->handler->startup(irq);
    1.43      }
    1.44 -
    1.45 -    action = (irq_guest_action_t *)desc->action;
    1.46 +    else if ( !will_share || !action->shareable )
    1.47 +    {
    1.48 +        DPRINTK("Cannot bind IRQ %d to guest. Will not share with others.\n");
    1.49 +        rc = -EBUSY;
    1.50 +        goto out;
    1.51 +    }
    1.52  
    1.53      rc = -EBUSY;
    1.54      if ( action->nr_guests == IRQ_MAX_GUESTS )
     2.1 --- a/xen/common/event_channel.c	Sun Mar 28 20:22:50 2004 +0000
     2.2 +++ b/xen/common/event_channel.c	Mon Mar 29 14:45:20 2004 +0000
     2.3 @@ -194,7 +194,9 @@ static long evtchn_bind_pirq(evtchn_bind
     2.4          goto out;
     2.5  
     2.6      p->pirq_to_evtchn[pirq] = port;
     2.7 -    if ( (rc = pirq_guest_bind(p, pirq)) != 0 )
     2.8 +    rc = pirq_guest_bind(p, pirq, 
     2.9 +                         !!(bind->flags & BIND_PIRQ__WILL_SHARE));
    2.10 +    if ( rc != 0 )
    2.11      {
    2.12          p->pirq_to_evtchn[pirq] = 0;
    2.13          DPRINTK("Couldn't bind to PIRQ %d (error=%d)\n", pirq, rc);
     3.1 --- a/xen/common/physdev.c	Sun Mar 28 20:22:50 2004 +0000
     3.2 +++ b/xen/common/physdev.c	Mon Mar 29 14:45:20 2004 +0000
     3.3 @@ -6,33 +6,18 @@
     3.4   * 
     3.5   * Description: allows a domain to access devices on the PCI bus
     3.6   *
     3.7 - * a guest os may be given access to particular devices on the PCI
     3.8 - * bus. to allow the standard PCI device discovery to work it may
     3.9 - * also have limited access to devices (bridges) in the PCI device
    3.10 - * tree between the device and the PCI root device.
    3.11 - *
    3.12 - * for each domain a list of PCI devices is maintained, describing the
    3.13 + * A guest OS may be given access to particular devices on the PCI bus.
    3.14 + * For each domain a list of PCI devices is maintained, describing the
    3.15   * access mode for the domain. 
    3.16   *
    3.17 - * guests can figure out the virtualised, or better, partioned PCI space
    3.18 - * through normal pci config register access. Some of the accesses, in
    3.19 - * particular write access are faked out. For example the sequence for
    3.20 - * for detecting the IO regions, which require writes to determine the
    3.21 - * size of teh region, is faked out by a very simple state machine, 
    3.22 - * preventing direct writes to the PCI config registers by a guest.
    3.23 - *
    3.24 - * Interrupt handling is currently done in a very cheese fashion.
    3.25 - * We take the default irq controller code and replace it with our own.
    3.26 - * If an interrupt comes in it is acked using the PICs normal routine. Then
    3.27 - * an event is send to the receiving domain which has to explicitly call
    3.28 - * once it is finished dealing with the interrupt. Only then the PICs end
    3.29 - * handler is called. very cheesy with all sorts of problems but it seems 
    3.30 - * to work in normal cases. No shared interrupts are allowed.
    3.31 - *
    3.32 - * XXX this code is not SMP safe at the moment!
    3.33 + * Guests can figure out the virtualised PCI space through normal PCI config
    3.34 + * register access. Some of the accesses, in particular write accesses, are
    3.35 + * faked. For example the sequence for detecting the IO regions, which requires
    3.36 + * writes to determine the size of the region, is faked out by a very simple
    3.37 + * state machine, preventing direct writes to the PCI config registers by a
    3.38 + * guest.
    3.39   */
    3.40  
    3.41 -
    3.42  #include <xen/config.h>
    3.43  #include <xen/lib.h>
    3.44  #include <xen/types.h>
    3.45 @@ -47,22 +32,29 @@
    3.46  /* Called by PHYSDEV_PCI_INITIALISE_DEVICE to finalise IRQ routing. */
    3.47  extern void pcibios_enable_irq(struct pci_dev *dev);
    3.48  
    3.49 -#if 1
    3.50 -#define DBG(_x...)
    3.51 +#if 0
    3.52 +#define VERBOSE_INFO(_f, _a...) printk( _f , ## _a )
    3.53  #else
    3.54 -#define DBG(_x...) printk(_x)
    3.55 +#define VERBOSE_INFO(_f, _a...) ((void)0)
    3.56  #endif
    3.57  
    3.58 +#if 1 || !defined(NDEBUG)
    3.59 +#define INFO(_f, _a...) printk( _f, ## _a )
    3.60 +#else
    3.61 +#define INFO(_f, _a...) ((void)0)
    3.62 +#endif
    3.63 +
    3.64 +
    3.65  #define ACC_READ  1
    3.66  #define ACC_WRITE 2
    3.67  
    3.68 -/* upper bounds for PCI  devices */
    3.69 +/* Upper bounds for PCI-device addressing. */
    3.70  #define PCI_BUSMAX  255
    3.71  #define PCI_DEVMAX   31
    3.72  #define PCI_FUNCMAX   7
    3.73  #define PCI_REGMAX  255
    3.74  
    3.75 -/* bit offsets into state */
    3.76 +/* Bit offsets into state. */
    3.77  #define ST_BASE_ADDRESS  0   /* bits 0-5: are for base address access */
    3.78  #define ST_ROM_ADDRESS   6   /* bit 6: is for rom address access */    
    3.79  
    3.80 @@ -75,13 +67,7 @@ typedef struct _phys_dev_st {
    3.81  } phys_dev_t;
    3.82  
    3.83  
    3.84 -/*
    3.85 - * 
    3.86 - * General functions
    3.87 - * 
    3.88 - */
    3.89 -
    3.90 -/* find a device on the device list */
    3.91 +/* Find a device on a per-domain device list. */
    3.92  static phys_dev_t *find_pdev(struct task_struct *p, struct pci_dev *dev)
    3.93  {
    3.94      phys_dev_t *t, *res = NULL;
    3.95 @@ -99,24 +85,22 @@ static phys_dev_t *find_pdev(struct task
    3.96      return res;
    3.97  }
    3.98  
    3.99 -/* add the device to the list of devices task p can access */
   3.100 +/* Add a device to a per-domain device-access list. */
   3.101  static void add_dev_to_task(struct task_struct *p, 
   3.102                              struct pci_dev *dev, int acc)
   3.103  {
   3.104 -    
   3.105      phys_dev_t *pdev;
   3.106      
   3.107      if ( (pdev = find_pdev(p, dev)) )
   3.108      {
   3.109 -        /* device already on list, update access  */
   3.110 +        /* Sevice already on list: update access permissions. */
   3.111          pdev->flags = acc;
   3.112          return;
   3.113      }
   3.114  
   3.115 -    /* add device */
   3.116      if ( !(pdev = kmalloc(sizeof(phys_dev_t), GFP_KERNEL)) )
   3.117      {
   3.118 -        printk("error allocating pdev structure\n");
   3.119 +        INFO("Error allocating pdev structure.\n");
   3.120          return;
   3.121      }
   3.122      
   3.123 @@ -127,7 +111,6 @@ static void add_dev_to_task(struct task_
   3.124  
   3.125      if ( acc == ACC_WRITE )
   3.126          pdev->owner = p;
   3.127 -
   3.128  }
   3.129  
   3.130  /*
   3.131 @@ -151,11 +134,11 @@ int physdev_pci_access_modify(
   3.132  
   3.133      if ( !enable )
   3.134      {
   3.135 -        DPRINTK("Disallowing access is not yet supported.\n");
   3.136 +        INFO("Disallowing access is not yet supported.\n");
   3.137          return -EINVAL;
   3.138      }
   3.139  
   3.140 -    DPRINTK("physdev_pci_access_modify: %02x:%02x:%02x\n", bus, dev, func);
   3.141 +    INFO("physdev_pci_access_modify: %02x:%02x:%02x\n", bus, dev, func);
   3.142  
   3.143      if ( (p = find_domain_by_id(dom)) == NULL ) 
   3.144          return -ESRCH;
   3.145 @@ -166,36 +149,36 @@ int physdev_pci_access_modify(
   3.146      /* Grant write access to the specified device. */
   3.147      if ( (pdev = pci_find_slot(bus, PCI_DEVFN(dev, func))) == NULL )
   3.148      {
   3.149 -        DPRINTK("  dev does not exist\n");
   3.150 +        INFO("  dev does not exist\n");
   3.151          return -ENODEV;
   3.152      }
   3.153      add_dev_to_task(p, pdev, ACC_WRITE);
   3.154 -    DPRINTK("  add RW %02x:%02x:%02x\n", pdev->bus->number,
   3.155 -            PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
   3.156 +    INFO("  add RW %02x:%02x:%02x\n", pdev->bus->number,
   3.157 +         PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
   3.158  
   3.159  
   3.160      /* Grant read access to the root device. */
   3.161      if ( (rdev = pci_find_slot(0, PCI_DEVFN(0, 0))) == NULL )
   3.162      {
   3.163 -        DPRINTK("  bizarre -- no PCI root dev\n");
   3.164 +        INFO("  bizarre -- no PCI root dev\n");
   3.165          return -ENODEV;
   3.166      }
   3.167      add_dev_to_task(p, rdev, ACC_READ);
   3.168 -    DPRINTK("  add R0 %02x:%02x:%02x\n", 0, 0, 0);
   3.169 +    INFO("  add R0 %02x:%02x:%02x\n", 0, 0, 0);
   3.170  
   3.171      /* Grant read access to all devices on the path to the root. */
   3.172      for ( tdev = pdev->bus->self; tdev != NULL; tdev = tdev->bus->self )
   3.173      {
   3.174          add_dev_to_task(p, tdev, ACC_READ);
   3.175 -        DPRINTK("  add RO %02x:%02x:%02x\n", tdev->bus->number,
   3.176 -                PCI_SLOT(tdev->devfn), PCI_FUNC(tdev->devfn));
   3.177 +        INFO("  add RO %02x:%02x:%02x\n", tdev->bus->number,
   3.178 +             PCI_SLOT(tdev->devfn), PCI_FUNC(tdev->devfn));
   3.179      }
   3.180  
   3.181      if ( pdev->hdr_type == PCI_HEADER_TYPE_NORMAL )
   3.182          return 0;
   3.183      
   3.184 -    /* The  device is a bridge or cardbus. */
   3.185 -    printk("XXX can't give access to bridge devices yet\n");
   3.186 +    /* The device is a bridge or cardbus. */
   3.187 +    INFO("XXX can't give access to bridge devices yet\n");
   3.188  
   3.189      return 0;
   3.190  }
   3.191 @@ -217,15 +200,15 @@ inline static int check_dev_acc (struct 
   3.192      if ( bus > PCI_BUSMAX || dev > PCI_DEVMAX || func > PCI_FUNCMAX )
   3.193          return -EINVAL;
   3.194  
   3.195 -    DBG("a=%c b=%x d=%x f=%x ", (acc == ACC_READ) ? 'R' : 'W',
   3.196 -        mask, bus, dev, func);
   3.197 +    VERBOSE_INFO("a=%c b=%x d=%x f=%x ", (acc == ACC_READ) ? 'R' : 'W',
   3.198 +                 mask, bus, dev, func);
   3.199  
   3.200      /* check target device */
   3.201      target_devfn = PCI_DEVFN(dev, func);
   3.202      target_dev   = pci_find_slot(bus, target_devfn);
   3.203      if ( !target_dev )
   3.204      {
   3.205 -        DBG("target does not exist\n");
   3.206 +        VERBOSE_INFO("target does not exist\n");
   3.207          return -ENODEV;
   3.208      }
   3.209  
   3.210 @@ -233,7 +216,7 @@ inline static int check_dev_acc (struct 
   3.211      target_pdev = find_pdev(p, target_dev);
   3.212      if ( !target_pdev )
   3.213      {
   3.214 -        DBG("dom has no access to target\n");
   3.215 +        VERBOSE_INFO("dom has no access to target\n");
   3.216          return -EPERM;
   3.217      }
   3.218  
   3.219 @@ -241,11 +224,6 @@ inline static int check_dev_acc (struct 
   3.220      return 0;
   3.221  }
   3.222  
   3.223 -/*
   3.224 - * 
   3.225 - * PCI config space access
   3.226 - * 
   3.227 - */
   3.228  
   3.229  /*
   3.230   * Base address registers contain the base address for IO regions.
   3.231 @@ -266,60 +244,58 @@ inline static int check_dev_acc (struct 
   3.232   * cleared again. If the guest attempts to "restores" a wrong value an
   3.233   * error is flagged.
   3.234   */
   3.235 -static int do_base_address_access(phys_dev_t *pdev, int acc,
   3.236 -                                  int bus, int dev, int func, 
   3.237 -                                  int reg, int len, u32 *val)
   3.238 +static int do_base_address_access(phys_dev_t *pdev, int acc, int idx, 
   3.239 +                                  int len, u32 *val)
   3.240  {
   3.241 -    int idx, st_bit, ret = -EINVAL;
   3.242 +    int st_bit, reg = PCI_BASE_ADDRESS_0 + (idx*4), ret = -EINVAL;
   3.243 +    struct pci_dev *dev = pdev->dev;
   3.244      u32 orig_val, sz;
   3.245      struct resource *res;
   3.246  
   3.247 -    idx    = (reg - PCI_BASE_ADDRESS_0)/4;
   3.248 +    if ( len != sizeof(u32) )
   3.249 +    {
   3.250 +        INFO("Guest attempting sub-dword %s to BASE_ADDRESS %d\n", 
   3.251 +             (acc == ACC_READ) ? "read" : "write", idx);
   3.252 +        return -EPERM;
   3.253 +    }
   3.254 +
   3.255      st_bit = idx + ST_BASE_ADDRESS;
   3.256      res    = &(pdev->dev->resource[idx]);
   3.257  
   3.258      if ( acc == ACC_WRITE )
   3.259      {
   3.260 -        if ( *val == 0xffffffff || 
   3.261 -             ((res->flags & IORESOURCE_IO) && *val == 0xffff) )
   3.262 +        if ( (*val == 0xffffffff) || 
   3.263 +             ((res->flags & IORESOURCE_IO) && (*val == 0xffff)) )
   3.264          {
   3.265 -            /* set bit and return */
   3.266 +            /* Set bit and return. */
   3.267              set_bit(st_bit, &pdev->state);
   3.268              ret = 0;
   3.269          }
   3.270          else
   3.271          {
   3.272 -            /* assume guest wants to set the base address */
   3.273 +            /* Assume guest wants to set the base address. */
   3.274              clear_bit(st_bit, &pdev->state);
   3.275  
   3.276              /* check if guest tries to restore orig value */
   3.277 -            ret = pci_config_read(0, bus, dev, func, reg, len, &orig_val);
   3.278 -            if ( *val != orig_val ) 
   3.279 +            ret = pci_read_config_dword(dev, reg, &orig_val);
   3.280 +            if ( (ret == 0) && (*val != orig_val) ) 
   3.281              {
   3.282 -                printk("caution: guest tried to change base address range.\n");
   3.283 +                INFO("Guest attempting update to BASE_ADDRESS %d\n", idx);
   3.284                  ret = -EPERM;
   3.285              }
   3.286          }
   3.287 -        DBG("fixed pci write: %02x:%02x:%02x reg=0x%02x len=0x%02x"
   3.288 -            " val=0x%08x %lx\n", bus, dev, func, reg, len, *val,
   3.289 -            pdev->state);
   3.290 -
   3.291 +        VERBOSE_INFO("fixed pci write: %02x:%02x:%02x reg=0x%02x len=0x%02x"
   3.292 +                     " val=0x%08x %lx\n", 
   3.293 +                     dev->bus->number, PCI_SLOT(dev->devfn), 
   3.294 +                     PCI_FUNC(dev->devfn), reg, len, *val, pdev->state);
   3.295      }
   3.296 -
   3.297      else if ( acc == ACC_READ )
   3.298      {
   3.299 -        if ( !test_bit(st_bit, &pdev->state) )
   3.300 +        ret = pci_read_config_dword(dev, reg, val);
   3.301 +        if ( (ret == 0) && test_bit(st_bit, &pdev->state) )
   3.302          {
   3.303 -            /* just read and return */
   3.304 -            ret = pci_config_read(0, bus, dev, func, reg, len, val);
   3.305 -        }
   3.306 -        else
   3.307 -        {
   3.308 -            /* fake value */
   3.309 -            ret = pci_config_read(0, bus, dev, func, reg, len, &orig_val);
   3.310 -
   3.311 +            /* Cook the value. */
   3.312              sz  = res->end - res->start;
   3.313 -
   3.314              if ( res->flags & IORESOURCE_MEM )
   3.315              {
   3.316                  /* this is written out explicitly for clarity */
   3.317 @@ -344,77 +320,75 @@ static int do_base_address_access(phys_d
   3.318                  *val = *val & (sz << 2);
   3.319                  *val = *val | 0x1;
   3.320              }
   3.321 -            ret = 0;
   3.322          }
   3.323 -        DBG("fixed pci read : %02x:%02x:%02x reg=0x%02x len=0x%02x"
   3.324 -            " val=0x%08x %lx\n", bus, dev, func, reg, len, *val, pdev->state);
   3.325 +        VERBOSE_INFO("fixed pci read: %02x:%02x:%02x reg=0x%02x len=0x%02x"
   3.326 +                     " val=0x%08x %lx\n", 
   3.327 +                     dev->bus->number, PCI_SLOT(dev->devfn), 
   3.328 +                     PCI_FUNC(dev->devfn), reg, len, *val, pdev->state);
   3.329      }
   3.330  
   3.331      return ret;
   3.332  }
   3.333  
   3.334 -/*
   3.335 - * fake out read/write access to rom address register
   3.336 - * pretty much the same as a above
   3.337 - */
   3.338 -static int do_rom_address_access(phys_dev_t *pdev, int acc,
   3.339 -                                 int bus, int dev, int func, 
   3.340 -                                 int reg, int len, u32 *val)
   3.341 +
   3.342 +static int do_rom_address_access(phys_dev_t *pdev, int acc, int len, u32 *val)
   3.343  {
   3.344      int st_bit, ret = -EINVAL;
   3.345 +    struct pci_dev *dev = pdev->dev;
   3.346      u32 orig_val, sz;
   3.347      struct resource *res;
   3.348  
   3.349 +    if ( len != sizeof(u32) )
   3.350 +    {
   3.351 +        INFO("Guest attempting sub-dword %s to ROM_ADDRESS\n", 
   3.352 +             (acc == ACC_READ) ? "read" : "write");
   3.353 +        return -EPERM;
   3.354 +    }
   3.355 +
   3.356      st_bit = ST_ROM_ADDRESS;
   3.357      res = &(pdev->dev->resource[PCI_ROM_RESOURCE]);
   3.358  
   3.359      if ( acc == ACC_WRITE )
   3.360      {
   3.361 -        if ( *val == 0xffffffff || *val == 0xfffffffe)
   3.362 +        if ( (*val == 0xffffffff) || (*val == 0xfffffffe) )
   3.363          {
   3.364 -            /* 0xffffffff would be unusual, but we check anyway */
   3.365 -            /* set bit and return */
   3.366 +            /* NB. 0xffffffff would be unusual, but we trap it anyway. */
   3.367              set_bit(st_bit, &pdev->state);
   3.368              ret = 0;
   3.369          }
   3.370          else
   3.371          {
   3.372 -            /* assume guest wants to set the base address */
   3.373 +            /* Assume guest wants simply to set the base address. */
   3.374              clear_bit(st_bit, &pdev->state);
   3.375              
   3.376 -            /* check if guest tries to restore orig value */
   3.377 -            ret = pci_config_read(0, bus, dev, func, reg, len, &orig_val);
   3.378 -            if ( (*val != orig_val) ) 
   3.379 +            /* Check if guest tries to restore the original value. */
   3.380 +            ret = pci_read_config_dword(dev, PCI_ROM_ADDRESS, &orig_val);
   3.381 +            if ( (ret == 0) && (*val != orig_val) ) 
   3.382              {
   3.383 -                if (*val != 0x00000000 )
   3.384 +                if ( (*val != 0x00000000) )
   3.385                  {
   3.386 -                    printk("caution: guest tried to change rom address.\n");
   3.387 +                    INFO("caution: guest tried to change rom address.\n");
   3.388                      ret = -EPERM;
   3.389                  }
   3.390                  else
   3.391                  {
   3.392 -                    printk ("guest disabled rom access for %02x:%02x:%02x\n",
   3.393 -                            bus, dev, func);
   3.394 -                    ret = 0;
   3.395 +                    INFO("guest disabled rom access for %02x:%02x:%02x\n",
   3.396 +                         dev->bus->number, PCI_SLOT(dev->devfn), 
   3.397 +                         PCI_FUNC(dev->devfn));
   3.398                  }
   3.399              }
   3.400 -
   3.401          }
   3.402 -        DBG("fixed pci write: %02x:%02x:%02x reg=0x%02x len=0x%02x"
   3.403 -            " val=0x%08x %lx\n", bus, dev, func, reg, len, *val, pdev->state);
   3.404 -     
   3.405 +        VERBOSE_INFO("fixed pci write: %02x:%02x:%02x reg=0x%02x len=0x%02x"
   3.406 +                     " val=0x%08x %lx\n", 
   3.407 +                     dev->bus->number, PCI_SLOT(dev->devfn), 
   3.408 +                     PCI_FUNC(dev->devfn), reg, len, *val, pdev->state);
   3.409      }
   3.410      else if ( acc == ACC_READ )
   3.411      {
   3.412 -       if ( !test_bit(st_bit, &pdev->state) )
   3.413 +        ret = pci_read_config_dword(dev, PCI_ROM_ADDRESS, val);
   3.414 +        if ( (ret == 0) && test_bit(st_bit, &pdev->state) )
   3.415          {
   3.416 -            /* just read and return */
   3.417 -            ret = pci_config_read(0, bus, dev, func, reg, len, val);
   3.418 -        }
   3.419 -        else
   3.420 -        {
   3.421 -            /* fake value */
   3.422 -            ret = pci_config_read(0, bus, dev, func, reg, len, &orig_val);
   3.423 +            /* Cook the value. */
   3.424              sz  = res->end - res->start;
   3.425              *val = 0xffffffff;
   3.426              /* leave bit 0 untouched */
   3.427 @@ -424,19 +398,18 @@ static int do_rom_address_access(phys_de
   3.428              *val = *val & (sz << 11);
   3.429              *val = *val | (orig_val & 0x1);
   3.430          }
   3.431 +        VERBOSE_INFO("fixed pci read: %02x:%02x:%02x reg=0x%02x len=0x%02x"
   3.432 +                     " val=0x%08x %lx\n", 
   3.433 +                     dev->bus->number, PCI_SLOT(dev->devfn), 
   3.434 +                     PCI_FUNC(dev->devfn), reg, len, *val, pdev->state);
   3.435 +    }
   3.436  
   3.437 -        DBG("fixed pci read : %02x:%02x:%02x reg=0x%02x len=0x%02x"
   3.438 -            " val=0x%08x %lx\n", bus, dev, func, reg, len, *val, pdev->state);
   3.439 -    }
   3.440      return ret;
   3.441  
   3.442  }
   3.443  
   3.444  /*
   3.445 - * handle a domains pci config space read access if it has access to
   3.446 - * the device.
   3.447 - * For some registers for read-only devices (e.g. address base registers)
   3.448 - * we need to maintain a state machine.
   3.449 + * Handle a PCI config space read access if the domain has access privileges.
   3.450   */
   3.451  static long pci_cfgreg_read(int bus, int dev, int func, int reg,
   3.452                              int len, u32 *val)
   3.453 @@ -451,39 +424,51 @@ static long pci_cfgreg_read(int bus, int
   3.454      switch ( reg )
   3.455      {
   3.456      case PCI_BASE_ADDRESS_0:
   3.457 +        ret = do_base_address_access(pdev, ACC_READ, 0, len, val);
   3.458 +        break;
   3.459 +
   3.460      case PCI_BASE_ADDRESS_1:
   3.461 +        ret = do_base_address_access(pdev, ACC_READ, 1, len, val);
   3.462 +        break;
   3.463 +
   3.464      case PCI_BASE_ADDRESS_2:
   3.465 +        ret = do_base_address_access(pdev, ACC_READ, 2, len, val);
   3.466 +        break;
   3.467 +
   3.468      case PCI_BASE_ADDRESS_3:
   3.469 +        ret = do_base_address_access(pdev, ACC_READ, 3, len, val);
   3.470 +        break;
   3.471 +
   3.472      case PCI_BASE_ADDRESS_4:
   3.473 +        ret = do_base_address_access(pdev, ACC_READ, 4, len, val);
   3.474 +        break;
   3.475 +
   3.476      case PCI_BASE_ADDRESS_5:
   3.477 -        ret = do_base_address_access(pdev, ACC_READ, bus, dev, 
   3.478 -                                     func, reg, len, val);
   3.479 +        ret = do_base_address_access(pdev, ACC_READ, 5, len, val);
   3.480          break;
   3.481  
   3.482      case PCI_ROM_ADDRESS:
   3.483 -        ret = do_rom_address_access(pdev, ACC_READ, bus, dev, 
   3.484 -                                    func, reg, len, val);
   3.485 +        ret = do_rom_address_access(pdev, ACC_READ, len, val);
   3.486          break;        
   3.487  
   3.488      case PCI_INTERRUPT_LINE:
   3.489 -        ret = pdev->dev->irq;
   3.490 +        *val = pdev->dev->irq;
   3.491 +        ret = 0;
   3.492          break;
   3.493  
   3.494      default:
   3.495          ret = pci_config_read(0, bus, dev, func, reg, len, val);        
   3.496 -        DBG("pci read : %02x:%02x:%02x reg=0x%02x len=0x%02x val=0x%08x\n",
   3.497 -            bus, dev, func, reg, len, *val);
   3.498 +        VERBOSE_INFO("pci read : %02x:%02x:%02x reg=0x%02x len=0x%02x "
   3.499 +                     "val=0x%08x\n", bus, dev, func, reg, len, *val);
   3.500          break;
   3.501      }
   3.502  
   3.503      return ret;
   3.504  }
   3.505  
   3.506 +
   3.507  /*
   3.508 - * handle a domains pci config space write accesses if it has access to
   3.509 - * the device.
   3.510 - * for some registers a state machine is maintained to fake out r/w access.
   3.511 - * By default no write access is allowed but we may change that in the future.
   3.512 + * Handle a PCI config space write access if the domain has access privileges.
   3.513   */
   3.514  static long pci_cfgreg_write(int bus, int dev, int func, int reg,
   3.515                               int len, u32 val)
   3.516 @@ -498,35 +483,46 @@ static long pci_cfgreg_write(int bus, in
   3.517      switch (reg)
   3.518      {
   3.519      case PCI_BASE_ADDRESS_0:
   3.520 +        ret = do_base_address_access(pdev, ACC_WRITE, 0, len, &val);
   3.521 +        break;
   3.522 +
   3.523      case PCI_BASE_ADDRESS_1:
   3.524 +        ret = do_base_address_access(pdev, ACC_WRITE, 1, len, &val);
   3.525 +        break;
   3.526 +
   3.527      case PCI_BASE_ADDRESS_2:
   3.528 +        ret = do_base_address_access(pdev, ACC_WRITE, 2, len, &val);
   3.529 +        break;
   3.530 +
   3.531      case PCI_BASE_ADDRESS_3:
   3.532 +        ret = do_base_address_access(pdev, ACC_WRITE, 3, len, &val);
   3.533 +        break;
   3.534 +
   3.535      case PCI_BASE_ADDRESS_4:
   3.536 +        ret = do_base_address_access(pdev, ACC_WRITE, 4, len, &val);
   3.537 +        break;
   3.538 +
   3.539      case PCI_BASE_ADDRESS_5:
   3.540 -        ret = do_base_address_access (pdev, ACC_WRITE, bus, dev, 
   3.541 -                                      func, reg, len, &val);
   3.542 -        return ret;
   3.543 +        ret = do_base_address_access(pdev, ACC_WRITE, 5, len, &val);
   3.544          break;
   3.545  
   3.546      case PCI_ROM_ADDRESS:
   3.547 -        ret = do_rom_address_access (pdev, ACC_WRITE, bus, dev, 
   3.548 -                                      func, reg, len, &val);
   3.549 -        return ret;
   3.550 +        ret = do_rom_address_access(pdev, ACC_WRITE, len, &val);
   3.551          break;        
   3.552  
   3.553      default:
   3.554          if ( pdev->flags != ACC_WRITE ) 
   3.555          {
   3.556 -            printk("pci write not allowed %02x:%02x:%02x: "
   3.557 -                   "reg=0x%02x len=0x%02x val=0x%08x\n",
   3.558 -                   bus, dev, func, reg, len, val);
   3.559 +            INFO("pci write not allowed %02x:%02x:%02x: "
   3.560 +                 "reg=0x%02x len=0x%02x val=0x%08x\n",
   3.561 +                 bus, dev, func, reg, len, val);
   3.562              ret = -EPERM;
   3.563          }
   3.564          else
   3.565          {
   3.566              ret = pci_config_write(0, bus, dev, func, reg, len, val);
   3.567 -            DBG("pci write: %02x:%02x:%02x reg=0x%02x len=0x%02x val=0x%08x\n",
   3.568 -                bus, dev, func, reg, len, val);
   3.569 +            VERBOSE_INFO("pci write: %02x:%02x:%02x reg=0x%02x len=0x%02x "
   3.570 +                         "val=0x%08x\n", bus, dev, func, reg, len, val);
   3.571          }
   3.572          break;
   3.573      }
   3.574 @@ -617,11 +613,13 @@ void physdev_init_dom0(struct task_struc
   3.575      struct pci_dev *dev;
   3.576      phys_dev_t *pdev;
   3.577  
   3.578 -    printk("Give DOM0 read access to all PCI devices\n");
   3.579 +    INFO("Give DOM0 read access to all PCI devices\n");
   3.580  
   3.581      pci_for_each_dev(dev)
   3.582      {
   3.583 -        /* add device */
   3.584 +        /* Skip bridges and other peculiarities for now. */
   3.585 +        if ( dev->hdr_type != PCI_HEADER_TYPE_NORMAL )
   3.586 +            continue;
   3.587          pdev = kmalloc(sizeof(phys_dev_t), GFP_KERNEL);
   3.588          pdev->dev = dev;
   3.589          pdev->flags = ACC_WRITE;
     4.1 --- a/xen/include/hypervisor-ifs/event_channel.h	Sun Mar 28 20:22:50 2004 +0000
     4.2 +++ b/xen/include/hypervisor-ifs/event_channel.h	Mon Mar 29 14:45:20 2004 +0000
     4.3 @@ -50,6 +50,8 @@ typedef struct evtchn_bind_pirq
     4.4  {
     4.5      /* IN parameters. */
     4.6      int pirq;
     4.7 +#define BIND_PIRQ__WILL_SHARE 1
     4.8 +    unsigned int flags; /* BIND_PIRQ__* */
     4.9      /* OUT parameters. */
    4.10      int port;
    4.11  } evtchn_bind_pirq_t;
     5.1 --- a/xen/include/xen/irq.h	Sun Mar 28 20:22:50 2004 +0000
     5.2 +++ b/xen/include/xen/irq.h	Mon Mar 29 14:45:20 2004 +0000
     5.3 @@ -59,7 +59,7 @@ extern void no_action(int cpl, void *dev
     5.4  
     5.5  struct task_struct;
     5.6  extern int pirq_guest_unmask(struct task_struct *p);
     5.7 -extern int pirq_guest_bind(struct task_struct *p, int irq);
     5.8 +extern int pirq_guest_bind(struct task_struct *p, int irq, int will_share);
     5.9  extern int pirq_guest_unbind(struct task_struct *p, int irq);
    5.10  
    5.11  #endif /* __XEN_IRQ_H__ */
     6.1 --- a/xen/include/xen/sched.h	Sun Mar 28 20:22:50 2004 +0000
     6.2 +++ b/xen/include/xen/sched.h	Mon Mar 29 14:45:20 2004 +0000
     6.3 @@ -164,7 +164,7 @@ struct task_struct
     6.4       * domain's event-channel spinlock. Read accesses can also synchronise on 
     6.5       * the lock, but races don't usually matter.
     6.6       */
     6.7 -    u16 pirq_to_evtchn[64];
     6.8 +    u16 pirq_to_evtchn[128];
     6.9      u16 virq_to_evtchn[NR_VIRQS];
    6.10      u32 pirq_mask[2];
    6.11  
     7.1 --- a/xenolinux-2.4.25-sparse/arch/xen/Makefile	Sun Mar 28 20:22:50 2004 +0000
     7.2 +++ b/xenolinux-2.4.25-sparse/arch/xen/Makefile	Mon Mar 29 14:45:20 2004 +0000
     7.3 @@ -49,9 +49,14 @@ endif
     7.4  HEAD := arch/xen/kernel/head.o arch/xen/kernel/init_task.o
     7.5  
     7.6  SUBDIRS += arch/xen/kernel arch/xen/mm arch/xen/lib
     7.7 -SUBDIRS += arch/xen/drivers/console arch/xen/drivers/network
     7.8 -SUBDIRS += arch/xen/drivers/evtchn arch/xen/drivers/block
     7.9 -SUBDIRS += arch/xen/drivers/balloon arch/xen/drivers/vnetif
    7.10 +SUBDIRS += arch/xen/drivers/console 
    7.11 +ifndef CONFIG_XEN_PHYSDEV_ACCESS
    7.12 +SUBDIRS += arch/xen/drivers/network
    7.13 +endif
    7.14 +SUBDIRS += arch/xen/drivers/evtchn
    7.15 +SUBDIRS += arch/xen/drivers/block
    7.16 +SUBDIRS += arch/xen/drivers/balloon
    7.17 +SUBDIRS += arch/xen/drivers/vnetif
    7.18  ifdef CONFIG_XEN_PRIVILEGED_GUEST
    7.19  SUBDIRS += arch/xen/drivers/dom0 
    7.20  endif
    7.21 @@ -60,7 +65,9 @@ CORE_FILES += arch/xen/kernel/kernel.o a
    7.22  CORE_FILES += arch/xen/drivers/evtchn/drv.o
    7.23  CORE_FILES += arch/xen/drivers/console/drv.o
    7.24  CORE_FILES += arch/xen/drivers/block/drv.o
    7.25 +ifndef CONFIG_XEN_PHYSDEV_ACCESS
    7.26  CORE_FILES += arch/xen/drivers/network/drv.o
    7.27 +endif
    7.28  CORE_FILES += arch/xen/drivers/vnetif/drv.o
    7.29  ifdef CONFIG_XEN_PRIVILEGED_GUEST
    7.30  CORE_FILES += arch/xen/drivers/dom0/drv.o
     8.1 --- a/xenolinux-2.4.25-sparse/arch/xen/defconfig-physdev	Sun Mar 28 20:22:50 2004 +0000
     8.2 +++ b/xenolinux-2.4.25-sparse/arch/xen/defconfig-physdev	Mon Mar 29 14:45:20 2004 +0000
     8.3 @@ -401,9 +401,6 @@ CONFIG_SCSI_DTC3280=y
     8.4  # CONFIG_SCSI_FUTURE_DOMAIN is not set
     8.5  # CONFIG_SCSI_GDTH is not set
     8.6  # CONFIG_SCSI_GENERIC_NCR5380 is not set
     8.7 -# CONFIG_SCSI_GENERIC_NCR53C400 is not set
     8.8 -# CONFIG_SCSI_G_NCR5380_PORT is not set
     8.9 -# CONFIG_SCSI_G_NCR5380_MEM is not set
    8.10  # CONFIG_SCSI_IPS is not set
    8.11  # CONFIG_SCSI_INITIO is not set
    8.12  # CONFIG_SCSI_INIA100 is not set
    8.13 @@ -500,7 +497,43 @@ CONFIG_VORTEX=y
    8.14  # CONFIG_DEPCA is not set
    8.15  # CONFIG_HP100 is not set
    8.16  # CONFIG_NET_ISA is not set
    8.17 -# CONFIG_NET_PCI is not set
    8.18 +CONFIG_NET_PCI=y
    8.19 +CONFIG_PCNET32=y
    8.20 +# CONFIG_AMD8111_ETH is not set
    8.21 +# CONFIG_ADAPTEC_STARFIRE is not set
    8.22 +# CONFIG_AC3200 is not set
    8.23 +# CONFIG_APRICOT is not set
    8.24 +# CONFIG_B44 is not set
    8.25 +# CONFIG_CS89x0 is not set
    8.26 +CONFIG_TULIP=y
    8.27 +# CONFIG_TULIP_MWI is not set
    8.28 +# CONFIG_TULIP_MMIO is not set
    8.29 +# CONFIG_DE4X5 is not set
    8.30 +# CONFIG_DGRS is not set
    8.31 +# CONFIG_DM9102 is not set
    8.32 +# CONFIG_EEPRO100 is not set
    8.33 +# CONFIG_EEPRO100_PIO is not set
    8.34 +# CONFIG_E100 is not set
    8.35 +# CONFIG_LNE390 is not set
    8.36 +# CONFIG_FEALNX is not set
    8.37 +# CONFIG_NATSEMI is not set
    8.38 +# CONFIG_NE2K_PCI is not set
    8.39 +# CONFIG_NE3210 is not set
    8.40 +# CONFIG_ES3210 is not set
    8.41 +# CONFIG_8139CP is not set
    8.42 +# CONFIG_8139TOO is not set
    8.43 +# CONFIG_8139TOO_PIO is not set
    8.44 +# CONFIG_8139TOO_TUNE_TWISTER is not set
    8.45 +# CONFIG_8139TOO_8129 is not set
    8.46 +# CONFIG_8139_OLD_RX_RESET is not set
    8.47 +# CONFIG_SIS900 is not set
    8.48 +# CONFIG_EPIC100 is not set
    8.49 +# CONFIG_SUNDANCE is not set
    8.50 +# CONFIG_SUNDANCE_MMIO is not set
    8.51 +# CONFIG_TLAN is not set
    8.52 +# CONFIG_VIA_RHINE is not set
    8.53 +# CONFIG_VIA_RHINE_MMIO is not set
    8.54 +# CONFIG_WINBOND_840 is not set
    8.55  # CONFIG_NET_POCKET is not set
    8.56  
    8.57  #
     9.1 --- a/xenolinux-2.4.25-sparse/arch/xen/kernel/evtchn.c	Sun Mar 28 20:22:50 2004 +0000
     9.2 +++ b/xenolinux-2.4.25-sparse/arch/xen/kernel/evtchn.c	Mon Mar 29 14:45:20 2004 +0000
     9.3 @@ -38,6 +38,8 @@ static int irq_bindcount[NR_IRQS];
     9.4  /* Upcall to generic IRQ layer. */
     9.5  extern asmlinkage unsigned int do_IRQ(int irq, struct pt_regs *regs);
     9.6  
     9.7 +#define VALID_EVTCHN(_chn) ((_chn) != -1)
     9.8 +
     9.9  void evtchn_do_upcall(struct pt_regs *regs)
    9.10  {
    9.11      unsigned long  l1, l2;
    9.12 @@ -233,15 +235,27 @@ static inline void pirq_unmask_notify(in
    9.13      (void)HYPERVISOR_physdev_op(&op);
    9.14  }
    9.15  
    9.16 +/*
    9.17 + * On startup, if there is no action associated with the IRQ then we are
    9.18 + * probing. In this case we should not share with others as it will confuse us.
    9.19 + */
    9.20 +#define probing_irq(_irq) (irq_desc[(_irq)].action == NULL)
    9.21 +
    9.22  static unsigned int startup_pirq(unsigned int irq)
    9.23  {
    9.24      evtchn_op_t op;
    9.25      int evtchn;
    9.26  
    9.27 -    op.cmd              = EVTCHNOP_bind_pirq;
    9.28 -    op.u.bind_pirq.pirq = irq;
    9.29 +    op.cmd               = EVTCHNOP_bind_pirq;
    9.30 +    op.u.bind_pirq.pirq  = irq;
    9.31 +    /* NB. We are happy to share unless we are probing. */
    9.32 +    op.u.bind_pirq.flags = probing_irq(irq) ? 0 : BIND_PIRQ__WILL_SHARE;
    9.33      if ( HYPERVISOR_event_channel_op(&op) != 0 )
    9.34 -        panic("Failed to obtain physical IRQ %d\n", irq);
    9.35 +    {
    9.36 +        if ( !probing_irq(irq) ) /* Some failures are expected when probing. */
    9.37 +            printk(KERN_INFO "Failed to obtain physical IRQ %d\n", irq);
    9.38 +        return 0;
    9.39 +    }
    9.40      evtchn = op.u.bind_pirq.port;
    9.41  
    9.42      evtchn_to_irq[evtchn] = irq;
    9.43 @@ -258,6 +272,9 @@ static void shutdown_pirq(unsigned int i
    9.44      evtchn_op_t op;
    9.45      int evtchn = irq_to_evtchn[irq];
    9.46  
    9.47 +    if ( !VALID_EVTCHN(evtchn) )
    9.48 +        return;
    9.49 +
    9.50      mask_evtchn(evtchn);
    9.51  
    9.52      op.cmd          = EVTCHNOP_close;
    9.53 @@ -272,26 +289,38 @@ static void shutdown_pirq(unsigned int i
    9.54  
    9.55  static void enable_pirq(unsigned int irq)
    9.56  {
    9.57 -    unmask_evtchn(irq_to_evtchn[irq]);
    9.58 +    int evtchn = irq_to_evtchn[irq];
    9.59 +    if ( !VALID_EVTCHN(evtchn) )
    9.60 +        return;
    9.61 +    unmask_evtchn(evtchn);
    9.62      pirq_unmask_notify(irq_to_pirq(irq));
    9.63  }
    9.64  
    9.65  static void disable_pirq(unsigned int irq)
    9.66  {
    9.67 -    mask_evtchn(irq_to_evtchn[irq]);
    9.68 +    int evtchn = irq_to_evtchn[irq];
    9.69 +    if ( !VALID_EVTCHN(evtchn) )
    9.70 +        return;
    9.71 +    mask_evtchn(evtchn);
    9.72  }
    9.73  
    9.74  static void ack_pirq(unsigned int irq)
    9.75  {
    9.76 -    mask_evtchn(irq_to_evtchn[irq]);
    9.77 -    clear_evtchn(irq_to_evtchn[irq]);
    9.78 +    int evtchn = irq_to_evtchn[irq];
    9.79 +    if ( !VALID_EVTCHN(evtchn) )
    9.80 +        return;
    9.81 +    mask_evtchn(evtchn);
    9.82 +    clear_evtchn(evtchn);
    9.83  }
    9.84  
    9.85  static void end_pirq(unsigned int irq)
    9.86  {
    9.87 +    int evtchn = irq_to_evtchn[irq];
    9.88 +    if ( !VALID_EVTCHN(evtchn) )
    9.89 +        return;
    9.90      if ( !(irq_desc[irq].status & IRQ_DISABLED) )
    9.91      {
    9.92 -        unmask_evtchn(irq_to_evtchn[irq]);
    9.93 +        unmask_evtchn(evtchn);
    9.94          pirq_unmask_notify(irq_to_pirq(irq));
    9.95      }
    9.96  }
    10.1 --- a/xenolinux-2.4.25-sparse/arch/xen/kernel/irq.c	Sun Mar 28 20:22:50 2004 +0000
    10.2 +++ b/xenolinux-2.4.25-sparse/arch/xen/kernel/irq.c	Mon Mar 29 14:45:20 2004 +0000
    10.3 @@ -86,7 +86,25 @@ static unsigned int startup_none(unsigne
    10.4  static void disable_none(unsigned int irq) { }
    10.5  static void ack_none(unsigned int irq)
    10.6  {
    10.7 +/*
    10.8 + * 'what should we do if we get a hw irq event on an illegal vector'.
    10.9 + * each architecture has to answer this themselves, it doesnt deserve
   10.10 + * a generic callback i think.
   10.11 + */
   10.12 +#if CONFIG_X86
   10.13  	printk("unexpected IRQ trap at vector %02x\n", irq);
   10.14 +#ifdef CONFIG_X86_LOCAL_APIC
   10.15 +	/*
   10.16 +	 * Currently unexpected vectors happen only on SMP and APIC.
   10.17 +	 * We _must_ ack these because every local APIC has only N
   10.18 +	 * irq slots per priority level, and a 'hanging, unacked' IRQ
   10.19 +	 * holds up an irq slot - in excessive cases (when multiple
   10.20 +	 * unexpected vectors occur) that might lock up the APIC
   10.21 +	 * completely.
   10.22 +	 */
   10.23 +	ack_APIC_irq();
   10.24 +#endif
   10.25 +#endif
   10.26  }
   10.27  
   10.28  /* startup is the same as "enable", shutdown is same as "disable" */
   10.29 @@ -322,14 +340,38 @@ static inline void get_irqlock(int cpu)
   10.30  	global_irq_holder = cpu;
   10.31  }
   10.32  
   10.33 +/*
   10.34 + * A global "cli()" while in an interrupt context
   10.35 + * turns into just a local cli(). Interrupts
   10.36 + * should use spinlocks for the (very unlikely)
   10.37 + * case that they ever want to protect against
   10.38 + * each other.
   10.39 + *
   10.40 + * If we already have local interrupts disabled,
   10.41 + * this will not turn a local disable into a
   10.42 + * global one (problems with spinlocks: this makes
   10.43 + * save_flags+cli+sti usable inside a spinlock).
   10.44 + */
   10.45  void __global_cli(void)
   10.46  {
   10.47 -    panic("__global_cli");
   10.48 +	unsigned int flags;
   10.49 +
   10.50 +	__save_flags(flags);
   10.51 +	if (!flags) {
   10.52 +		int cpu = smp_processor_id();
   10.53 +		__cli();
   10.54 +		if (!local_irq_count(cpu))
   10.55 +			get_irqlock(cpu);
   10.56 +	}
   10.57  }
   10.58  
   10.59  void __global_sti(void)
   10.60  {
   10.61 -    panic("__global_sti");
   10.62 +	int cpu = smp_processor_id();
   10.63 +
   10.64 +	if (!local_irq_count(cpu))
   10.65 +		release_irqlock(cpu);
   10.66 +	__sti();
   10.67  }
   10.68  
   10.69  /*
   10.70 @@ -341,12 +383,45 @@ void __global_sti(void)
   10.71   */
   10.72  unsigned long __global_save_flags(void)
   10.73  {
   10.74 -    panic("__global_save_flags");
   10.75 +	int retval;
   10.76 +	int local_enabled;
   10.77 +	unsigned long flags;
   10.78 +	int cpu = smp_processor_id();
   10.79 +
   10.80 +	__save_flags(flags);
   10.81 +	local_enabled = !flags;
   10.82 +	/* default to local */
   10.83 +	retval = 2 + local_enabled;
   10.84 +
   10.85 +	/* check for global flags if we're not in an interrupt */
   10.86 +	if (!local_irq_count(cpu)) {
   10.87 +		if (local_enabled)
   10.88 +			retval = 1;
   10.89 +		if (global_irq_holder == cpu)
   10.90 +			retval = 0;
   10.91 +	}
   10.92 +	return retval;
   10.93  }
   10.94  
   10.95  void __global_restore_flags(unsigned long flags)
   10.96  {
   10.97 -    panic("__global_restore_flags");
   10.98 +	switch (flags) {
   10.99 +	case 0:
  10.100 +		__global_cli();
  10.101 +		break;
  10.102 +	case 1:
  10.103 +		__global_sti();
  10.104 +		break;
  10.105 +	case 2:
  10.106 +		__cli();
  10.107 +		break;
  10.108 +	case 3:
  10.109 +		__sti();
  10.110 +		break;
  10.111 +	default:
  10.112 +		printk("global_restore_flags: %08lx (%08lx)\n",
  10.113 +			flags, (&flags)[-1]);
  10.114 +	}
  10.115  }
  10.116  
  10.117  #endif