linux/drivers/pci/htirq.c
<<
>>
Prefs
   1/*
   2 * File:        htirq.c
   3 * Purpose:     Hypertransport Interrupt Capability
   4 *
   5 * Copyright (C) 2006 Linux Networx
   6 * Copyright (C) Eric Biederman <ebiederman@lnxi.com>
   7 */
   8
   9#include <linux/irq.h>
  10#include <linux/pci.h>
  11#include <linux/spinlock.h>
  12#include <linux/export.h>
  13#include <linux/slab.h>
  14#include <linux/htirq.h>
  15
  16/* Global ht irq lock.
  17 *
  18 * This is needed to serialize access to the data port in hypertransport
  19 * irq capability.
  20 *
  21 * With multiple simultaneous hypertransport irq devices it might pay
  22 * to make this more fine grained.  But start with simple, stupid, and correct.
  23 */
  24static DEFINE_SPINLOCK(ht_irq_lock);
  25
  26struct ht_irq_cfg {
  27        struct pci_dev *dev;
  28         /* Update callback used to cope with buggy hardware */
  29        ht_irq_update_t *update;
  30        unsigned pos;
  31        unsigned idx;
  32        struct ht_irq_msg msg;
  33};
  34
  35
  36void write_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg)
  37{
  38        struct ht_irq_cfg *cfg = irq_get_handler_data(irq);
  39        unsigned long flags;
  40        spin_lock_irqsave(&ht_irq_lock, flags);
  41        if (cfg->msg.address_lo != msg->address_lo) {
  42                pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx);
  43                pci_write_config_dword(cfg->dev, cfg->pos + 4, msg->address_lo);
  44        }
  45        if (cfg->msg.address_hi != msg->address_hi) {
  46                pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx + 1);
  47                pci_write_config_dword(cfg->dev, cfg->pos + 4, msg->address_hi);
  48        }
  49        if (cfg->update)
  50                cfg->update(cfg->dev, irq, msg);
  51        spin_unlock_irqrestore(&ht_irq_lock, flags);
  52        cfg->msg = *msg;
  53}
  54
  55void fetch_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg)
  56{
  57        struct ht_irq_cfg *cfg = irq_get_handler_data(irq);
  58        *msg = cfg->msg;
  59}
  60
  61void mask_ht_irq(struct irq_data *data)
  62{
  63        struct ht_irq_cfg *cfg = irq_data_get_irq_handler_data(data);
  64        struct ht_irq_msg msg = cfg->msg;
  65
  66        msg.address_lo |= 1;
  67        write_ht_irq_msg(data->irq, &msg);
  68}
  69
  70void unmask_ht_irq(struct irq_data *data)
  71{
  72        struct ht_irq_cfg *cfg = irq_data_get_irq_handler_data(data);
  73        struct ht_irq_msg msg = cfg->msg;
  74
  75        msg.address_lo &= ~1;
  76        write_ht_irq_msg(data->irq, &msg);
  77}
  78
  79/**
  80 * __ht_create_irq - create an irq and attach it to a device.
  81 * @dev: The hypertransport device to find the irq capability on.
  82 * @idx: Which of the possible irqs to attach to.
  83 * @update: Function to be called when changing the htirq message
  84 *
  85 * The irq number of the new irq or a negative error value is returned.
  86 */
  87int __ht_create_irq(struct pci_dev *dev, int idx, ht_irq_update_t *update)
  88{
  89        struct ht_irq_cfg *cfg;
  90        unsigned long flags;
  91        u32 data;
  92        int max_irq;
  93        int pos;
  94        int irq;
  95        int node;
  96
  97        pos = pci_find_ht_capability(dev, HT_CAPTYPE_IRQ);
  98        if (!pos)
  99                return -EINVAL;
 100
 101        /* Verify the idx I want to use is in range */
 102        spin_lock_irqsave(&ht_irq_lock, flags);
 103        pci_write_config_byte(dev, pos + 2, 1);
 104        pci_read_config_dword(dev, pos + 4, &data);
 105        spin_unlock_irqrestore(&ht_irq_lock, flags);
 106
 107        max_irq = (data >> 16) & 0xff;
 108        if ( idx > max_irq)
 109                return -EINVAL;
)
ht_irq_cfg *ht_irq_locGFP_KERNE -flags);
  98      g *flags);
  09                reNOMEM-EINVAL;
  74
 105 te(cfg-> *dev;
  76        cfg-> *update;
 107 v, cfg->pos<  int pos;
 107 v, cfg10" cq_get_handler_dat if ( flags);
 101         rsinete" .ant to use is in range */
  40    if (cfg->msg. &&&&&&&inux/spinlock.h>
)
cfg->msg. &&&&&&&inux/spinlock.h>
 103    int cfg->flags);
 104    int msght_irq_loc   int flags);
  25
  49        int address_hi) {
 104 kfreint flags);
  09                reBUSY-pos;
  77}
  40 ss=_s= pci_read_config_dwoa>-> *flags);
flags);
msch_rs= up ->address_hi) {
  43         flags);
  09                reBUSY-pos;
  77}
 106
 ">  94        int irq;
  68}
  69
  80/**
  81 * __ht_create_irq - create an irq and attach it to a device.
  82 * @dev: The hypertransport device to find the irq capability on.
  83 * @idx: Which of the possible irqs to attach to.
  84 *
  85 * @update: fnumbll comment"> * @dev: Thespan class="comment"> *
   6
  17 *
  18 * The irq number of the new irq or a negative error value is returned.
  19
  95     >int __ht_create_irq(struct pci_dev *dev, int flags);
  71{
 ">  94     /a>int de>, int idNUL -flags);
  53}
  54
  85/**
   6/**
  17 * @udestroyed"s class="comment">/**
  18/**
  19/**
  80  81
  70pci_>fetch_ht_irq_msg(unsigned int flags);
  71{
  64        struct ht_irq_cfg *cfg;
  65
  66 g *cfg = irq_get_handler_data(irq);
  67 er_ds= pci_read_config_dwoa>->flags);
 107 ss=_s= pci_read_config_dwoa>->flags);
  29 destroy href="+code=unmaskdestroy hre>pci_read_config_dwoa>->flags);
)
pci_read_config_dwog *flags);
  53}
  53}
pci_read_config_dwo/a>int flags);
pci_read_config_dwo>int flags);
pci_read_config_dwo>indestroy href="+code=unmaskpci)lass="sref">flags);

an coriginal LXR softo copbass="css="sref"http://sourc@fenge.net/projects/lxr">LXR >  8unf">pci_,"="comexperi81lxr@ltirq.no=msg"
ch_resuts"
	htirq.csubfooter">
lxr.ltirq.no kihrey hoscld basss="sref"http://www.redpill-ltipro.no">Redpill> * pro ASpci_,"providmment"L* Copcajaxlto bee_iroper _ents"> * hypersinnd 1995.
ch_result/bodysut;