1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * driver for the TEWS TPCI-200 device |
4 | * |
5 | * Copyright (C) 2009-2012 CERN (www.cern.ch) |
6 | * Author: Nicolas Serafini, EIC2 SA |
7 | * Author: Samuel Iglesias Gonsalvez <siglesias@igalia.com> |
8 | */ |
9 | |
10 | #include <linux/module.h> |
11 | #include <linux/slab.h> |
12 | #include "tpci200.h" |
13 | |
14 | static const u16 tpci200_status_timeout[] = { |
15 | TPCI200_A_TIMEOUT, |
16 | TPCI200_B_TIMEOUT, |
17 | TPCI200_C_TIMEOUT, |
18 | TPCI200_D_TIMEOUT, |
19 | }; |
20 | |
21 | static const u16 tpci200_status_error[] = { |
22 | TPCI200_A_ERROR, |
23 | TPCI200_B_ERROR, |
24 | TPCI200_C_ERROR, |
25 | TPCI200_D_ERROR, |
26 | }; |
27 | |
28 | static const size_t tpci200_space_size[IPACK_SPACE_COUNT] = { |
29 | [IPACK_IO_SPACE] = TPCI200_IO_SPACE_SIZE, |
30 | [IPACK_ID_SPACE] = TPCI200_ID_SPACE_SIZE, |
31 | [IPACK_INT_SPACE] = TPCI200_INT_SPACE_SIZE, |
32 | [IPACK_MEM8_SPACE] = TPCI200_MEM8_SPACE_SIZE, |
33 | [IPACK_MEM16_SPACE] = TPCI200_MEM16_SPACE_SIZE, |
34 | }; |
35 | |
36 | static const size_t tpci200_space_interval[IPACK_SPACE_COUNT] = { |
37 | [IPACK_IO_SPACE] = TPCI200_IO_SPACE_INTERVAL, |
38 | [IPACK_ID_SPACE] = TPCI200_ID_SPACE_INTERVAL, |
39 | [IPACK_INT_SPACE] = TPCI200_INT_SPACE_INTERVAL, |
40 | [IPACK_MEM8_SPACE] = TPCI200_MEM8_SPACE_INTERVAL, |
41 | [IPACK_MEM16_SPACE] = TPCI200_MEM16_SPACE_INTERVAL, |
42 | }; |
43 | |
44 | static struct tpci200_board *check_slot(struct ipack_device *dev) |
45 | { |
46 | struct tpci200_board *tpci200; |
47 | |
48 | if (dev == NULL) |
49 | return NULL; |
50 | |
51 | |
52 | tpci200 = dev_get_drvdata(dev: dev->bus->parent); |
53 | |
54 | if (tpci200 == NULL) { |
55 | dev_info(&dev->dev, "carrier board not found\n" ); |
56 | return NULL; |
57 | } |
58 | |
59 | if (dev->slot >= TPCI200_NB_SLOT) { |
60 | dev_info(&dev->dev, |
61 | "Slot [%d:%d] doesn't exist! Last tpci200 slot is %d.\n" , |
62 | dev->bus->bus_nr, dev->slot, TPCI200_NB_SLOT-1); |
63 | return NULL; |
64 | } |
65 | |
66 | return tpci200; |
67 | } |
68 | |
69 | static void tpci200_clear_mask(struct tpci200_board *tpci200, |
70 | __le16 __iomem *addr, u16 mask) |
71 | { |
72 | unsigned long flags; |
73 | spin_lock_irqsave(&tpci200->regs_lock, flags); |
74 | iowrite16(ioread16(addr) & (~mask), addr); |
75 | spin_unlock_irqrestore(lock: &tpci200->regs_lock, flags); |
76 | } |
77 | |
78 | static void tpci200_set_mask(struct tpci200_board *tpci200, |
79 | __le16 __iomem *addr, u16 mask) |
80 | { |
81 | unsigned long flags; |
82 | spin_lock_irqsave(&tpci200->regs_lock, flags); |
83 | iowrite16(ioread16(addr) | mask, addr); |
84 | spin_unlock_irqrestore(lock: &tpci200->regs_lock, flags); |
85 | } |
86 | |
87 | static void tpci200_unregister(struct tpci200_board *tpci200) |
88 | { |
89 | free_irq(tpci200->info->pdev->irq, (void *) tpci200); |
90 | |
91 | pci_iounmap(dev: tpci200->info->pdev, tpci200->info->interface_regs); |
92 | |
93 | pci_release_region(tpci200->info->pdev, TPCI200_IP_INTERFACE_BAR); |
94 | pci_release_region(tpci200->info->pdev, TPCI200_IO_ID_INT_SPACES_BAR); |
95 | pci_release_region(tpci200->info->pdev, TPCI200_MEM16_SPACE_BAR); |
96 | pci_release_region(tpci200->info->pdev, TPCI200_MEM8_SPACE_BAR); |
97 | |
98 | pci_disable_device(dev: tpci200->info->pdev); |
99 | } |
100 | |
101 | static void tpci200_enable_irq(struct tpci200_board *tpci200, |
102 | int islot) |
103 | { |
104 | tpci200_set_mask(tpci200, |
105 | addr: &tpci200->info->interface_regs->control[islot], |
106 | TPCI200_INT0_EN | TPCI200_INT1_EN); |
107 | } |
108 | |
109 | static void tpci200_disable_irq(struct tpci200_board *tpci200, |
110 | int islot) |
111 | { |
112 | tpci200_clear_mask(tpci200, |
113 | addr: &tpci200->info->interface_regs->control[islot], |
114 | TPCI200_INT0_EN | TPCI200_INT1_EN); |
115 | } |
116 | |
117 | static irqreturn_t tpci200_slot_irq(struct slot_irq *slot_irq) |
118 | { |
119 | irqreturn_t ret; |
120 | |
121 | if (!slot_irq) |
122 | return -ENODEV; |
123 | ret = slot_irq->handler(slot_irq->arg); |
124 | |
125 | return ret; |
126 | } |
127 | |
128 | static irqreturn_t tpci200_interrupt(int irq, void *dev_id) |
129 | { |
130 | struct tpci200_board *tpci200 = (struct tpci200_board *) dev_id; |
131 | struct slot_irq *slot_irq; |
132 | irqreturn_t ret; |
133 | u16 status_reg; |
134 | int i; |
135 | |
136 | /* Read status register */ |
137 | status_reg = ioread16(&tpci200->info->interface_regs->status); |
138 | |
139 | /* Did we cause the interrupt? */ |
140 | if (!(status_reg & TPCI200_SLOT_INT_MASK)) |
141 | return IRQ_NONE; |
142 | |
143 | /* callback to the IRQ handler for the corresponding slot */ |
144 | rcu_read_lock(); |
145 | for (i = 0; i < TPCI200_NB_SLOT; i++) { |
146 | if (!(status_reg & ((TPCI200_A_INT0 | TPCI200_A_INT1) << (2 * i)))) |
147 | continue; |
148 | slot_irq = rcu_dereference(tpci200->slots[i].irq); |
149 | ret = tpci200_slot_irq(slot_irq); |
150 | if (ret == -ENODEV) { |
151 | dev_info(&tpci200->info->pdev->dev, |
152 | "No registered ISR for slot [%d:%d]!. IRQ will be disabled.\n" , |
153 | tpci200->number, i); |
154 | tpci200_disable_irq(tpci200, islot: i); |
155 | } |
156 | } |
157 | rcu_read_unlock(); |
158 | |
159 | return IRQ_HANDLED; |
160 | } |
161 | |
162 | static int tpci200_free_irq(struct ipack_device *dev) |
163 | { |
164 | struct slot_irq *slot_irq; |
165 | struct tpci200_board *tpci200; |
166 | |
167 | tpci200 = check_slot(dev); |
168 | if (tpci200 == NULL) |
169 | return -EINVAL; |
170 | |
171 | if (mutex_lock_interruptible(&tpci200->mutex)) |
172 | return -ERESTARTSYS; |
173 | |
174 | if (tpci200->slots[dev->slot].irq == NULL) { |
175 | mutex_unlock(lock: &tpci200->mutex); |
176 | return -EINVAL; |
177 | } |
178 | |
179 | tpci200_disable_irq(tpci200, islot: dev->slot); |
180 | slot_irq = tpci200->slots[dev->slot].irq; |
181 | /* uninstall handler */ |
182 | RCU_INIT_POINTER(tpci200->slots[dev->slot].irq, NULL); |
183 | synchronize_rcu(); |
184 | kfree(objp: slot_irq); |
185 | mutex_unlock(lock: &tpci200->mutex); |
186 | return 0; |
187 | } |
188 | |
189 | static int tpci200_request_irq(struct ipack_device *dev, |
190 | irqreturn_t (*handler)(void *), void *arg) |
191 | { |
192 | int res = 0; |
193 | struct slot_irq *slot_irq; |
194 | struct tpci200_board *tpci200; |
195 | |
196 | tpci200 = check_slot(dev); |
197 | if (tpci200 == NULL) |
198 | return -EINVAL; |
199 | |
200 | if (mutex_lock_interruptible(&tpci200->mutex)) |
201 | return -ERESTARTSYS; |
202 | |
203 | if (tpci200->slots[dev->slot].irq != NULL) { |
204 | dev_err(&dev->dev, |
205 | "Slot [%d:%d] IRQ already registered !\n" , |
206 | dev->bus->bus_nr, |
207 | dev->slot); |
208 | res = -EINVAL; |
209 | goto out_unlock; |
210 | } |
211 | |
212 | slot_irq = kzalloc(size: sizeof(struct slot_irq), GFP_KERNEL); |
213 | if (slot_irq == NULL) { |
214 | dev_err(&dev->dev, |
215 | "Slot [%d:%d] unable to allocate memory for IRQ !\n" , |
216 | dev->bus->bus_nr, dev->slot); |
217 | res = -ENOMEM; |
218 | goto out_unlock; |
219 | } |
220 | |
221 | /* |
222 | * WARNING: Setup Interrupt Vector in the IndustryPack device |
223 | * before an IRQ request. |
224 | * Read the User Manual of your IndustryPack device to know |
225 | * where to write the vector in memory. |
226 | */ |
227 | slot_irq->handler = handler; |
228 | slot_irq->arg = arg; |
229 | slot_irq->holder = dev; |
230 | |
231 | rcu_assign_pointer(tpci200->slots[dev->slot].irq, slot_irq); |
232 | tpci200_enable_irq(tpci200, islot: dev->slot); |
233 | |
234 | out_unlock: |
235 | mutex_unlock(lock: &tpci200->mutex); |
236 | return res; |
237 | } |
238 | |
239 | static int tpci200_register(struct tpci200_board *tpci200) |
240 | { |
241 | int i; |
242 | int res; |
243 | phys_addr_t ioidint_base; |
244 | unsigned short slot_ctrl; |
245 | |
246 | if (pci_enable_device(dev: tpci200->info->pdev) < 0) |
247 | return -ENODEV; |
248 | |
249 | /* Request IP interface register (Bar 2) */ |
250 | res = pci_request_region(tpci200->info->pdev, TPCI200_IP_INTERFACE_BAR, |
251 | "Carrier IP interface registers" ); |
252 | if (res) { |
253 | dev_err(&tpci200->info->pdev->dev, |
254 | "(bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 2 !" , |
255 | tpci200->info->pdev->bus->number, |
256 | tpci200->info->pdev->devfn); |
257 | goto err_disable_device; |
258 | } |
259 | |
260 | /* Request IO ID INT space (Bar 3) */ |
261 | res = pci_request_region(tpci200->info->pdev, |
262 | TPCI200_IO_ID_INT_SPACES_BAR, |
263 | "Carrier IO ID INT space" ); |
264 | if (res) { |
265 | dev_err(&tpci200->info->pdev->dev, |
266 | "(bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 3 !" , |
267 | tpci200->info->pdev->bus->number, |
268 | tpci200->info->pdev->devfn); |
269 | goto err_ip_interface_bar; |
270 | } |
271 | |
272 | /* Request MEM8 space (Bar 5) */ |
273 | res = pci_request_region(tpci200->info->pdev, TPCI200_MEM8_SPACE_BAR, |
274 | "Carrier MEM8 space" ); |
275 | if (res) { |
276 | dev_err(&tpci200->info->pdev->dev, |
277 | "(bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 5!" , |
278 | tpci200->info->pdev->bus->number, |
279 | tpci200->info->pdev->devfn); |
280 | goto err_io_id_int_spaces_bar; |
281 | } |
282 | |
283 | /* Request MEM16 space (Bar 4) */ |
284 | res = pci_request_region(tpci200->info->pdev, TPCI200_MEM16_SPACE_BAR, |
285 | "Carrier MEM16 space" ); |
286 | if (res) { |
287 | dev_err(&tpci200->info->pdev->dev, |
288 | "(bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 4!" , |
289 | tpci200->info->pdev->bus->number, |
290 | tpci200->info->pdev->devfn); |
291 | goto err_mem8_space_bar; |
292 | } |
293 | |
294 | /* Map internal tpci200 driver user space */ |
295 | tpci200->info->interface_regs = |
296 | ioremap(pci_resource_start(tpci200->info->pdev, |
297 | TPCI200_IP_INTERFACE_BAR), |
298 | TPCI200_IFACE_SIZE); |
299 | if (!tpci200->info->interface_regs) { |
300 | dev_err(&tpci200->info->pdev->dev, |
301 | "(bn 0x%X, sn 0x%X) failed to map driver user space!" , |
302 | tpci200->info->pdev->bus->number, |
303 | tpci200->info->pdev->devfn); |
304 | res = -ENOMEM; |
305 | goto err_mem16_space_bar; |
306 | } |
307 | |
308 | /* Initialize lock that protects interface_regs */ |
309 | spin_lock_init(&tpci200->regs_lock); |
310 | |
311 | ioidint_base = pci_resource_start(tpci200->info->pdev, |
312 | TPCI200_IO_ID_INT_SPACES_BAR); |
313 | tpci200->mod_mem[IPACK_IO_SPACE] = ioidint_base + TPCI200_IO_SPACE_OFF; |
314 | tpci200->mod_mem[IPACK_ID_SPACE] = ioidint_base + TPCI200_ID_SPACE_OFF; |
315 | tpci200->mod_mem[IPACK_INT_SPACE] = |
316 | ioidint_base + TPCI200_INT_SPACE_OFF; |
317 | tpci200->mod_mem[IPACK_MEM8_SPACE] = |
318 | pci_resource_start(tpci200->info->pdev, |
319 | TPCI200_MEM8_SPACE_BAR); |
320 | tpci200->mod_mem[IPACK_MEM16_SPACE] = |
321 | pci_resource_start(tpci200->info->pdev, |
322 | TPCI200_MEM16_SPACE_BAR); |
323 | |
324 | /* Set the default parameters of the slot |
325 | * INT0 disabled, level sensitive |
326 | * INT1 disabled, level sensitive |
327 | * error interrupt disabled |
328 | * timeout interrupt disabled |
329 | * recover time disabled |
330 | * clock rate 8 MHz |
331 | */ |
332 | slot_ctrl = 0; |
333 | for (i = 0; i < TPCI200_NB_SLOT; i++) |
334 | writew(val: slot_ctrl, addr: &tpci200->info->interface_regs->control[i]); |
335 | |
336 | res = request_irq(irq: tpci200->info->pdev->irq, |
337 | handler: tpci200_interrupt, IRQF_SHARED, |
338 | KBUILD_MODNAME, dev: (void *) tpci200); |
339 | if (res) { |
340 | dev_err(&tpci200->info->pdev->dev, |
341 | "(bn 0x%X, sn 0x%X) unable to register IRQ !" , |
342 | tpci200->info->pdev->bus->number, |
343 | tpci200->info->pdev->devfn); |
344 | goto err_interface_regs; |
345 | } |
346 | |
347 | return 0; |
348 | |
349 | err_interface_regs: |
350 | pci_iounmap(dev: tpci200->info->pdev, tpci200->info->interface_regs); |
351 | err_mem16_space_bar: |
352 | pci_release_region(tpci200->info->pdev, TPCI200_MEM16_SPACE_BAR); |
353 | err_mem8_space_bar: |
354 | pci_release_region(tpci200->info->pdev, TPCI200_MEM8_SPACE_BAR); |
355 | err_io_id_int_spaces_bar: |
356 | pci_release_region(tpci200->info->pdev, TPCI200_IO_ID_INT_SPACES_BAR); |
357 | err_ip_interface_bar: |
358 | pci_release_region(tpci200->info->pdev, TPCI200_IP_INTERFACE_BAR); |
359 | err_disable_device: |
360 | pci_disable_device(dev: tpci200->info->pdev); |
361 | return res; |
362 | } |
363 | |
364 | static int tpci200_get_clockrate(struct ipack_device *dev) |
365 | { |
366 | struct tpci200_board *tpci200 = check_slot(dev); |
367 | __le16 __iomem *addr; |
368 | |
369 | if (!tpci200) |
370 | return -ENODEV; |
371 | |
372 | addr = &tpci200->info->interface_regs->control[dev->slot]; |
373 | return (ioread16(addr) & TPCI200_CLK32) ? 32 : 8; |
374 | } |
375 | |
376 | static int tpci200_set_clockrate(struct ipack_device *dev, int mherz) |
377 | { |
378 | struct tpci200_board *tpci200 = check_slot(dev); |
379 | __le16 __iomem *addr; |
380 | |
381 | if (!tpci200) |
382 | return -ENODEV; |
383 | |
384 | addr = &tpci200->info->interface_regs->control[dev->slot]; |
385 | |
386 | switch (mherz) { |
387 | case 8: |
388 | tpci200_clear_mask(tpci200, addr, TPCI200_CLK32); |
389 | break; |
390 | case 32: |
391 | tpci200_set_mask(tpci200, addr, TPCI200_CLK32); |
392 | break; |
393 | default: |
394 | return -EINVAL; |
395 | } |
396 | return 0; |
397 | } |
398 | |
399 | static int tpci200_get_error(struct ipack_device *dev) |
400 | { |
401 | struct tpci200_board *tpci200 = check_slot(dev); |
402 | __le16 __iomem *addr; |
403 | u16 mask; |
404 | |
405 | if (!tpci200) |
406 | return -ENODEV; |
407 | |
408 | addr = &tpci200->info->interface_regs->status; |
409 | mask = tpci200_status_error[dev->slot]; |
410 | return (ioread16(addr) & mask) ? 1 : 0; |
411 | } |
412 | |
413 | static int tpci200_get_timeout(struct ipack_device *dev) |
414 | { |
415 | struct tpci200_board *tpci200 = check_slot(dev); |
416 | __le16 __iomem *addr; |
417 | u16 mask; |
418 | |
419 | if (!tpci200) |
420 | return -ENODEV; |
421 | |
422 | addr = &tpci200->info->interface_regs->status; |
423 | mask = tpci200_status_timeout[dev->slot]; |
424 | |
425 | return (ioread16(addr) & mask) ? 1 : 0; |
426 | } |
427 | |
428 | static int tpci200_reset_timeout(struct ipack_device *dev) |
429 | { |
430 | struct tpci200_board *tpci200 = check_slot(dev); |
431 | __le16 __iomem *addr; |
432 | u16 mask; |
433 | |
434 | if (!tpci200) |
435 | return -ENODEV; |
436 | |
437 | addr = &tpci200->info->interface_regs->status; |
438 | mask = tpci200_status_timeout[dev->slot]; |
439 | |
440 | iowrite16(mask, addr); |
441 | return 0; |
442 | } |
443 | |
444 | static void tpci200_uninstall(struct tpci200_board *tpci200) |
445 | { |
446 | tpci200_unregister(tpci200); |
447 | kfree(objp: tpci200->slots); |
448 | } |
449 | |
450 | static const struct ipack_bus_ops tpci200_bus_ops = { |
451 | .request_irq = tpci200_request_irq, |
452 | .free_irq = tpci200_free_irq, |
453 | .get_clockrate = tpci200_get_clockrate, |
454 | .set_clockrate = tpci200_set_clockrate, |
455 | .get_error = tpci200_get_error, |
456 | .get_timeout = tpci200_get_timeout, |
457 | .reset_timeout = tpci200_reset_timeout, |
458 | }; |
459 | |
460 | static int tpci200_install(struct tpci200_board *tpci200) |
461 | { |
462 | int res; |
463 | |
464 | tpci200->slots = kcalloc(TPCI200_NB_SLOT, size: sizeof(struct tpci200_slot), |
465 | GFP_KERNEL); |
466 | if (tpci200->slots == NULL) |
467 | return -ENOMEM; |
468 | |
469 | res = tpci200_register(tpci200); |
470 | if (res) { |
471 | kfree(objp: tpci200->slots); |
472 | tpci200->slots = NULL; |
473 | return res; |
474 | } |
475 | |
476 | mutex_init(&tpci200->mutex); |
477 | return 0; |
478 | } |
479 | |
480 | static void tpci200_release_device(struct ipack_device *dev) |
481 | { |
482 | kfree(objp: dev); |
483 | } |
484 | |
485 | static int tpci200_create_device(struct tpci200_board *tpci200, int i) |
486 | { |
487 | int ret; |
488 | enum ipack_space space; |
489 | struct ipack_device *dev = |
490 | kzalloc(size: sizeof(struct ipack_device), GFP_KERNEL); |
491 | if (!dev) |
492 | return -ENOMEM; |
493 | dev->slot = i; |
494 | dev->bus = tpci200->info->ipack_bus; |
495 | dev->release = tpci200_release_device; |
496 | |
497 | for (space = 0; space < IPACK_SPACE_COUNT; space++) { |
498 | dev->region[space].start = |
499 | tpci200->mod_mem[space] |
500 | + tpci200_space_interval[space] * i; |
501 | dev->region[space].size = tpci200_space_size[space]; |
502 | } |
503 | |
504 | ret = ipack_device_init(dev); |
505 | if (ret < 0) { |
506 | ipack_put_device(dev); |
507 | return ret; |
508 | } |
509 | |
510 | ret = ipack_device_add(dev); |
511 | if (ret < 0) |
512 | ipack_put_device(dev); |
513 | |
514 | return ret; |
515 | } |
516 | |
517 | static int tpci200_pci_probe(struct pci_dev *pdev, |
518 | const struct pci_device_id *id) |
519 | { |
520 | int ret, i; |
521 | struct tpci200_board *tpci200; |
522 | u32 reg32; |
523 | |
524 | tpci200 = kzalloc(size: sizeof(struct tpci200_board), GFP_KERNEL); |
525 | if (!tpci200) |
526 | return -ENOMEM; |
527 | |
528 | tpci200->info = kzalloc(size: sizeof(struct tpci200_infos), GFP_KERNEL); |
529 | if (!tpci200->info) { |
530 | ret = -ENOMEM; |
531 | goto err_tpci200; |
532 | } |
533 | |
534 | pci_dev_get(dev: pdev); |
535 | |
536 | /* Obtain a mapping of the carrier's PCI configuration registers */ |
537 | ret = pci_request_region(pdev, TPCI200_CFG_MEM_BAR, |
538 | KBUILD_MODNAME " Configuration Memory" ); |
539 | if (ret) { |
540 | dev_err(&pdev->dev, "Failed to allocate PCI Configuration Memory" ); |
541 | ret = -EBUSY; |
542 | goto err_tpci200_info; |
543 | } |
544 | tpci200->info->cfg_regs = ioremap( |
545 | pci_resource_start(pdev, TPCI200_CFG_MEM_BAR), |
546 | pci_resource_len(pdev, TPCI200_CFG_MEM_BAR)); |
547 | if (!tpci200->info->cfg_regs) { |
548 | dev_err(&pdev->dev, "Failed to map PCI Configuration Memory" ); |
549 | ret = -EFAULT; |
550 | goto err_request_region; |
551 | } |
552 | |
553 | /* Disable byte swapping for 16 bit IP module access. This will ensure |
554 | * that the Industrypack big endian byte order is preserved by the |
555 | * carrier. */ |
556 | reg32 = ioread32(tpci200->info->cfg_regs + LAS1_DESC); |
557 | reg32 |= 1 << LAS_BIT_BIGENDIAN; |
558 | iowrite32(reg32, tpci200->info->cfg_regs + LAS1_DESC); |
559 | |
560 | reg32 = ioread32(tpci200->info->cfg_regs + LAS2_DESC); |
561 | reg32 |= 1 << LAS_BIT_BIGENDIAN; |
562 | iowrite32(reg32, tpci200->info->cfg_regs + LAS2_DESC); |
563 | |
564 | /* Save struct pci_dev pointer */ |
565 | tpci200->info->pdev = pdev; |
566 | tpci200->info->id_table = (struct pci_device_id *)id; |
567 | |
568 | /* register the device and initialize it */ |
569 | ret = tpci200_install(tpci200); |
570 | if (ret) { |
571 | dev_err(&pdev->dev, "error during tpci200 install\n" ); |
572 | ret = -ENODEV; |
573 | goto err_cfg_regs; |
574 | } |
575 | |
576 | /* Register the carrier in the industry pack bus driver */ |
577 | tpci200->info->ipack_bus = ipack_bus_register(parent: &pdev->dev, |
578 | TPCI200_NB_SLOT, |
579 | ops: &tpci200_bus_ops, |
580 | THIS_MODULE); |
581 | if (!tpci200->info->ipack_bus) { |
582 | dev_err(&pdev->dev, |
583 | "error registering the carrier on ipack driver\n" ); |
584 | ret = -EFAULT; |
585 | goto err_tpci200_install; |
586 | } |
587 | |
588 | /* save the bus number given by ipack to logging purpose */ |
589 | tpci200->number = tpci200->info->ipack_bus->bus_nr; |
590 | dev_set_drvdata(dev: &pdev->dev, data: tpci200); |
591 | |
592 | for (i = 0; i < TPCI200_NB_SLOT; i++) |
593 | tpci200_create_device(tpci200, i); |
594 | return 0; |
595 | |
596 | err_tpci200_install: |
597 | tpci200_uninstall(tpci200); |
598 | err_cfg_regs: |
599 | pci_iounmap(dev: tpci200->info->pdev, tpci200->info->cfg_regs); |
600 | err_request_region: |
601 | pci_release_region(pdev, TPCI200_CFG_MEM_BAR); |
602 | err_tpci200_info: |
603 | kfree(objp: tpci200->info); |
604 | pci_dev_put(dev: pdev); |
605 | err_tpci200: |
606 | kfree(objp: tpci200); |
607 | return ret; |
608 | } |
609 | |
610 | static void __tpci200_pci_remove(struct tpci200_board *tpci200) |
611 | { |
612 | ipack_bus_unregister(bus: tpci200->info->ipack_bus); |
613 | tpci200_uninstall(tpci200); |
614 | |
615 | pci_iounmap(dev: tpci200->info->pdev, tpci200->info->cfg_regs); |
616 | |
617 | pci_release_region(tpci200->info->pdev, TPCI200_CFG_MEM_BAR); |
618 | |
619 | pci_dev_put(dev: tpci200->info->pdev); |
620 | |
621 | kfree(objp: tpci200->info); |
622 | kfree(objp: tpci200); |
623 | } |
624 | |
625 | static void tpci200_pci_remove(struct pci_dev *dev) |
626 | { |
627 | struct tpci200_board *tpci200 = pci_get_drvdata(pdev: dev); |
628 | |
629 | __tpci200_pci_remove(tpci200); |
630 | } |
631 | |
632 | static const struct pci_device_id tpci200_idtable[] = { |
633 | { TPCI200_VENDOR_ID, TPCI200_DEVICE_ID, TPCI200_SUBVENDOR_ID, |
634 | TPCI200_SUBDEVICE_ID }, |
635 | { 0, }, |
636 | }; |
637 | |
638 | MODULE_DEVICE_TABLE(pci, tpci200_idtable); |
639 | |
640 | static struct pci_driver tpci200_pci_drv = { |
641 | .name = "tpci200" , |
642 | .id_table = tpci200_idtable, |
643 | .probe = tpci200_pci_probe, |
644 | .remove = tpci200_pci_remove, |
645 | }; |
646 | |
647 | module_pci_driver(tpci200_pci_drv); |
648 | |
649 | MODULE_DESCRIPTION("TEWS TPCI-200 device driver" ); |
650 | MODULE_LICENSE("GPL" ); |
651 | |