1 #include <linux/module.h>
3 #include <linux/interrupt.h>
4 #include "modulbus_register.h"
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
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
];
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
)
49 for (i
= 0; i
< devices
; i
++)
50 if (device_table
[i
].lun
== lun
)
51 return &device_table
[i
];
55 static unsigned int modpci_offsets
[] = {
60 static int get_address_space(
61 struct carrier_as
*as
,
64 int address_space_number
)
66 struct mod_pci
*dev
= find_device_by_lun(board_number
);
68 if (dev
== NULL
|| (board_position
& (~0x1)) != 0)
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;
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
);
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
)
95 *map_bar(struct pci_dev
*dev
, unsigned int bar
, unsigned int bar_size
)
99 if (!(pci_resource_flags(dev
, bar
) & IORESOURCE_MEM
)) {
100 printk(KERN_ERR PFX
"BAR#%d not a MMIO, device not present?\n", bar
);
103 if (pci_resource_len(dev
, bar
) < bar_size
) {
104 printk(KERN_ERR PFX
"wrong BAR#%d size\n", bar
);
107 if (pci_request_region(dev
, bar
, DRIVER_NAME
) != 0) {
108 printk(KERN_ERR PFX
"could not request BAR#%d\n", bar
);
111 ret
= ioremap(pci_resource_start(dev
, bar
), bar_size
);
113 printk(KERN_ERR PFX
"could not map BAR#%d\n", bar
);
119 pci_release_regions(dev
);
124 static struct mz_callback
{
127 } modpci_callbacks
[MAX_DEVICES
][MOD_PCI_SLOTS
];
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
;
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
++) {
176 struct mz_callback
*cb
= &modpci_callbacks
[dev
->lun
][i
];
177 callback
= cb
->callback
;
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
);
191 modpci_register_isr(isrcb_t callback
,
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
);
204 cb
= &modpci_callbacks
[board_number
][board_position
];
205 cb
->callback
= callback
;
210 static int probe(struct pci_dev
*dev
, const struct pci_device_id
*id
)
212 struct mod_pci
*cfg_entry
;
216 /* check static config is present */
217 cfg_entry
= find_device_config(dev
);
220 "no config data for bus = %d, slot %d\n",
221 dev
->bus
->number
, PCI_SLOT(dev
->devfn
));
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");
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
);
244 printk(KERN_INFO PFX
"configured device maps, "
245 "lun = %d, bus = %d, slot = %d, "
246 "vaddr = %p onboard = %p\n",
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 */
253 errno
= request_irq(irq
, modpci_interrupt
,
254 IRQF_SHARED
, DRIVER_NAME
, cfg_entry
);
256 printk(KERN_ERR PFX
"could not request irq"
257 "%d for device %p, err = %d\n",
258 irq
, cfg_entry
, errno
);
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
);
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
);
273 pci_disable_device(dev
);
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
);
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
= {
295 .id_table
= mod_pci_ids
,
300 static int __init
init(void)
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");
310 if (nlun
< 0 || nlun
>= MAX_DEVICES
) {
312 "invalid number of configured devices (%d)\n", nlun
);
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
);
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
);
333 printk(KERN_INFO PFX
"registering driver\n");
334 return pci_register_driver(&pci_driver
);
337 printk(KERN_ERR PFX
"module exiting\n");
341 static void __exit
exit(void)
343 pci_unregister_driver(&pci_driver
);
344 modulbus_carrier_unregister(DRIVER_NAME
);
349 MODULE_LICENSE("GPL");
350 MODULE_AUTHOR("Juan David Gonzalez Cobas <dcobas@cern.ch>");