Commit 43539c38 authored by Eric W. Biederman's avatar Eric W. Biederman Committed by Linus Torvalds

[PATCH] htirq: allow buggy drivers of buggy hardware to write the registers

This patch adds a variant of ht_create_irq __ht_create_irq that takes an
aditional parameter update that is a function that is called whenever we want
to write to a drivers htirq configuration registers.

This is needed to support the ipath_iba6110 because it's registers in the
proper location are not actually conected to the hardware that controlls
interrupt delivery.

[bos@serpentine.com: fixes]
Signed-off-by: default avatarEric W. Biederman <ebiederm@xmission.com>
Cc: Andi Kleen <ak@suse.de>
Cc: <olson@pathscale.com>
Cc: Roland Dreier <rolandd@cisco.com>
Signed-off-by: default avatarBryan O'Sullivan <bryan.osullivan@qlogic.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent ec68307c
...@@ -25,6 +25,8 @@ static DEFINE_SPINLOCK(ht_irq_lock); ...@@ -25,6 +25,8 @@ static DEFINE_SPINLOCK(ht_irq_lock);
struct ht_irq_cfg { struct ht_irq_cfg {
struct pci_dev *dev; struct pci_dev *dev;
/* Update callback used to cope with buggy hardware */
ht_irq_update_t *update;
unsigned pos; unsigned pos;
unsigned idx; unsigned idx;
struct ht_irq_msg msg; struct ht_irq_msg msg;
...@@ -44,6 +46,8 @@ void write_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg) ...@@ -44,6 +46,8 @@ void write_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg)
pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx + 1); pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx + 1);
pci_write_config_dword(cfg->dev, cfg->pos + 4, msg->address_hi); pci_write_config_dword(cfg->dev, cfg->pos + 4, msg->address_hi);
} }
if (cfg->update)
cfg->update(cfg->dev, irq, msg);
spin_unlock_irqrestore(&ht_irq_lock, flags); spin_unlock_irqrestore(&ht_irq_lock, flags);
cfg->msg = *msg; cfg->msg = *msg;
} }
...@@ -79,16 +83,14 @@ void unmask_ht_irq(unsigned int irq) ...@@ -79,16 +83,14 @@ void unmask_ht_irq(unsigned int irq)
} }
/** /**
* ht_create_irq - create an irq and attach it to a device. * __ht_create_irq - create an irq and attach it to a device.
* @dev: The hypertransport device to find the irq capability on. * @dev: The hypertransport device to find the irq capability on.
* @idx: Which of the possible irqs to attach to. * @idx: Which of the possible irqs to attach to.
* * @update: Function to be called when changing the htirq message
* ht_create_irq is needs to be called for all hypertransport devices
* that generate irqs.
* *
* The irq number of the new irq or a negative error value is returned. * The irq number of the new irq or a negative error value is returned.
*/ */
int ht_create_irq(struct pci_dev *dev, int idx) int __ht_create_irq(struct pci_dev *dev, int idx, ht_irq_update_t *update)
{ {
struct ht_irq_cfg *cfg; struct ht_irq_cfg *cfg;
unsigned long flags; unsigned long flags;
...@@ -123,6 +125,7 @@ int ht_create_irq(struct pci_dev *dev, int idx) ...@@ -123,6 +125,7 @@ int ht_create_irq(struct pci_dev *dev, int idx)
return -ENOMEM; return -ENOMEM;
cfg->dev = dev; cfg->dev = dev;
cfg->update = update;
cfg->pos = pos; cfg->pos = pos;
cfg->idx = 0x10 + (idx * 2); cfg->idx = 0x10 + (idx * 2);
/* Initialize msg to a value that will never match the first write. */ /* Initialize msg to a value that will never match the first write. */
...@@ -144,6 +147,21 @@ int ht_create_irq(struct pci_dev *dev, int idx) ...@@ -144,6 +147,21 @@ int ht_create_irq(struct pci_dev *dev, int idx)
return irq; return irq;
} }
/**
* ht_create_irq - create an irq and attach it to a device.
* @dev: The hypertransport device to find the irq capability on.
* @idx: Which of the possible irqs to attach to.
*
* ht_create_irq needs to be called for all hypertransport devices
* that generate irqs.
*
* The irq number of the new irq or a negative error value is returned.
*/
int ht_create_irq(struct pci_dev *dev, int idx)
{
return __ht_create_irq(dev, idx, NULL);
}
/** /**
* ht_destroy_irq - destroy an irq created with ht_create_irq * ht_destroy_irq - destroy an irq created with ht_create_irq
* *
...@@ -162,5 +180,6 @@ void ht_destroy_irq(unsigned int irq) ...@@ -162,5 +180,6 @@ void ht_destroy_irq(unsigned int irq)
kfree(cfg); kfree(cfg);
} }
EXPORT_SYMBOL(__ht_create_irq);
EXPORT_SYMBOL(ht_create_irq); EXPORT_SYMBOL(ht_create_irq);
EXPORT_SYMBOL(ht_destroy_irq); EXPORT_SYMBOL(ht_destroy_irq);
...@@ -15,4 +15,9 @@ void unmask_ht_irq(unsigned int irq); ...@@ -15,4 +15,9 @@ void unmask_ht_irq(unsigned int irq);
/* The arch hook for getting things started */ /* The arch hook for getting things started */
int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev); int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev);
/* For drivers of buggy hardware */
typedef void (ht_irq_update_t)(struct pci_dev *dev, int irq,
struct ht_irq_msg *msg);
int __ht_create_irq(struct pci_dev *dev, int idx, ht_irq_update_t *update);
#endif /* LINUX_HTIRQ_H */ #endif /* LINUX_HTIRQ_H */
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