Hi, On Tue, Mar 17, 2020 at 2:36 PM Stephen Boyd <swboyd@xxxxxxxxxxxx> wrote: > > > Patch is marked "speculative" because I have no way to reproduce this > > problem, so I'm just hoping this fixes it. Weakly ordered memory > > makes my brain hurt. > > It could be that. It could also be the poor design of geni_se_init() and > how it enables many interrupts that this driver doesn't look to handle? > Why do we allow the wrapper to enable all those bits in > M_COMMON_GENI_M_IRQ_EN and S_COMMON_GENI_S_IRQ_EN if nobody is going to > handle them? It is possible it's related to an interrupt that we don't handle. However: * IMO having the locking in place is safer anyway. At some point I read that advice that trying to reason about weakly ordered memory was simply too hard for the average person (even the average kernel developer). In 99% of the cases you could just use a lock so it's super clear and the performance difference is near zero. * Most of the cases I saw of the "nobody cared" for geni-spi was on a mostly idle system (presumably still doing periodic SPI transactions to the EC, though). It seems weird that one of these other interrupts would suddenly fire. It seems more likely that we just happened to win a race of some sort. If nothing else it will suddenly become very obvious after my patch lands because I'll print out the status. That all being said if someone wants to submit a patch to clean up which interrupts are enabled I'd support it. > > @@ -151,16 +151,19 @@ static void spi_geni_set_cs(struct spi_device *slv, bool set_flag) > > struct geni_se *se = &mas->se; > > unsigned long time_left; > > > > - reinit_completion(&mas->xfer_done); > > pm_runtime_get_sync(mas->dev); > > if (!(slv->mode & SPI_CS_HIGH)) > > set_flag = !set_flag; > > > > + spin_lock_irq(&mas->lock); > > Why is this spin_lock_irq() vs. spin_lock_irqsave()? This isn't possible > to be called from somewhere that hasn't changed irq flags? See below. > > + reinit_completion(&mas->xfer_done); > > + > > mas->cur_mcmd = CMD_CS; > > if (set_flag) > > geni_se_setup_m_cmd(se, SPI_CS_ASSERT, 0); > > else > > geni_se_setup_m_cmd(se, SPI_CS_DEASSERT, 0); > > + spin_unlock_irq(&mas->lock); > > This will force on interrupts if they were masked. I'll change it if you want, but in this function there is already a call to "wait_for_completion_timeout". That's not gonna be too happy if this function is ever called with interrupts already masked. Also in this function is pm_runtime_get_sync() which in many cases will sleep (I think we'll end up in geni_se_clks_on() which calls clk_bulk_prepare_enable()). In cases where you know for sure that interrupts aren't masked, spin_lock_irq() and spin_unlock_irq() are fine and that's what they're for, no? > > time_left = wait_for_completion_timeout(&mas->xfer_done, HZ); > > if (!time_left) > > @@ -307,6 +310,8 @@ static void setup_fifo_xfer(struct spi_transfer *xfer, > > u32 spi_tx_cfg, len; > > struct geni_se *se = &mas->se; > > > > + spin_lock_irq(&mas->lock); ...and just to answer the same question for here: setup_fifo_xfer() is called from spi_geni_transfer_one() which is our "transfer_one" function. We don't happen to block anywhere in these functions, but I'm nearly certain you are allowed to block in them. We actually return a positive number to indicate to the SPI core that we're not doing the blocking ourselves but since the SPI core can't know we were going to do that it has to assume we might block. > > @@ -478,13 +485,29 @@ static irqreturn_t geni_spi_isr(int irq, void *data) > > struct geni_se *se = &mas->se; > > u32 m_irq; > > unsigned long flags; > > - > > - if (mas->cur_mcmd == CMD_NONE) > > - return IRQ_NONE; > > + irqreturn_t ret = IRQ_HANDLED; > > > > spin_lock_irqsave(&mas->lock, flags); Ironically the above could probably just be "spin_lock" since this is our interrupt handler. ;-) I'll just leave it alone though since what's there now doesn't hurt. > > m_irq = readl(se->base + SE_GENI_M_IRQ_STATUS); > > Does this read need to be inside the lock? Probably not. Discussion below. > > + /* Check for spurious interrupt */ > > + if (!m_irq) { > > + ret = IRQ_NONE; > > + goto exit; > > I ask because it could be simplified by reading the status and then > immediately returning IRQ_NONE if no bits are set without having to do > the lock/unlock dance. And does writing 0 to the irq clear register do > anything? Sure. I'll move it if you want. It felt nicer to just keep the whole thing under lock so I didn't have to think about whether it mattered. ...and anyone else looking at it didn't need to think about if it mattered, too. It it is very easy to say that it doesn't _hurt_ to have it under lock other than having one extra memory read under lock. ...and presumably the case where the optimization matters is incredibly rare (a spurious interrupt) and we just spent a whole lot of cycles calling the interrupt handler to begin with for this spurious interrupt. I would have a hard time believing that a write of 0 to a "write 1 to clear" register would have any impact. It would be a pretty bad hardware design... So I guess in summary, I'm not planning to spin for any of these things unless you really insist or you say I'm wrong about something above or someone else says my opinions are the wrong opinions. -Doug