Skip to content

Commit 25216af

Browse files
Philipp Stannerbjorn-helgaas
Philipp Stanner
authored andcommitted
PCI: Add managed pcim_intx()
pci_intx() is a "hybrid" function, i.e., it is managed if pcim_enable_device() has been called, but unmanaged otherwise. Add pcim_intx(), which is always managed, and implement pci_intx() using it. Remove the now-unused struct pci_devres.orig_intx and .restore_intx and find_pci_dr(). Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Philipp Stanner <[email protected]> [kwilczynski: squashed in https://lore.kernel.org/r/[email protected] to fix problem reported and tested by Ashish Kalra <[email protected]>: https://lore.kernel.org/r/[email protected] https://lore.kernel.org/r/[email protected]/] Signed-off-by: Krzysztof Wilczyński <[email protected]> [bhelgaas: commit log] Signed-off-by: Bjorn Helgaas <[email protected]>
1 parent 2c3e842 commit 25216af

File tree

3 files changed

+85
-31
lines changed

3 files changed

+85
-31
lines changed

Diff for: drivers/pci/devres.c

+70-14
Original file line numberDiff line numberDiff line change
@@ -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+
4651
enum 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

432488
static struct pci_devres *get_pci_dr(struct pci_dev *pdev)

Diff for: drivers/pci/pci.c

+8-11
Original file line numberDiff line numberDiff line change
@@ -4442,30 +4442,27 @@ void pci_disable_parity(struct pci_dev *dev)
44424442
* NOTE:
44434443
* This is a "hybrid" function: It's normally unmanaged, but becomes managed
44444444
* when pcim_enable_device() has been called in advance. This hybrid feature is
4445-
* DEPRECATED!
4445+
* DEPRECATED! If you want managed cleanup, use pcim_intx() instead.
44464446
*/
44474447
void pci_intx(struct pci_dev *pdev, int enable)
44484448
{
44494449
u16 pci_command, new;
44504450

4451+
/* Preserve the "hybrid" behavior for backwards compatibility */
4452+
if (pci_is_managed(pdev)) {
4453+
WARN_ON_ONCE(pcim_intx(pdev, enable) != 0);
4454+
return;
4455+
}
4456+
44514457
pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
44524458

44534459
if (enable)
44544460
new = pci_command & ~PCI_COMMAND_INTX_DISABLE;
44554461
else
44564462
new = pci_command | PCI_COMMAND_INTX_DISABLE;
44574463

4458-
if (new != pci_command) {
4459-
struct pci_devres *dr;
4460-
4464+
if (new != pci_command)
44614465
pci_write_config_word(pdev, PCI_COMMAND, new);
4462-
4463-
dr = find_pci_dr(pdev);
4464-
if (dr && !dr->restore_intx) {
4465-
dr->restore_intx = 1;
4466-
dr->orig_intx = !enable;
4467-
}
4468-
}
44694466
}
44704467
EXPORT_SYMBOL_GPL(pci_intx);
44714468

Diff for: drivers/pci/pci.h

+7-6
Original file line numberDiff line numberDiff line change
@@ -816,16 +816,17 @@ static inline pci_power_t mid_pci_get_power_state(struct pci_dev *pdev)
816816
* there's no need to track it separately. pci_devres is initialized
817817
* when a device is enabled using managed PCI device enable interface.
818818
*
819-
* TODO: Struct pci_devres and find_pci_dr() only need to be here because
820-
* they're used in pci.c. Port or move these functions to devres.c and
821-
* then remove them from here.
819+
* TODO: Struct pci_devres only needs to be here because they're used in pci.c.
820+
* Port or move these functions to devres.c and then remove them from here.
822821
*/
823822
struct pci_devres {
824-
unsigned int orig_intx:1;
825-
unsigned int restore_intx:1;
823+
/*
824+
* TODO:
825+
* This struct is now surplus. Remove it by refactoring pci/devres.c
826+
*/
826827
};
827828

828-
struct pci_devres *find_pci_dr(struct pci_dev *pdev);
829+
int pcim_intx(struct pci_dev *dev, int enable);
829830

830831
int pcim_request_region(struct pci_dev *pdev, int bar, const char *name);
831832
int pcim_request_region_exclusive(struct pci_dev *pdev, int bar,

0 commit comments

Comments
 (0)