Blame view
drivers/pci/htirq.c
4.31 KB
8b955b0dd [PATCH] Initial g... |
1 2 3 4 5 6 7 8 9 10 11 |
/* * File: htirq.c * Purpose: Hypertransport Interrupt Capability * * Copyright (C) 2006 Linux Networx * Copyright (C) Eric Biederman <ebiederman@lnxi.com> */ #include <linux/irq.h> #include <linux/pci.h> #include <linux/spinlock.h> |
363c75db1 pci: Fix files ne... |
12 |
#include <linux/export.h> |
8b955b0dd [PATCH] Initial g... |
13 |
#include <linux/slab.h> |
95d77884c [PATCH] htirq: ti... |
14 |
#include <linux/htirq.h> |
8b955b0dd [PATCH] Initial g... |
15 16 17 18 19 20 21 22 23 24 25 26 27 |
/* Global ht irq lock. * * This is needed to serialize access to the data port in hypertransport * irq capability. * * With multiple simultaneous hypertransport irq devices it might pay * to make this more fine grained. But start with simple, stupid, and correct. */ static DEFINE_SPINLOCK(ht_irq_lock); struct ht_irq_cfg { struct pci_dev *dev; |
43539c38c [PATCH] htirq: al... |
28 29 |
/* Update callback used to cope with buggy hardware */ ht_irq_update_t *update; |
8b955b0dd [PATCH] Initial g... |
30 31 |
unsigned pos; unsigned idx; |
ec68307cc [PATCH] htirq: re... |
32 |
struct ht_irq_msg msg; |
8b955b0dd [PATCH] Initial g... |
33 |
}; |
8b955b0dd [PATCH] Initial g... |
34 |
|
ec68307cc [PATCH] htirq: re... |
35 |
void write_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg) |
8b955b0dd [PATCH] Initial g... |
36 |
{ |
dced35aeb drivers: Final ir... |
37 |
struct ht_irq_cfg *cfg = irq_get_handler_data(irq); |
8b955b0dd [PATCH] Initial g... |
38 |
unsigned long flags; |
8b955b0dd [PATCH] Initial g... |
39 |
spin_lock_irqsave(&ht_irq_lock, flags); |
ec68307cc [PATCH] htirq: re... |
40 41 42 43 44 45 46 47 |
if (cfg->msg.address_lo != msg->address_lo) { pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx); pci_write_config_dword(cfg->dev, cfg->pos + 4, msg->address_lo); } if (cfg->msg.address_hi != msg->address_hi) { pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx + 1); pci_write_config_dword(cfg->dev, cfg->pos + 4, msg->address_hi); } |
43539c38c [PATCH] htirq: al... |
48 49 |
if (cfg->update) cfg->update(cfg->dev, irq, msg); |
8b955b0dd [PATCH] Initial g... |
50 |
spin_unlock_irqrestore(&ht_irq_lock, flags); |
ec68307cc [PATCH] htirq: re... |
51 |
cfg->msg = *msg; |
8b955b0dd [PATCH] Initial g... |
52 |
} |
ec68307cc [PATCH] htirq: re... |
53 |
void fetch_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg) |
8b955b0dd [PATCH] Initial g... |
54 |
{ |
dced35aeb drivers: Final ir... |
55 |
struct ht_irq_cfg *cfg = irq_get_handler_data(irq); |
ec68307cc [PATCH] htirq: re... |
56 |
*msg = cfg->msg; |
8b955b0dd [PATCH] Initial g... |
57 |
} |
e9f7ac664 ht: Convert to ne... |
58 |
void mask_ht_irq(struct irq_data *data) |
8b955b0dd [PATCH] Initial g... |
59 |
{ |
dced35aeb drivers: Final ir... |
60 |
struct ht_irq_cfg *cfg = irq_data_get_irq_handler_data(data); |
e9f7ac664 ht: Convert to ne... |
61 |
struct ht_irq_msg msg = cfg->msg; |
8b955b0dd [PATCH] Initial g... |
62 |
|
ec68307cc [PATCH] htirq: re... |
63 |
msg.address_lo |= 1; |
e9f7ac664 ht: Convert to ne... |
64 |
write_ht_irq_msg(data->irq, &msg); |
8b955b0dd [PATCH] Initial g... |
65 |
} |
e9f7ac664 ht: Convert to ne... |
66 |
void unmask_ht_irq(struct irq_data *data) |
8b955b0dd [PATCH] Initial g... |
67 |
{ |
dced35aeb drivers: Final ir... |
68 |
struct ht_irq_cfg *cfg = irq_data_get_irq_handler_data(data); |
e9f7ac664 ht: Convert to ne... |
69 |
struct ht_irq_msg msg = cfg->msg; |
8b955b0dd [PATCH] Initial g... |
70 |
|
ec68307cc [PATCH] htirq: re... |
71 |
msg.address_lo &= ~1; |
e9f7ac664 ht: Convert to ne... |
72 |
write_ht_irq_msg(data->irq, &msg); |
8b955b0dd [PATCH] Initial g... |
73 74 75 |
} /** |
43539c38c [PATCH] htirq: al... |
76 |
* __ht_create_irq - create an irq and attach it to a device. |
8b955b0dd [PATCH] Initial g... |
77 78 |
* @dev: The hypertransport device to find the irq capability on. * @idx: Which of the possible irqs to attach to. |
43539c38c [PATCH] htirq: al... |
79 |
* @update: Function to be called when changing the htirq message |
8b955b0dd [PATCH] Initial g... |
80 81 82 |
* * The irq number of the new irq or a negative error value is returned. */ |
43539c38c [PATCH] htirq: al... |
83 |
int __ht_create_irq(struct pci_dev *dev, int idx, ht_irq_update_t *update) |
8b955b0dd [PATCH] Initial g... |
84 85 86 87 88 89 |
{ struct ht_irq_cfg *cfg; unsigned long flags; u32 data; int max_irq; int pos; |
1f3addcf2 irq: error missed... |
90 |
int irq; |
56b581ea9 irq: make ht irq_... |
91 |
int node; |
8b955b0dd [PATCH] Initial g... |
92 |
|
120a50df4 PCI: Use pci_find... |
93 |
pos = pci_find_ht_capability(dev, HT_CAPTYPE_IRQ); |
8b955b0dd [PATCH] Initial g... |
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
if (!pos) return -EINVAL; /* Verify the idx I want to use is in range */ spin_lock_irqsave(&ht_irq_lock, flags); pci_write_config_byte(dev, pos + 2, 1); pci_read_config_dword(dev, pos + 4, &data); spin_unlock_irqrestore(&ht_irq_lock, flags); max_irq = (data >> 16) & 0xff; if ( idx > max_irq) return -EINVAL; cfg = kmalloc(sizeof(*cfg), GFP_KERNEL); if (!cfg) return -ENOMEM; cfg->dev = dev; |
43539c38c [PATCH] htirq: al... |
112 |
cfg->update = update; |
8b955b0dd [PATCH] Initial g... |
113 114 |
cfg->pos = pos; cfg->idx = 0x10 + (idx * 2); |
ec68307cc [PATCH] htirq: re... |
115 116 117 |
/* Initialize msg to a value that will never match the first write. */ cfg->msg.address_lo = 0xffffffff; cfg->msg.address_hi = 0xffffffff; |
8b955b0dd [PATCH] Initial g... |
118 |
|
56b581ea9 irq: make ht irq_... |
119 120 |
node = dev_to_node(&dev->dev); irq = create_irq_nr(0, node); |
2cc21ef84 genirq: remove sp... |
121 |
|
e65ef88c2 irq: error missed... |
122 |
if (irq <= 0) { |
8b955b0dd [PATCH] Initial g... |
123 124 125 |
kfree(cfg); return -EBUSY; } |
dced35aeb drivers: Final ir... |
126 |
irq_set_handler_data(irq, cfg); |
8b955b0dd [PATCH] Initial g... |
127 128 129 130 131 132 133 134 135 136 |
if (arch_setup_ht_irq(irq, dev) < 0) { ht_destroy_irq(irq); return -EBUSY; } return irq; } /** |
43539c38c [PATCH] htirq: al... |
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
* 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); } /** |
8b955b0dd [PATCH] Initial g... |
152 |
* ht_destroy_irq - destroy an irq created with ht_create_irq |
cffb2fafb docbooks: add/fix... |
153 |
* @irq: irq to be destroyed |
8b955b0dd [PATCH] Initial g... |
154 155 156 157 158 159 160 |
* * This reverses ht_create_irq removing the specified irq from * existence. The irq should be free before this happens. */ void ht_destroy_irq(unsigned int irq) { struct ht_irq_cfg *cfg; |
dced35aeb drivers: Final ir... |
161 162 163 |
cfg = irq_get_handler_data(irq); irq_set_chip(irq, NULL); irq_set_handler_data(irq, NULL); |
8b955b0dd [PATCH] Initial g... |
164 165 166 167 |
destroy_irq(irq); kfree(cfg); } |
43539c38c [PATCH] htirq: al... |
168 |
EXPORT_SYMBOL(__ht_create_irq); |
8b955b0dd [PATCH] Initial g... |
169 170 |
EXPORT_SYMBOL(ht_create_irq); EXPORT_SYMBOL(ht_destroy_irq); |