vmod/vmodttl: fixed bug related to luns not ordered and/or not starting from zero.
[ht-drivers.git] / vmod / driver / mod-pci.c
blob55411ed061d8f39cc0d208b18a3af431ade6a8a4
1 #include <linux/module.h>
2 #include <linux/pci.h>
3 #include <linux/interrupt.h>
4 #include "modulbus_register.h"
5 #include "mod-pci.h"
7 #define MAX_DEVICES 16
8 #define DRIVER_NAME "mod-pci"
9 #define PFX DRIVER_NAME ": "
12 * this module is invoked as
13 * $ insmod mod-pci lun=0,1,2,4 bus_number=1,1,1,2 slot_number=2,3,5,1
14 * to describe the bus number and slot number associated to devices with
15 * prescribed luns.
18 static int lun[MAX_DEVICES];
19 static unsigned int nlun;
20 module_param_array(lun, int, &nlun, S_IRUGO);
22 static int bus_number[MAX_DEVICES];
23 static unsigned int nbus_number;
24 module_param_array(bus_number, int, &nbus_number, S_IRUGO);
26 static int slot_number[MAX_DEVICES];
27 static unsigned int nslot_number;
28 module_param_array(slot_number, int, &nslot_number, S_IRUGO);
30 /** static device table */
31 static struct mod_pci device_table[MAX_DEVICES];
32 static int devices;
34 static struct pci_device_id mod_pci_ids[] = {
35 { PCI_VENDOR_ID_JANZ, PCI_DEVICE_ID_JANZ_MOD_PCI_1,
36 PCI_SUBSYSTEM_VENDOR_ID_JANZ, PCI_SUBSYSTEM_ID_MOD_PCI_1_0, },
37 { PCI_VENDOR_ID_JANZ, PCI_DEVICE_ID_JANZ_MOD_PCI_1,
38 PCI_SUBSYSTEM_VENDOR_ID_JANZ, PCI_SUBSYSTEM_ID_MOD_PCI_2_0, },
39 { PCI_VENDOR_ID_JANZ, PCI_DEVICE_ID_JANZ_MOD_PCI_1,
40 PCI_SUBSYSTEM_VENDOR_ID_JANZ, PCI_SUBSYSTEM_ID_MOD_PCI_2_1, },
41 { PCI_VENDOR_ID_JANZ, PCI_DEVICE_ID_JANZ_MOD_PCI_1,
42 PCI_SUBSYSTEM_VENDOR_ID_JANZ, PCI_SUBSYSTEM_ID_MOD_PCI_3_0, },
45 static struct mod_pci *find_device_by_lun(int lun)
47 int i;
49 for (i = 0; i < devices; i++)
50 if (device_table[i].lun == lun)
51 return &device_table[i];
52 return NULL;
55 static unsigned int modpci_offsets[] = {
56 MOD_PCI_SLOT0_OFFSET,
57 MOD_PCI_SLOT1_OFFSET,
60 static int get_address_space(
61 struct carrier_as *as,
62 int board_number,
63 int board_position,
64 int address_space_number)
66 struct mod_pci *dev = find_device_by_lun(board_number);
68 if (dev == NULL || (board_position & (~0x1)) != 0)
69 return -1;
70 as->address = (unsigned long)dev->vaddr + modpci_offsets[board_position];
71 as->width = MOD_PCI_WIDTH;
72 as->size = MOD_PCI_WINDOW_SIZE/4;
73 as->is_big_endian = 1;
75 return 0;
78 static struct mod_pci *find_device_config(struct pci_dev *dev)
80 int bus = dev->bus->number;
81 int slot = PCI_SLOT(dev->devfn);
82 int i;
84 /* find the device in config table */
85 for (i = 0; i < devices; i++) {
86 struct mod_pci *entry = &device_table[i];
87 if (entry->bus_number == bus &&
88 entry->slot_number == slot)
89 return entry;
91 return NULL;
94 static void __iomem
95 *map_bar(struct pci_dev *dev, unsigned int bar, unsigned int bar_size)
97 void __iomem *ret;
99 if (!(pci_resource_flags(dev, bar) & IORESOURCE_MEM)) {
100 printk(KERN_ERR PFX "BAR#%d not a MMIO, device not present?\n", bar);
101 goto failed_request;
103 if (pci_resource_len(dev, bar) < bar_size) {
104 printk(KERN_ERR PFX "wrong BAR#%d size\n", bar);
105 goto failed_request;
107 if (pci_request_region(dev, bar, DRIVER_NAME) != 0) {
108 printk(KERN_ERR PFX "could not request BAR#%d\n", bar);
109 goto failed_request;
111 ret = ioremap(pci_resource_start(dev, bar), bar_size);
112 if (ret == NULL) {
113 printk(KERN_ERR PFX "could not map BAR#%d\n", bar);
114 goto failed_map;
116 return ret;
118 failed_map:
119 pci_release_regions(dev);
120 failed_request:
121 return NULL;
124 static struct mz_callback {
125 isrcb_t callback;
126 void *dev;
127 } modpci_callbacks[MAX_DEVICES][MOD_PCI_SLOTS];
129 static inline int
130 within_range(int board, int slot)
132 return board >= 0 && board < MAX_DEVICES &&
133 slot >= 0 && slot < MOD_PCI_SLOTS;
136 static void modpci_enable_irq(struct mod_pci *dev)
138 void __iomem *int_enable = &dev->onboard->int_enable;
139 iowrite8(0x3, int_enable);
142 static void modpci_disable_irq(struct mod_pci *dev)
144 void __iomem *int_disable = &dev->onboard->int_disable;
145 iowrite8(0x3, int_disable);
148 static void modpci_reset(struct mod_pci *dev)
150 void __iomem *reset_assert = &dev->onboard->reset_assert;
151 void __iomem *reset_deassert = &dev->onboard->reset_deassert;
152 iowrite8(0x3, reset_assert);
153 iowrite8(0x3, reset_deassert);
157 static irqreturn_t modpci_interrupt(int irq, void *device_id)
159 struct mod_pci *dev = device_id;
160 int i;
161 u8 int_stat;
162 u8 slot[] = { 0, 0 };
164 /* determine source */
165 int_stat = ioread8(&dev->onboard->int_stat);
166 slot[0] = !(int_stat & 1);
167 slot[1] = !(int_stat & 2);
168 if (!slot[0] && !slot[1])
169 return IRQ_NONE; /* not mine */
171 for (i = 0; i < MOD_PCI_SLOTS; i++) {
172 isrcb_t callback;
173 void *source;
175 if (slot[i]) {
176 struct mz_callback *cb = &modpci_callbacks[dev->lun][i];
177 callback = cb->callback;
178 source = cb->dev;
179 } else
180 continue;
181 if (callback == NULL || callback(source, NULL) < 0) {
182 printk(KERN_ERR PFX "unhandled interrupt! "
183 " irq = %d lun = %d, slot = %d\n", irq, dev->lun, i);
184 return IRQ_NONE;
187 return IRQ_HANDLED;
190 static int
191 modpci_register_isr(isrcb_t callback,
192 void *source,
193 int board_number,
194 int board_position)
196 struct mz_callback *cb;
198 if (!within_range(board_number, board_position)) {
199 printk(KERN_ERR PFX "invalid %s board number %d"
200 " and position %d\n", DRIVER_NAME,
201 board_number, board_position);
202 return -1;
204 cb = &modpci_callbacks[board_number][board_position];
205 cb->callback = callback;
206 cb->dev = source;
207 return 0;
210 static int probe(struct pci_dev *dev, const struct pci_device_id *id)
212 struct mod_pci *cfg_entry;
213 u8 irq;
214 int errno;
216 /* check static config is present */
217 cfg_entry = find_device_config(dev);
218 if (!cfg_entry) {
219 printk(KERN_INFO PFX
220 "no config data for bus = %d, slot %d\n",
221 dev->bus->number, PCI_SLOT(dev->devfn));
222 goto failed_enable;
224 printk(KERN_INFO PFX
225 "configuring device at bus = %d, slot %d\n",
226 cfg_entry->bus_number, cfg_entry->slot_number);
228 if (pci_enable_device(dev) < 0) {
229 printk(KERN_ERR PFX "could not enable device\n");
230 goto failed_enable;
233 /* map MMIO slot addresses and onboard registers */
234 cfg_entry->vaddr = map_bar(dev, MOD_PCI_BIG_BAR, MOD_PCI_BIG_BAR_SIZE);
235 cfg_entry->onboard = map_bar(dev, MOD_PCI_ONBOARD_REGS_BAR, MOD_PCI_ONBOARD_REGS_BAR_SIZE);
236 if (cfg_entry->vaddr == NULL || cfg_entry->onboard == NULL) {
237 printk(KERN_ERR PFX "could not map registers, "
238 "mmio = %p, onboard = %p\n",
239 cfg_entry->vaddr, cfg_entry->onboard);
240 goto failed_map;
243 /* success! */
244 printk(KERN_INFO PFX "configured device maps, "
245 "lun = %d, bus = %d, slot = %d, "
246 "vaddr = %p onboard = %p\n",
247 cfg_entry->lun,
248 cfg_entry->bus_number, cfg_entry->slot_number,
249 cfg_entry->vaddr, cfg_entry->onboard);
251 /* get interrupt line, enable ints and install handler */
252 irq = dev->irq;
253 errno = request_irq(irq, modpci_interrupt,
254 IRQF_SHARED, DRIVER_NAME, cfg_entry);
255 if (errno != 0) {
256 printk(KERN_ERR PFX "could not request irq"
257 "%d for device %p, err = %d\n",
258 irq, cfg_entry, errno);
259 goto failed_irq;
261 modpci_reset(cfg_entry);
262 modpci_enable_irq(cfg_entry);
263 printk(KERN_INFO PFX "got irq %d for dev %p\n", irq, cfg_entry);
264 return 0;
266 failed_irq:
267 modpci_disable_irq(cfg_entry);
268 iounmap(cfg_entry->onboard);
269 iounmap(cfg_entry->vaddr);
270 pci_release_region(dev, MOD_PCI_ONBOARD_REGS_BAR);
271 pci_release_region(dev, MOD_PCI_BIG_BAR);
272 failed_map:
273 pci_disable_device(dev);
274 failed_enable:
275 return -ENODEV;
278 static void remove(struct pci_dev *dev)
280 struct mod_pci *cfg = find_device_config(dev);
282 printk(KERN_INFO PFX "removing device %d\n", cfg->lun);
283 modpci_disable_irq(cfg);
284 printk(KERN_INFO PFX "freeing irq %d for dev %p\n", dev->irq, cfg);
285 free_irq(dev->irq, cfg);
286 iounmap(cfg->onboard);
287 iounmap(cfg->vaddr);
288 pci_release_region(dev, MOD_PCI_ONBOARD_REGS_BAR);
289 pci_release_region(dev, MOD_PCI_BIG_BAR);
290 pci_disable_device(dev);
293 static struct pci_driver pci_driver = {
294 .name = DRIVER_NAME,
295 .id_table = mod_pci_ids,
296 .probe = probe,
297 .remove = remove,
300 static int __init init(void)
302 int device = 0;
304 printk(KERN_INFO PFX "initializing driver\n");
305 if (modulbus_carrier_register(
306 DRIVER_NAME, get_address_space, modpci_register_isr)) {
307 printk(KERN_ERR PFX "could not register with modulbus\n");
308 goto failed_init;
310 if (nlun < 0 || nlun >= MAX_DEVICES) {
311 printk(KERN_ERR PFX
312 "invalid number of configured devices (%d)\n", nlun);
313 goto failed_init;
315 if (nbus_number != nlun || nslot_number != nlun) {
316 printk(KERN_ERR PFX "parameter mismatch.\n"
317 "Given %d luns, %d bus numbers, %d slot numbers\n",
318 nlun, nbus_number, nslot_number);
319 goto failed_init;
322 for (device = 0; device < nlun; device++) {
323 struct mod_pci *dev = &device_table[device];
325 dev->lun = lun[device];
326 dev->bus_number = bus_number[device];
327 dev->slot_number= slot_number[device];
328 printk(KERN_INFO PFX "shall config lun %d," "bus %d, slot %d\n",
329 dev->lun, dev->bus_number, dev->slot_number);
331 devices = device;
333 printk(KERN_INFO PFX "registering driver\n");
334 return pci_register_driver(&pci_driver);
336 failed_init:
337 printk(KERN_ERR PFX "module exiting\n");
338 return -1;
341 static void __exit exit(void)
343 pci_unregister_driver(&pci_driver);
344 modulbus_carrier_unregister(DRIVER_NAME);
347 module_init(init);
348 module_exit(exit);
349 MODULE_LICENSE("GPL");
350 MODULE_AUTHOR("Juan David Gonzalez Cobas <dcobas@cern.ch>");