@@ -43,6 +43,11 @@ struct pcim_iomap_devres {
43
43
void __iomem * table [PCI_STD_NUM_BARS ];
44
44
};
45
45
46
+ /* Used to restore the old INTx state on driver detach. */
47
+ struct pcim_intx_devres {
48
+ int orig_intx ;
49
+ };
50
+
46
51
enum pcim_addr_devres_type {
47
52
/* Default initializer. */
48
53
PCIM_ADDR_DEVRES_TYPE_INVALID ,
@@ -406,27 +411,78 @@ static inline bool mask_contains_bar(int mask, int bar)
406
411
return mask & BIT (bar );
407
412
}
408
413
409
- static void pcim_release (struct device * gendev , void * res )
414
+ /*
415
+ * This is a copy of pci_intx() used to bypass the problem of recursive
416
+ * function calls due to the hybrid nature of pci_intx().
417
+ */
418
+ static void __pcim_intx (struct pci_dev * pdev , int enable )
410
419
{
411
- struct pci_dev * dev = to_pci_dev (gendev );
412
- struct pci_devres * this = res ;
420
+ u16 pci_command , new ;
413
421
414
- if (this -> restore_intx )
415
- pci_intx (dev , this -> orig_intx );
422
+ pci_read_config_word (pdev , PCI_COMMAND , & pci_command );
416
423
417
- if (pci_is_enabled (dev ) && !dev -> pinned )
418
- pci_disable_device (dev );
424
+ if (enable )
425
+ new = pci_command & ~PCI_COMMAND_INTX_DISABLE ;
426
+ else
427
+ new = pci_command | PCI_COMMAND_INTX_DISABLE ;
428
+
429
+ if (new != pci_command )
430
+ pci_write_config_word (pdev , PCI_COMMAND , new );
419
431
}
420
432
421
- /*
422
- * TODO: After the last four callers in pci.c are ported, find_pci_dr()
423
- * needs to be made static again.
433
+ static void pcim_intx_restore (struct device * dev , void * data )
434
+ {
435
+ struct pci_dev * pdev = to_pci_dev (dev );
436
+ struct pcim_intx_devres * res = data ;
437
+
438
+ __pcim_intx (pdev , res -> orig_intx );
439
+ }
440
+
441
+ static struct pcim_intx_devres * get_or_create_intx_devres (struct device * dev )
442
+ {
443
+ struct pcim_intx_devres * res ;
444
+
445
+ res = devres_find (dev , pcim_intx_restore , NULL , NULL );
446
+ if (res )
447
+ return res ;
448
+
449
+ res = devres_alloc (pcim_intx_restore , sizeof (* res ), GFP_KERNEL );
450
+ if (res )
451
+ devres_add (dev , res );
452
+
453
+ return res ;
454
+ }
455
+
456
+ /**
457
+ * pcim_intx - managed pci_intx()
458
+ * @pdev: the PCI device to operate on
459
+ * @enable: boolean: whether to enable or disable PCI INTx
460
+ *
461
+ * Returns: 0 on success, -ENOMEM on error.
462
+ *
463
+ * Enable/disable PCI INTx for device @pdev.
464
+ * Restore the original state on driver detach.
424
465
*/
425
- struct pci_devres * find_pci_dr (struct pci_dev * pdev )
466
+ int pcim_intx (struct pci_dev * pdev , int enable )
426
467
{
427
- if (pci_is_managed (pdev ))
428
- return devres_find (& pdev -> dev , pcim_release , NULL , NULL );
429
- return NULL ;
468
+ struct pcim_intx_devres * res ;
469
+
470
+ res = get_or_create_intx_devres (& pdev -> dev );
471
+ if (!res )
472
+ return - ENOMEM ;
473
+
474
+ res -> orig_intx = !enable ;
475
+ __pcim_intx (pdev , enable );
476
+
477
+ return 0 ;
478
+ }
479
+
480
+ static void pcim_release (struct device * gendev , void * res )
481
+ {
482
+ struct pci_dev * dev = to_pci_dev (gendev );
483
+
484
+ if (pci_is_enabled (dev ) && !dev -> pinned )
485
+ pci_disable_device (dev );
430
486
}
431
487
432
488
static struct pci_devres * get_pci_dr (struct pci_dev * pdev )
0 commit comments