On Fri, 2018-08-17 at 10:09 +0200, Marta Rybczynska wrote: > > ----- On 17 Aug, 2018, at 06:49, Benjamin Herrenschmidt benh@xxxxxxxxxxxxxxxxxxx wrote: > > > This protects enable/disable operations using the state mutex to > > avoid races with, for example, concurrent enables on a bridge. > > > > The bus hierarchy is walked first before taking the lock to > > avoid lock nesting (though it would be ok if we ensured that > > we always nest them bottom-up, it is better to just avoid the > > issue alltogether, especially as we might find cases where > > we want to take it top-down later). > > > > Signed-off-by: Benjamin Herrenschmidt <benh@xxxxxxxxxxxxxxxxxxx> > > > > > > static void pci_enable_bridge(struct pci_dev *dev) > > { > > struct pci_dev *bridge; > > - int retval; > > + int retval, enabled; > > > > bridge = pci_upstream_bridge(dev); > > if (bridge) > > pci_enable_bridge(bridge); > > > > - if (pci_is_enabled(dev)) { > > - if (!dev->is_busmaster) > > - pci_set_master(dev); > > + /* Already enabled ? */ > > + pci_dev_state_lock(dev); > > + enabled = pci_is_enabled(dev); > > + if (enabled && !dev->is_busmaster) > > + pci_set_master(dev); > > + pci_dev_state_unlock(dev); > > + if (enabled) > > return; > > - } > > > > This looks complicated too me especially with the double locking. What do you > think about a function doing that check that used an unlocked version of > pcie_set_master? > > Like: > > dev_state_lock(dev); > enabled = pci_is_enabled(dev); > if (enabled && !dev->is_busmaster) > pci_set_master_unlocked(); > pci_dev_state_unlock(dev); > > BTW If I remember correctly the code today can set bus mastering multiple > times without checking if already done. I don't mind but I tend to dislike all those _unlocked() suffixes, I suppose my generation is typing adverse enough that we call these __something instead :) As for setting multiple times, yes pci_set_master() doesn't check but look at the "-" hunks of my patch, I'm not changing the existing test here. Not that it matters much, it's an optimization. In fact my original version just completely removed the whole lot and just unconditionally did pci_enable_device() + pci_set_master(), just ignoring the existing state :-) But I decided to keep the patch functionally equivalent so I added it back. Cheers, Ben.