summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorStefano Stabellini <stefano.stabellini@eu.citrix.com>2010-10-22 21:24:06 +0100
committerStefano Stabellini <stefano.stabellini@eu.citrix.com>2010-10-22 21:24:06 +0100
commit67ba37293e938208795d6a3562201bdb0cf43393 (patch)
tree3522e949ff19f3809583bfb3fa3973ddf264689d /drivers
parentcd07202cc8262e1669edff0d97715f3dd9260917 (diff)
parent5bba6c56dc99ff88f79a79572e29ecf445710878 (diff)
Merge commit 'konrad/stable/xen-pcifront-0.8.2' into 2.6.36-rc8-initial-domain-v6
Diffstat (limited to 'drivers')
-rw-r--r--drivers/block/xen-blkfront.c2
-rw-r--r--drivers/input/xen-kbdfront.c2
-rw-r--r--drivers/isdn/act2000/act2000.h6
-rw-r--r--drivers/isdn/hisax/config.c18
-rw-r--r--drivers/isdn/hisax/hisax.h1
-rw-r--r--drivers/mfd/twl4030-irq.c4
-rw-r--r--drivers/net/xen-netfront.c2
-rw-r--r--drivers/pci/Kconfig21
-rw-r--r--drivers/pci/Makefile2
-rw-r--r--drivers/pci/bus.c1
-rw-r--r--drivers/pci/dmar.c8
-rw-r--r--drivers/pci/htirq.c22
-rw-r--r--drivers/pci/intr_remapping.c212
-rw-r--r--drivers/pci/msi.c52
-rw-r--r--drivers/pci/xen-pcifront.c1148
-rw-r--r--drivers/video/xen-fbfront.c2
-rw-r--r--drivers/xen/Kconfig3
-rw-r--r--drivers/xen/Makefile1
-rw-r--r--drivers/xen/biomerge.c13
-rw-r--r--drivers/xen/events.c365
-rw-r--r--drivers/xen/xenbus/xenbus_client.c2
21 files changed, 1623 insertions, 264 deletions
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index ab735a605cf3..c4e9d817caaa 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -1125,6 +1125,8 @@ static void blkback_changed(struct xenbus_device *dev,
case XenbusStateInitialising:
case XenbusStateInitWait:
case XenbusStateInitialised:
+ case XenbusStateReconfiguring:
+ case XenbusStateReconfigured:
case XenbusStateUnknown:
case XenbusStateClosed:
break;
diff --git a/drivers/input/xen-kbdfront.c b/drivers/input/xen-kbdfront.c
index ebb11907d402..e0c024db2ca5 100644
--- a/drivers/input/xen-kbdfront.c
+++ b/drivers/input/xen-kbdfront.c
@@ -276,6 +276,8 @@ static void xenkbd_backend_changed(struct xenbus_device *dev,
switch (backend_state) {
case XenbusStateInitialising:
case XenbusStateInitialised:
+ case XenbusStateReconfiguring:
+ case XenbusStateReconfigured:
case XenbusStateUnknown:
case XenbusStateClosed:
break;
diff --git a/drivers/isdn/act2000/act2000.h b/drivers/isdn/act2000/act2000.h
index d4c50512a1ff..88c9423500d8 100644
--- a/drivers/isdn/act2000/act2000.h
+++ b/drivers/isdn/act2000/act2000.h
@@ -141,9 +141,9 @@ typedef struct irq_data_isa {
__u8 rcvhdr[8];
} irq_data_isa;
-typedef union irq_data {
+typedef union act2000_irq_data {
irq_data_isa isa;
-} irq_data;
+} act2000_irq_data;
/*
* Per card driver data
@@ -176,7 +176,7 @@ typedef struct act2000_card {
char *status_buf_read;
char *status_buf_write;
char *status_buf_end;
- irq_data idat; /* Data used for IRQ handler */
+ act2000_irq_data idat; /* Data used for IRQ handler */
isdn_if interface; /* Interface to upper layer */
char regname[35]; /* Name used for request_region */
} act2000_card;
diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c
index 6f9afcd5ca4e..b133378d4dc9 100644
--- a/drivers/isdn/hisax/config.c
+++ b/drivers/isdn/hisax/config.c
@@ -801,6 +801,16 @@ static void closecard(int cardnr)
ll_unload(csta);
}
+static irqreturn_t card_irq(int intno, void *dev_id)
+{
+ struct IsdnCardState *cs = dev_id;
+ irqreturn_t ret = cs->irq_func(intno, cs);
+
+ if (ret == IRQ_HANDLED)
+ cs->irq_cnt++;
+ return ret;
+}
+
static int init_card(struct IsdnCardState *cs)
{
int irq_cnt, cnt = 3, ret;
@@ -809,10 +819,10 @@ static int init_card(struct IsdnCardState *cs)
ret = cs->cardmsg(cs, CARD_INIT, NULL);
return(ret);
}
- irq_cnt = kstat_irqs(cs->irq);
+ irq_cnt = cs->irq_cnt = 0;
printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ],
cs->irq, irq_cnt);
- if (request_irq(cs->irq, cs->irq_func, cs->irq_flags, "HiSax", cs)) {
+ if (request_irq(cs->irq, card_irq, cs->irq_flags, "HiSax", cs)) {
printk(KERN_WARNING "HiSax: couldn't get interrupt %d\n",
cs->irq);
return 1;
@@ -822,8 +832,8 @@ static int init_card(struct IsdnCardState *cs)
/* Timeout 10ms */
msleep(10);
printk(KERN_INFO "%s: IRQ %d count %d\n",
- CardType[cs->typ], cs->irq, kstat_irqs(cs->irq));
- if (kstat_irqs(cs->irq) == irq_cnt) {
+ CardType[cs->typ], cs->irq, cs->irq_cnt);
+ if (cs->irq_cnt == irq_cnt) {
printk(KERN_WARNING
"%s: IRQ(%d) getting no interrupts during init %d\n",
CardType[cs->typ], cs->irq, 4 - cnt);
diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h
index 832a87855ffb..32ab3924aa73 100644
--- a/drivers/isdn/hisax/hisax.h
+++ b/drivers/isdn/hisax/hisax.h
@@ -959,6 +959,7 @@ struct IsdnCardState {
u_long event;
struct work_struct tqueue;
struct timer_list dbusytimer;
+ unsigned int irq_cnt;
#ifdef ERROR_STATISTIC
int err_crc;
int err_tx;
diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c
index 097f24d8bceb..b9fda7018cef 100644
--- a/drivers/mfd/twl4030-irq.c
+++ b/drivers/mfd/twl4030-irq.c
@@ -78,7 +78,7 @@ struct sih {
u8 irq_lines; /* number of supported irq lines */
/* SIR ignored -- set interrupt, for testing only */
- struct irq_data {
+ struct sih_irq_data {
u8 isr_offset;
u8 imr_offset;
} mask[2];
@@ -810,7 +810,7 @@ int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
twl4030_irq_chip = dummy_irq_chip;
twl4030_irq_chip.name = "twl4030";
- twl4030_sih_irq_chip.ack = dummy_irq_chip.ack;
+ twl4030_sih_irq_chip.irq_ack = dummy_irq_chip.irq_ack;
for (i = irq_base; i < irq_end; i++) {
set_irq_chip_and_handler(i, &twl4030_irq_chip,
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index b50fedcef8ac..cb6e112989d8 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -1610,6 +1610,8 @@ static void backend_changed(struct xenbus_device *dev,
switch (backend_state) {
case XenbusStateInitialising:
case XenbusStateInitialised:
+ case XenbusStateReconfiguring:
+ case XenbusStateReconfigured:
case XenbusStateConnected:
case XenbusStateUnknown:
case XenbusStateClosed:
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 34ef70d562b2..5b1630e4e9e3 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -40,6 +40,27 @@ config PCI_STUB
When in doubt, say N.
+config XEN_PCIDEV_FRONTEND
+ tristate "Xen PCI Frontend"
+ depends on PCI && X86 && XEN
+ select HOTPLUG
+ select PCI_XEN
+ default y
+ help
+ The PCI device frontend driver allows the kernel to import arbitrary
+ PCI devices from a PCI backend to support PCI driver domains.
+
+config XEN_PCIDEV_FE_DEBUG
+ bool "Xen PCI Frontend debugging"
+ depends on XEN_PCIDEV_FRONTEND && PCI_DEBUG
+ help
+ Say Y here if you want the Xen PCI frontend to produce a bunch of debug
+ messages to the system log. Select this if you are having a
+ problem with Xen PCI frontend support and want to see more of what is
+ going on.
+
+ When in doubt, say N.
+
config HT_IRQ
bool "Interrupts on hypertransport devices"
default y
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index dc1aa0922868..d5e27050c4e3 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -65,6 +65,8 @@ obj-$(CONFIG_PCI_SYSCALL) += syscall.o
obj-$(CONFIG_PCI_STUB) += pci-stub.o
+obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += xen-pcifront.o
+
ifeq ($(CONFIG_PCI_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
endif
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index 7f0af0e9b826..69546e9213dd 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -299,6 +299,7 @@ void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *),
}
up_read(&pci_bus_sem);
}
+EXPORT_SYMBOL_GPL(pci_walk_bus);
EXPORT_SYMBOL(pci_bus_alloc_resource);
EXPORT_SYMBOL_GPL(pci_bus_add_device);
diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c
index 0a19708074c2..3de3a436a432 100644
--- a/drivers/pci/dmar.c
+++ b/drivers/pci/dmar.c
@@ -1221,9 +1221,9 @@ const char *dmar_get_fault_reason(u8 fault_reason, int *fault_type)
}
}
-void dmar_msi_unmask(unsigned int irq)
+void dmar_msi_unmask(struct irq_data *data)
{
- struct intel_iommu *iommu = get_irq_data(irq);
+ struct intel_iommu *iommu = irq_data_get_irq_data(data);
unsigned long flag;
/* unmask it */
@@ -1234,10 +1234,10 @@ void dmar_msi_unmask(unsigned int irq)
spin_unlock_irqrestore(&iommu->register_lock, flag);
}
-void dmar_msi_mask(unsigned int irq)
+void dmar_msi_mask(struct irq_data *data)
{
unsigned long flag;
- struct intel_iommu *iommu = get_irq_data(irq);
+ struct intel_iommu *iommu = irq_data_get_irq_data(data);
/* mask it */
spin_lock_irqsave(&iommu->register_lock, flag);
diff --git a/drivers/pci/htirq.c b/drivers/pci/htirq.c
index 98abf8b91294..834842aa5bbf 100644
--- a/drivers/pci/htirq.c
+++ b/drivers/pci/htirq.c
@@ -57,28 +57,22 @@ void fetch_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg)
*msg = cfg->msg;
}
-void mask_ht_irq(unsigned int irq)
+void mask_ht_irq(struct irq_data *data)
{
- struct ht_irq_cfg *cfg;
- struct ht_irq_msg msg;
-
- cfg = get_irq_data(irq);
+ struct ht_irq_cfg *cfg = irq_data_get_irq_data(data);
+ struct ht_irq_msg msg = cfg->msg;
- msg = cfg->msg;
msg.address_lo |= 1;
- write_ht_irq_msg(irq, &msg);
+ write_ht_irq_msg(data->irq, &msg);
}
-void unmask_ht_irq(unsigned int irq)
+void unmask_ht_irq(struct irq_data *data)
{
- struct ht_irq_cfg *cfg;
- struct ht_irq_msg msg;
-
- cfg = get_irq_data(irq);
+ struct ht_irq_cfg *cfg = irq_data_get_irq_data(data);
+ struct ht_irq_msg msg = cfg->msg;
- msg = cfg->msg;
msg.address_lo &= ~1;
- write_ht_irq_msg(irq, &msg);
+ write_ht_irq_msg(data->irq, &msg);
}
/**
diff --git a/drivers/pci/intr_remapping.c b/drivers/pci/intr_remapping.c
index fd1d2867cdcc..ec87cd66f3eb 100644
--- a/drivers/pci/intr_remapping.c
+++ b/drivers/pci/intr_remapping.c
@@ -46,109 +46,24 @@ static __init int setup_intremap(char *str)
}
early_param("intremap", setup_intremap);
-struct irq_2_iommu {
- struct intel_iommu *iommu;
- u16 irte_index;
- u16 sub_handle;
- u8 irte_mask;
-};
-
-#ifdef CONFIG_GENERIC_HARDIRQS
-static struct irq_2_iommu *get_one_free_irq_2_iommu(int node)
-{
- struct irq_2_iommu *iommu;
-
- iommu = kzalloc_node(sizeof(*iommu), GFP_ATOMIC, node);
- printk(KERN_DEBUG "alloc irq_2_iommu on node %d\n", node);
-
- return iommu;
-}
-
-static struct irq_2_iommu *irq_2_iommu(unsigned int irq)
-{
- struct irq_desc *desc;
-
- desc = irq_to_desc(irq);
-
- if (WARN_ON_ONCE(!desc))
- return NULL;
-
- return desc->irq_2_iommu;
-}
-
-static struct irq_2_iommu *irq_2_iommu_alloc(unsigned int irq)
-{
- struct irq_desc *desc;
- struct irq_2_iommu *irq_iommu;
-
- desc = irq_to_desc(irq);
- if (!desc) {
- printk(KERN_INFO "can not get irq_desc for %d\n", irq);
- return NULL;
- }
-
- irq_iommu = desc->irq_2_iommu;
-
- if (!irq_iommu)
- desc->irq_2_iommu = get_one_free_irq_2_iommu(irq_node(irq));
-
- return desc->irq_2_iommu;
-}
-
-#else /* !CONFIG_SPARSE_IRQ */
-
-static struct irq_2_iommu irq_2_iommuX[NR_IRQS];
-
-static struct irq_2_iommu *irq_2_iommu(unsigned int irq)
-{
- if (irq < nr_irqs)
- return &irq_2_iommuX[irq];
-
- return NULL;
-}
-static struct irq_2_iommu *irq_2_iommu_alloc(unsigned int irq)
-{
- return irq_2_iommu(irq);
-}
-#endif
-
static DEFINE_SPINLOCK(irq_2_ir_lock);
-static struct irq_2_iommu *valid_irq_2_iommu(unsigned int irq)
-{
- struct irq_2_iommu *irq_iommu;
-
- irq_iommu = irq_2_iommu(irq);
-
- if (!irq_iommu)
- return NULL;
-
- if (!irq_iommu->iommu)
- return NULL;
-
- return irq_iommu;
-}
-
-int irq_remapped(int irq)
+static struct irq_2_iommu *irq_2_iommu(unsigned int irq)
{
- return valid_irq_2_iommu(irq) != NULL;
+ struct irq_cfg *cfg = get_irq_chip_data(irq);
+ return cfg ? &cfg->irq_2_iommu : NULL;
}
int get_irte(int irq, struct irte *entry)
{
- int index;
- struct irq_2_iommu *irq_iommu;
+ struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
unsigned long flags;
+ int index;
- if (!entry)
+ if (!entry || !irq_iommu)
return -1;
spin_lock_irqsave(&irq_2_ir_lock, flags);
- irq_iommu = valid_irq_2_iommu(irq);
- if (!irq_iommu) {
- spin_unlock_irqrestore(&irq_2_ir_lock, flags);
- return -1;
- }
index = irq_iommu->irte_index + irq_iommu->sub_handle;
*entry = *(irq_iommu->iommu->ir_table->base + index);
@@ -160,20 +75,14 @@ int get_irte(int irq, struct irte *entry)
int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)
{
struct ir_table *table = iommu->ir_table;
- struct irq_2_iommu *irq_iommu;
+ struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
u16 index, start_index;
unsigned int mask = 0;
unsigned long flags;
int i;
- if (!count)
- return -1;
-
-#ifndef CONFIG_SPARSE_IRQ
- /* protect irq_2_iommu_alloc later */
- if (irq >= nr_irqs)
+ if (!count || !irq_iommu)
return -1;
-#endif
/*
* start the IRTE search from index 0.
@@ -214,13 +123,6 @@ int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)
for (i = index; i < index + count; i++)
table->base[i].present = 1;
- irq_iommu = irq_2_iommu_alloc(irq);
- if (!irq_iommu) {
- spin_unlock_irqrestore(&irq_2_ir_lock, flags);
- printk(KERN_ERR "can't allocate irq_2_iommu\n");
- return -1;
- }
-
irq_iommu->iommu = iommu;
irq_iommu->irte_index = index;
irq_iommu->sub_handle = 0;
@@ -244,17 +146,14 @@ static int qi_flush_iec(struct intel_iommu *iommu, int index, int mask)
int map_irq_to_irte_handle(int irq, u16 *sub_handle)
{
- int index;
- struct irq_2_iommu *irq_iommu;
+ struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
unsigned long flags;
+ int index;
- spin_lock_irqsave(&irq_2_ir_lock, flags);
- irq_iommu = valid_irq_2_iommu(irq);
- if (!irq_iommu) {
- spin_unlock_irqrestore(&irq_2_ir_lock, flags);
+ if (!irq_iommu)
return -1;
- }
+ spin_lock_irqsave(&irq_2_ir_lock, flags);
*sub_handle = irq_iommu->sub_handle;
index = irq_iommu->irte_index;
spin_unlock_irqrestore(&irq_2_ir_lock, flags);
@@ -263,18 +162,13 @@ int map_irq_to_irte_handle(int irq, u16 *sub_handle)
int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle)
{
- struct irq_2_iommu *irq_iommu;
+ struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
unsigned long flags;
- spin_lock_irqsave(&irq_2_ir_lock, flags);
-
- irq_iommu = irq_2_iommu_alloc(irq);
-
- if (!irq_iommu) {
- spin_unlock_irqrestore(&irq_2_ir_lock, flags);
- printk(KERN_ERR "can't allocate irq_2_iommu\n");
+ if (!irq_iommu)
return -1;
- }
+
+ spin_lock_irqsave(&irq_2_ir_lock, flags);
irq_iommu->iommu = iommu;
irq_iommu->irte_index = index;
@@ -286,43 +180,18 @@ int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle)
return 0;
}
-int clear_irte_irq(int irq, struct intel_iommu *iommu, u16 index)
-{
- struct irq_2_iommu *irq_iommu;
- unsigned long flags;
-
- spin_lock_irqsave(&irq_2_ir_lock, flags);
- irq_iommu = valid_irq_2_iommu(irq);
- if (!irq_iommu) {
- spin_unlock_irqrestore(&irq_2_ir_lock, flags);
- return -1;
- }
-
- irq_iommu->iommu = NULL;
- irq_iommu->irte_index = 0;
- irq_iommu->sub_handle = 0;
- irq_2_iommu(irq)->irte_mask = 0;
-
- spin_unlock_irqrestore(&irq_2_ir_lock, flags);
-
- return 0;
-}
-
int modify_irte(int irq, struct irte *irte_modified)
{
- int rc;
- int index;
- struct irte *irte;
+ struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
struct intel_iommu *iommu;
- struct irq_2_iommu *irq_iommu;
unsigned long flags;
+ struct irte *irte;
+ int rc, index;
- spin_lock_irqsave(&irq_2_ir_lock, flags);
- irq_iommu = valid_irq_2_iommu(irq);
- if (!irq_iommu) {
- spin_unlock_irqrestore(&irq_2_ir_lock, flags);
+ if (!irq_iommu)
return -1;
- }
+
+ spin_lock_irqsave(&irq_2_ir_lock, flags);
iommu = irq_iommu->iommu;
@@ -339,31 +208,6 @@ int modify_irte(int irq, struct irte *irte_modified)
return rc;
}
-int flush_irte(int irq)
-{
- int rc;
- int index;
- struct intel_iommu *iommu;
- struct irq_2_iommu *irq_iommu;
- unsigned long flags;
-
- spin_lock_irqsave(&irq_2_ir_lock, flags);
- irq_iommu = valid_irq_2_iommu(irq);
- if (!irq_iommu) {
- spin_unlock_irqrestore(&irq_2_ir_lock, flags);
- return -1;
- }
-
- iommu = irq_iommu->iommu;
-
- index = irq_iommu->irte_index + irq_iommu->sub_handle;
-
- rc = qi_flush_iec(iommu, index, irq_iommu->irte_mask);
- spin_unlock_irqrestore(&irq_2_ir_lock, flags);
-
- return rc;
-}
-
struct intel_iommu *map_hpet_to_ir(u8 hpet_id)
{
int i;
@@ -420,16 +264,14 @@ static int clear_entries(struct irq_2_iommu *irq_iommu)
int free_irte(int irq)
{
- int rc = 0;
- struct irq_2_iommu *irq_iommu;
+ struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
unsigned long flags;
+ int rc;
- spin_lock_irqsave(&irq_2_ir_lock, flags);
- irq_iommu = valid_irq_2_iommu(irq);
- if (!irq_iommu) {
- spin_unlock_irqrestore(&irq_2_ir_lock, flags);
+ if (!irq_iommu)
return -1;
- }
+
+ spin_lock_irqsave(&irq_2_ir_lock, flags);
rc = clear_entries(irq_iommu);
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 69b7be33b3a2..7c24dcef2989 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -35,7 +35,12 @@ int arch_msi_check_device(struct pci_dev *dev, int nvec, int type)
#endif
#ifndef arch_setup_msi_irqs
-int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
+# define arch_setup_msi_irqs default_setup_msi_irqs
+# define HAVE_DEFAULT_MSI_SETUP_IRQS
+#endif
+
+#ifdef HAVE_DEFAULT_MSI_SETUP_IRQS
+int default_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
{
struct msi_desc *entry;
int ret;
@@ -60,7 +65,12 @@ int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
#endif
#ifndef arch_teardown_msi_irqs
-void arch_teardown_msi_irqs(struct pci_dev *dev)
+# define arch_teardown_msi_irqs default_teardown_msi_irqs
+# define HAVE_DEFAULT_MSI_TEARDOWN_IRQS
+#endif
+
+#ifdef HAVE_DEFAULT_MSI_TEARDOWN_IRQS
+void default_teardown_msi_irqs(struct pci_dev *dev)
{
struct msi_desc *entry;
@@ -170,33 +180,31 @@ static void msix_mask_irq(struct msi_desc *desc, u32 flag)
desc->masked = __msix_mask_irq(desc, flag);
}
-static void msi_set_mask_bit(unsigned irq, u32 flag)
+static void msi_set_mask_bit(struct irq_data *data, u32 flag)
{
- struct msi_desc *desc = get_irq_msi(irq);
+ struct msi_desc *desc = irq_data_get_msi(data);
if (desc->msi_attrib.is_msix) {
msix_mask_irq(desc, flag);
readl(desc->mask_base); /* Flush write to device */
} else {
- unsigned offset = irq - desc->dev->irq;
+ unsigned offset = data->irq - desc->dev->irq;
msi_mask_irq(desc, 1 << offset, flag << offset);
}
}
-void mask_msi_irq(unsigned int irq)
+void mask_msi_irq(struct irq_data *data)
{
- msi_set_mask_bit(irq, 1);
+ msi_set_mask_bit(data, 1);
}
-void unmask_msi_irq(unsigned int irq)
+void unmask_msi_irq(struct irq_data *data)
{
- msi_set_mask_bit(irq, 0);
+ msi_set_mask_bit(data, 0);
}
-void read_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg)
+void __read_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
{
- struct msi_desc *entry = get_irq_desc_msi(desc);
-
BUG_ON(entry->dev->current_state != PCI_D0);
if (entry->msi_attrib.is_msix) {
@@ -227,15 +235,13 @@ void read_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg)
void read_msi_msg(unsigned int irq, struct msi_msg *msg)
{
- struct irq_desc *desc = irq_to_desc(irq);
+ struct msi_desc *entry = get_irq_msi(irq);
- read_msi_msg_desc(desc, msg);
+ __read_msi_msg(entry, msg);
}
-void get_cached_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg)
+void __get_cached_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
{
- struct msi_desc *entry = get_irq_desc_msi(desc);
-
/* Assert that the cache is valid, assuming that
* valid messages are not all-zeroes. */
BUG_ON(!(entry->msg.address_hi | entry->msg.address_lo |
@@ -246,15 +252,13 @@ void get_cached_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg)
void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg)
{
- struct irq_desc *desc = irq_to_desc(irq);
+ struct msi_desc *entry = get_irq_msi(irq);
- get_cached_msi_msg_desc(desc, msg);
+ __get_cached_msi_msg(entry, msg);
}
-void write_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg)
+void __write_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
{
- struct msi_desc *entry = get_irq_desc_msi(desc);
-
if (entry->dev->current_state != PCI_D0) {
/* Don't touch the hardware now */
} else if (entry->msi_attrib.is_msix) {
@@ -292,9 +296,9 @@ void write_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg)
void write_msi_msg(unsigned int irq, struct msi_msg *msg)
{
- struct irq_desc *desc = irq_to_desc(irq);
+ struct msi_desc *entry = get_irq_msi(irq);
- write_msi_msg_desc(desc, msg);
+ __write_msi_msg(entry, msg);
}
static void free_msi_irqs(struct pci_dev *dev)
diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c
new file mode 100644
index 000000000000..a87c4985326e
--- /dev/null
+++ b/drivers/pci/xen-pcifront.c
@@ -0,0 +1,1148 @@
+/*
+ * Xen PCI Frontend.
+ *
+ * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <xen/xenbus.h>
+#include <xen/events.h>
+#include <xen/grant_table.h>
+#include <xen/page.h>
+#include <linux/spinlock.h>
+#include <linux/pci.h>
+#include <linux/msi.h>
+#include <xen/xenbus.h>
+#include <xen/interface/io/pciif.h>
+#include <asm/xen/pci.h>
+#include <linux/interrupt.h>
+#include <asm/atomic.h>
+#include <linux/workqueue.h>
+#include <linux/bitops.h>
+#include <linux/time.h>
+
+#define INVALID_GRANT_REF (0)
+#define INVALID_EVTCHN (-1)
+
+struct pci_bus_entry {
+ struct list_head list;
+ struct pci_bus *bus;
+};
+
+#define _PDEVB_op_active (0)
+#define PDEVB_op_active (1 << (_PDEVB_op_active))
+
+struct pcifront_device {
+ struct xenbus_device *xdev;
+ struct list_head root_buses;
+
+ int evtchn;
+ int gnt_ref;
+
+ int irq;
+
+ /* Lock this when doing any operations in sh_info */
+ spinlock_t sh_info_lock;
+ struct xen_pci_sharedinfo *sh_info;
+ struct work_struct op_work;
+ unsigned long flags;
+
+};
+
+struct pcifront_sd {
+ int domain;
+ struct pcifront_device *pdev;
+};
+
+static inline struct pcifront_device *
+pcifront_get_pdev(struct pcifront_sd *sd)
+{
+ return sd->pdev;
+}
+
+static inline void pcifront_init_sd(struct pcifront_sd *sd,
+ unsigned int domain, unsigned int bus,
+ struct pcifront_device *pdev)
+{
+ sd->domain = domain;
+ sd->pdev = pdev;
+}
+
+static DEFINE_SPINLOCK(pcifront_dev_lock);
+static struct pcifront_device *pcifront_dev;
+
+static int verbose_request;
+module_param(verbose_request, int, 0644);
+
+static int errno_to_pcibios_err(int errno)
+{
+ switch (errno) {
+ case XEN_PCI_ERR_success:
+ return PCIBIOS_SUCCESSFUL;
+
+ case XEN_PCI_ERR_dev_not_found:
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ case XEN_PCI_ERR_invalid_offset:
+ case XEN_PCI_ERR_op_failed:
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ case XEN_PCI_ERR_not_implemented:
+ return PCIBIOS_FUNC_NOT_SUPPORTED;
+
+ case XEN_PCI_ERR_access_denied:
+ return PCIBIOS_SET_FAILED;
+ }
+ return errno;
+}
+
+static inline void schedule_pcifront_aer_op(struct pcifront_device *pdev)
+{
+ if (test_bit(_XEN_PCIB_active, (unsigned long *)&pdev->sh_info->flags)
+ && !test_and_set_bit(_PDEVB_op_active, &pdev->flags)) {
+ dev_dbg(&pdev->xdev->dev, "schedule aer frontend job\n");
+ schedule_work(&pdev->op_work);
+ }
+}
+
+static int do_pci_op(struct pcifront_device *pdev, struct xen_pci_op *op)
+{
+ int err = 0;
+ struct xen_pci_op *active_op = &pdev->sh_info->op;
+ unsigned long irq_flags;
+ evtchn_port_t port = pdev->evtchn;
+ unsigned irq = pdev->irq;
+ s64 ns, ns_timeout;
+ struct timeval tv;
+
+ spin_lock_irqsave(&pdev->sh_info_lock, irq_flags);
+
+ memcpy(active_op, op, sizeof(struct xen_pci_op));
+
+ /* Go */
+ wmb();
+ set_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags);
+ notify_remote_via_evtchn(port);
+
+ /*
+ * We set a poll timeout of 3 seconds but give up on return after
+ * 2 seconds. It is better to time out too late rather than too early
+ * (in the latter case we end up continually re-executing poll() with a
+ * timeout in the past). 1s difference gives plenty of slack for error.
+ */
+ do_gettimeofday(&tv);
+ ns_timeout = timeval_to_ns(&tv) + 2 * (s64)NSEC_PER_SEC;
+
+ xen_clear_irq_pending(irq);
+
+ while (test_bit(_XEN_PCIF_active,
+ (unsigned long *)&pdev->sh_info->flags)) {
+ xen_poll_irq_timeout(irq, jiffies + 3*HZ);
+ xen_clear_irq_pending(irq);
+ do_gettimeofday(&tv);
+ ns = timeval_to_ns(&tv);
+ if (ns > ns_timeout) {
+ dev_err(&pdev->xdev->dev,
+ "pciback not responding!!!\n");
+ clear_bit(_XEN_PCIF_active,
+ (unsigned long *)&pdev->sh_info->flags);
+ err = XEN_PCI_ERR_dev_not_found;
+ goto out;
+ }
+ }
+
+ /*
+ * We might lose backend service request since we
+ * reuse same evtchn with pci_conf backend response. So re-schedule
+ * aer pcifront service.
+ */
+ if (test_bit(_XEN_PCIB_active,
+ (unsigned long *)&pdev->sh_info->flags)) {
+ dev_err(&pdev->xdev->dev,
+ "schedule aer pcifront service\n");
+ schedule_pcifront_aer_op(pdev);
+ }
+
+ memcpy(op, active_op, sizeof(struct xen_pci_op));
+
+ err = op->err;
+out:
+ spin_unlock_irqrestore(&pdev->sh_info_lock, irq_flags);
+ return err;
+}
+
+/* Access to this function is spinlocked in drivers/pci/access.c */
+static int pcifront_bus_read(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 *val)
+{
+ int err = 0;
+ struct xen_pci_op op = {
+ .cmd = XEN_PCI_OP_conf_read,
+ .domain = pci_domain_nr(bus),
+ .bus = bus->number,
+ .devfn = devfn,
+ .offset = where,
+ .size = size,
+ };
+ struct pcifront_sd *sd = bus->sysdata;
+ struct pcifront_device *pdev = pcifront_get_pdev(sd);
+
+ if (verbose_request)
+ dev_info(&pdev->xdev->dev,
+ "read dev=%04x:%02x:%02x.%01x - offset %x size %d\n",
+ pci_domain_nr(bus), bus->number, PCI_SLOT(devfn),
+ PCI_FUNC(devfn), where, size);
+
+ err = do_pci_op(pdev, &op);
+
+ if (likely(!err)) {
+ if (verbose_request)
+ dev_info(&pdev->xdev->dev, "read got back value %x\n",
+ op.value);
+
+ *val = op.value;
+ } else if (err == -ENODEV) {
+ /* No device here, pretend that it just returned 0 */
+ err = 0;
+ *val = 0;
+ }
+
+ return errno_to_pcibios_err(err);
+}
+
+/* Access to this function is spinlocked in drivers/pci/access.c */
+static int pcifront_bus_write(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 val)
+{
+ struct xen_pci_op op = {
+ .cmd = XEN_PCI_OP_conf_write,
+ .domain = pci_domain_nr(bus),
+ .bus = bus->number,
+ .devfn = devfn,
+ .offset = where,
+ .size = size,
+ .value = val,
+ };
+ struct pcifront_sd *sd = bus->sysdata;
+ struct pcifront_device *pdev = pcifront_get_pdev(sd);
+
+ if (verbose_request)
+ dev_info(&pdev->xdev->dev,
+ "write dev=%04x:%02x:%02x.%01x - "
+ "offset %x size %d val %x\n",
+ pci_domain_nr(bus), bus->number,
+ PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, val);
+
+ return errno_to_pcibios_err(do_pci_op(pdev, &op));
+}
+
+struct pci_ops pcifront_bus_ops = {
+ .read = pcifront_bus_read,
+ .write = pcifront_bus_write,
+};
+
+#ifdef CONFIG_PCI_MSI
+static int pci_frontend_enable_msix(struct pci_dev *dev,
+ int **vector, int nvec)
+{
+ int err;
+ int i;
+ struct xen_pci_op op = {
+ .cmd = XEN_PCI_OP_enable_msix,
+ .domain = pci_domain_nr(dev->bus),
+ .bus = dev->bus->number,
+ .devfn = dev->devfn,
+ .value = nvec,
+ };
+ struct pcifront_sd *sd = dev->bus->sysdata;
+ struct pcifront_device *pdev = pcifront_get_pdev(sd);
+ struct msi_desc *entry;
+
+ if (nvec > SH_INFO_MAX_VEC) {
+ dev_err(&dev->dev, "too much vector for pci frontend: %x."
+ " Increase SH_INFO_MAX_VEC.\n", nvec);
+ return -EINVAL;
+ }
+
+ i = 0;
+ lis