@@ -43,6 +43,11 @@ struct pcim_iomap_devres {
4343 void __iomem * table [PCI_STD_NUM_BARS ];
4444};
4545
46+ /* Used to restore the old INTx state on driver detach. */
47+ struct pcim_intx_devres {
48+ int orig_intx ;
49+ };
50+
4651enum pcim_addr_devres_type {
4752 /* Default initializer. */
4853 PCIM_ADDR_DEVRES_TYPE_INVALID ,
@@ -406,27 +411,78 @@ static inline bool mask_contains_bar(int mask, int bar)
406411 return mask & BIT (bar );
407412}
408413
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 )
410419{
411- struct pci_dev * dev = to_pci_dev (gendev );
412- struct pci_devres * this = res ;
420+ u16 pci_command , new ;
413421
414- if (this -> restore_intx )
415- pci_intx (dev , this -> orig_intx );
422+ pci_read_config_word (pdev , PCI_COMMAND , & pci_command );
416423
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 );
419431}
420432
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.
424465 */
425- struct pci_devres * find_pci_dr (struct pci_dev * pdev )
466+ int pcim_intx (struct pci_dev * pdev , int enable )
426467{
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 );
430486}
431487
432488static struct pci_devres * get_pci_dr (struct pci_dev * pdev )
0 commit comments