Blame view

drivers/pci/htirq.c 4.31 KB
8b955b0dd   Eric W. Biederman   [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   Paul Gortmaker   pci: Fix files ne...
12
  #include <linux/export.h>
8b955b0dd   Eric W. Biederman   [PATCH] Initial g...
13
  #include <linux/slab.h>
95d77884c   Eric W. Biederman   [PATCH] htirq: ti...
14
  #include <linux/htirq.h>
8b955b0dd   Eric W. Biederman   [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   Eric W. Biederman   [PATCH] htirq: al...
28
29
  	 /* Update callback used to cope with buggy hardware */
  	ht_irq_update_t *update;
8b955b0dd   Eric W. Biederman   [PATCH] Initial g...
30
31
  	unsigned pos;
  	unsigned idx;
ec68307cc   Eric W. Biederman   [PATCH] htirq: re...
32
  	struct ht_irq_msg msg;
8b955b0dd   Eric W. Biederman   [PATCH] Initial g...
33
  };
8b955b0dd   Eric W. Biederman   [PATCH] Initial g...
34

ec68307cc   Eric W. Biederman   [PATCH] htirq: re...
35
  void write_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg)
8b955b0dd   Eric W. Biederman   [PATCH] Initial g...
36
  {
dced35aeb   Thomas Gleixner   drivers: Final ir...
37
  	struct ht_irq_cfg *cfg = irq_get_handler_data(irq);
8b955b0dd   Eric W. Biederman   [PATCH] Initial g...
38
  	unsigned long flags;
8b955b0dd   Eric W. Biederman   [PATCH] Initial g...
39
  	spin_lock_irqsave(&ht_irq_lock, flags);
ec68307cc   Eric W. Biederman   [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   Eric W. Biederman   [PATCH] htirq: al...
48
49
  	if (cfg->update)
  		cfg->update(cfg->dev, irq, msg);
8b955b0dd   Eric W. Biederman   [PATCH] Initial g...
50
  	spin_unlock_irqrestore(&ht_irq_lock, flags);
ec68307cc   Eric W. Biederman   [PATCH] htirq: re...
51
  	cfg->msg = *msg;
8b955b0dd   Eric W. Biederman   [PATCH] Initial g...
52
  }
ec68307cc   Eric W. Biederman   [PATCH] htirq: re...
53
  void fetch_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg)
8b955b0dd   Eric W. Biederman   [PATCH] Initial g...
54
  {
dced35aeb   Thomas Gleixner   drivers: Final ir...
55
  	struct ht_irq_cfg *cfg = irq_get_handler_data(irq);
ec68307cc   Eric W. Biederman   [PATCH] htirq: re...
56
  	*msg = cfg->msg;
8b955b0dd   Eric W. Biederman   [PATCH] Initial g...
57
  }
e9f7ac664   Thomas Gleixner   ht: Convert to ne...
58
  void mask_ht_irq(struct irq_data *data)
8b955b0dd   Eric W. Biederman   [PATCH] Initial g...
59
  {
dced35aeb   Thomas Gleixner   drivers: Final ir...
60
  	struct ht_irq_cfg *cfg = irq_data_get_irq_handler_data(data);
e9f7ac664   Thomas Gleixner   ht: Convert to ne...
61
  	struct ht_irq_msg msg = cfg->msg;
8b955b0dd   Eric W. Biederman   [PATCH] Initial g...
62

ec68307cc   Eric W. Biederman   [PATCH] htirq: re...
63
  	msg.address_lo |= 1;
e9f7ac664   Thomas Gleixner   ht: Convert to ne...
64
  	write_ht_irq_msg(data->irq, &msg);
8b955b0dd   Eric W. Biederman   [PATCH] Initial g...
65
  }
e9f7ac664   Thomas Gleixner   ht: Convert to ne...
66
  void unmask_ht_irq(struct irq_data *data)
8b955b0dd   Eric W. Biederman   [PATCH] Initial g...
67
  {
dced35aeb   Thomas Gleixner   drivers: Final ir...
68
  	struct ht_irq_cfg *cfg = irq_data_get_irq_handler_data(data);
e9f7ac664   Thomas Gleixner   ht: Convert to ne...
69
  	struct ht_irq_msg msg = cfg->msg;
8b955b0dd   Eric W. Biederman   [PATCH] Initial g...
70

ec68307cc   Eric W. Biederman   [PATCH] htirq: re...
71
  	msg.address_lo &= ~1;
e9f7ac664   Thomas Gleixner   ht: Convert to ne...
72
  	write_ht_irq_msg(data->irq, &msg);
8b955b0dd   Eric W. Biederman   [PATCH] Initial g...
73
74
75
  }
  
  /**
43539c38c   Eric W. Biederman   [PATCH] htirq: al...
76
   * __ht_create_irq - create an irq and attach it to a device.
8b955b0dd   Eric W. Biederman   [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   Eric W. Biederman   [PATCH] htirq: al...
79
   * @update: Function to be called when changing the htirq message
8b955b0dd   Eric W. Biederman   [PATCH] Initial g...
80
81
82
   *
   * The irq number of the new irq or a negative error value is returned.
   */
43539c38c   Eric W. Biederman   [PATCH] htirq: al...
83
  int __ht_create_irq(struct pci_dev *dev, int idx, ht_irq_update_t *update)
8b955b0dd   Eric W. Biederman   [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   Yinghai Lu   irq: error missed...
90
  	int irq;
56b581ea9   Yinghai Lu   irq: make ht irq_...
91
  	int node;
8b955b0dd   Eric W. Biederman   [PATCH] Initial g...
92

120a50df4   Michael Ellerman   PCI: Use pci_find...
93
  	pos = pci_find_ht_capability(dev, HT_CAPTYPE_IRQ);
8b955b0dd   Eric W. Biederman   [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   Eric W. Biederman   [PATCH] htirq: al...
112
  	cfg->update = update;
8b955b0dd   Eric W. Biederman   [PATCH] Initial g...
113
114
  	cfg->pos = pos;
  	cfg->idx = 0x10 + (idx * 2);
ec68307cc   Eric W. Biederman   [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   Eric W. Biederman   [PATCH] Initial g...
118

56b581ea9   Yinghai Lu   irq: make ht irq_...
119
120
  	node = dev_to_node(&dev->dev);
  	irq = create_irq_nr(0, node);
2cc21ef84   Thomas Gleixner   genirq: remove sp...
121

e65ef88c2   Dean Nelson   irq: error missed...
122
  	if (irq <= 0) {
8b955b0dd   Eric W. Biederman   [PATCH] Initial g...
123
124
125
  		kfree(cfg);
  		return -EBUSY;
  	}
dced35aeb   Thomas Gleixner   drivers: Final ir...
126
  	irq_set_handler_data(irq, cfg);
8b955b0dd   Eric W. Biederman   [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   Eric W. Biederman   [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   Eric W. Biederman   [PATCH] Initial g...
152
   * ht_destroy_irq - destroy an irq created with ht_create_irq
cffb2fafb   Randy Dunlap   docbooks: add/fix...
153
   * @irq: irq to be destroyed
8b955b0dd   Eric W. Biederman   [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   Thomas Gleixner   drivers: Final ir...
161
162
163
  	cfg = irq_get_handler_data(irq);
  	irq_set_chip(irq, NULL);
  	irq_set_handler_data(irq, NULL);
8b955b0dd   Eric W. Biederman   [PATCH] Initial g...
164
165
166
167
  	destroy_irq(irq);
  
  	kfree(cfg);
  }
43539c38c   Eric W. Biederman   [PATCH] htirq: al...
168
  EXPORT_SYMBOL(__ht_create_irq);
8b955b0dd   Eric W. Biederman   [PATCH] Initial g...
169
170
  EXPORT_SYMBOL(ht_create_irq);
  EXPORT_SYMBOL(ht_destroy_irq);