aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/htirq.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/htirq.c')
-rw-r--r--drivers/pci/htirq.c101
1 files changed, 48 insertions, 53 deletions
diff --git a/drivers/pci/htirq.c b/drivers/pci/htirq.c
index 0e27f2404a83..0a8d1cce9fa0 100644
--- a/drivers/pci/htirq.c
+++ b/drivers/pci/htirq.c
@@ -25,97 +25,72 @@ static DEFINE_SPINLOCK(ht_irq_lock);
25 25
26struct ht_irq_cfg { 26struct ht_irq_cfg {
27 struct pci_dev *dev; 27 struct pci_dev *dev;
28 /* Update callback used to cope with buggy hardware */
29 ht_irq_update_t *update;
28 unsigned pos; 30 unsigned pos;
29 unsigned idx; 31 unsigned idx;
32 struct ht_irq_msg msg;
30}; 33};
31 34
32void write_ht_irq_low(unsigned int irq, u32 data)
33{
34 struct ht_irq_cfg *cfg = get_irq_data(irq);
35 unsigned long flags;
36 spin_lock_irqsave(&ht_irq_lock, flags);
37 pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx);
38 pci_write_config_dword(cfg->dev, cfg->pos + 4, data);
39 spin_unlock_irqrestore(&ht_irq_lock, flags);
40}
41 35
42void write_ht_irq_high(unsigned int irq, u32 data) 36void write_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg)
43{ 37{
44 struct ht_irq_cfg *cfg = get_irq_data(irq); 38 struct ht_irq_cfg *cfg = get_irq_data(irq);
45 unsigned long flags; 39 unsigned long flags;
46 spin_lock_irqsave(&ht_irq_lock, flags); 40 spin_lock_irqsave(&ht_irq_lock, flags);
47 pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx + 1); 41 if (cfg->msg.address_lo != msg->address_lo) {
48 pci_write_config_dword(cfg->dev, cfg->pos + 4, data); 42 pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx);
49 spin_unlock_irqrestore(&ht_irq_lock, flags); 43 pci_write_config_dword(cfg->dev, cfg->pos + 4, msg->address_lo);
50} 44 }
51 45 if (cfg->msg.address_hi != msg->address_hi) {
52u32 read_ht_irq_low(unsigned int irq) 46 pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx + 1);
53{ 47 pci_write_config_dword(cfg->dev, cfg->pos + 4, msg->address_hi);
54 struct ht_irq_cfg *cfg = get_irq_data(irq); 48 }
55 unsigned long flags; 49 if (cfg->update)
56 u32 data; 50 cfg->update(cfg->dev, irq, msg);
57 spin_lock_irqsave(&ht_irq_lock, flags);
58 pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx);
59 pci_read_config_dword(cfg->dev, cfg->pos + 4, &data);
60 spin_unlock_irqrestore(&ht_irq_lock, flags); 51 spin_unlock_irqrestore(&ht_irq_lock, flags);
61 return data; 52 cfg->msg = *msg;
62} 53}
63 54
64u32 read_ht_irq_high(unsigned int irq) 55void fetch_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg)
65{ 56{
66 struct ht_irq_cfg *cfg = get_irq_data(irq); 57 struct ht_irq_cfg *cfg = get_irq_data(irq);
67 unsigned long flags; 58 *msg = cfg->msg;
68 u32 data;
69 spin_lock_irqsave(&ht_irq_lock, flags);
70 pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx + 1);
71 pci_read_config_dword(cfg->dev, cfg->pos + 4, &data);
72 spin_unlock_irqrestore(&ht_irq_lock, flags);
73 return data;
74} 59}
75 60
76void mask_ht_irq(unsigned int irq) 61void mask_ht_irq(unsigned int irq)
77{ 62{
78 struct ht_irq_cfg *cfg; 63 struct ht_irq_cfg *cfg;
79 unsigned long flags; 64 struct ht_irq_msg msg;
80 u32 data;
81 65
82 cfg = get_irq_data(irq); 66 cfg = get_irq_data(irq);
83 67
84 spin_lock_irqsave(&ht_irq_lock, flags); 68 msg = cfg->msg;
85 pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx); 69 msg.address_lo |= 1;
86 pci_read_config_dword(cfg->dev, cfg->pos + 4, &data); 70 write_ht_irq_msg(irq, &msg);
87 data |= 1;
88 pci_write_config_dword(cfg->dev, cfg->pos + 4, data);
89 spin_unlock_irqrestore(&ht_irq_lock, flags);
90} 71}
91 72
92void unmask_ht_irq(unsigned int irq) 73void unmask_ht_irq(unsigned int irq)
93{ 74{
94 struct ht_irq_cfg *cfg; 75 struct ht_irq_cfg *cfg;
95 unsigned long flags; 76 struct ht_irq_msg msg;
96 u32 data;
97 77
98 cfg = get_irq_data(irq); 78 cfg = get_irq_data(irq);
99 79
100 spin_lock_irqsave(&ht_irq_lock, flags); 80 msg = cfg->msg;
101 pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx); 81 msg.address_lo &= ~1;
102 pci_read_config_dword(cfg->dev, cfg->pos + 4, &data); 82 write_ht_irq_msg(irq, &msg);
103 data &= ~1;
104 pci_write_config_dword(cfg->dev, cfg->pos + 4, data);
105 spin_unlock_irqrestore(&ht_irq_lock, flags);
106} 83}
107 84
108/** 85/**
109 * ht_create_irq - create an irq and attach it to a device. 86 * __ht_create_irq - create an irq and attach it to a device.
110 * @dev: The hypertransport device to find the irq capability on. 87 * @dev: The hypertransport device to find the irq capability on.
111 * @idx: Which of the possible irqs to attach to. 88 * @idx: Which of the possible irqs to attach to.
112 * 89 * @update: Function to be called when changing the htirq message
113 * ht_create_irq is needs to be called for all hypertransport devices
114 * that generate irqs.
115 * 90 *
116 * The irq number of the new irq or a negative error value is returned. 91 * The irq number of the new irq or a negative error value is returned.
117 */ 92 */
118int ht_create_irq(struct pci_dev *dev, int idx) 93int __ht_create_irq(struct pci_dev *dev, int idx, ht_irq_update_t *update)
119{ 94{
120 struct ht_irq_cfg *cfg; 95 struct ht_irq_cfg *cfg;
121 unsigned long flags; 96 unsigned long flags;
@@ -150,8 +125,12 @@ int ht_create_irq(struct pci_dev *dev, int idx)
150 return -ENOMEM; 125 return -ENOMEM;
151 126
152 cfg->dev = dev; 127 cfg->dev = dev;
128 cfg->update = update;
153 cfg->pos = pos; 129 cfg->pos = pos;
154 cfg->idx = 0x10 + (idx * 2); 130 cfg->idx = 0x10 + (idx * 2);
131 /* Initialize msg to a value that will never match the first write. */
132 cfg->msg.address_lo = 0xffffffff;
133 cfg->msg.address_hi = 0xffffffff;
155 134
156 irq = create_irq(); 135 irq = create_irq();
157 if (irq < 0) { 136 if (irq < 0) {
@@ -169,6 +148,21 @@ int ht_create_irq(struct pci_dev *dev, int idx)
169} 148}
170 149
171/** 150/**
151 * ht_create_irq - create an irq and attach it to a device.
152 * @dev: The hypertransport device to find the irq capability on.
153 * @idx: Which of the possible irqs to attach to.
154 *
155 * ht_create_irq needs to be called for all hypertransport devices
156 * that generate irqs.
157 *
158 * The irq number of the new irq or a negative error value is returned.
159 */
160int ht_create_irq(struct pci_dev *dev, int idx)
161{
162 return __ht_create_irq(dev, idx, NULL);
163}
164
165/**
172 * ht_destroy_irq - destroy an irq created with ht_create_irq 166 * ht_destroy_irq - destroy an irq created with ht_create_irq
173 * 167 *
174 * This reverses ht_create_irq removing the specified irq from 168 * This reverses ht_create_irq removing the specified irq from
@@ -186,5 +180,6 @@ void ht_destroy_irq(unsigned int irq)
186 kfree(cfg); 180 kfree(cfg);
187} 181}
188 182
183EXPORT_SYMBOL(__ht_create_irq);
189EXPORT_SYMBOL(ht_create_irq); 184EXPORT_SYMBOL(ht_create_irq);
190EXPORT_SYMBOL(ht_destroy_irq); 185EXPORT_SYMBOL(ht_destroy_irq);