All of lore.kernel.org
 help / color / mirror / Atom feed
From: Tejun Heo <tj@kernel.org>
To: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: linux-ide@vger.kernel.org, linuxppc-dev@lists.ozlabs.org,
	Jeff Garzik <jeff@garzik.org>, Holger Macht <hmacht@suse.de>
Subject: Re: [PATCH 5/5] libata/drivers: Add pata_macio, driver Apple PowerMac/PowerBook IDE controller
Date: Tue, 01 Dec 2009 17:00:34 +0900	[thread overview]
Message-ID: <4B14CD22.4020806@kernel.org> (raw)
In-Reply-To: <20091201070834.6A840B7B63@ozlabs.org>

(cc'ing Holger Macht, please read the comment below pata_macio_mb_event())
Hello,

On 12/01/2009 04:08 PM, Benjamin Herrenschmidt wrote:
> This is a libata driver for the "macio" IDE controller used on most Apple
> PowerMac and PowerBooks. It's a libata equivalent of drivers/ide/ppc/pmac.c

Don't know much about the controller or the platform so my comments
will be pretty confined.

> +/*
> + * Wait 1s for disk to answer on IDE bus after a hard reset
> + * of the device (via GPIO/FCR).
> + *
> + * Some devices seem to "pollute" the bus even after dropping
> + * the BSY bit (typically some combo drives slave on the UDMA
> + * bus) after a hard reset. Since we hard reset all drives on
> + * KeyLargo ATA66, we have to keep that delay around. I may end
> + * up not hard resetting anymore on these and keep the delay only
> + * for older interfaces instead (we have to reset when coming
> + * from MacOS...) --BenH.
> + */
> +#define IDE_WAKEUP_DELAY	(1*HZ)

nitpick: In libata, it's common to use msecs for timing values so that
might be a better option.

> +static const struct pata_macio_timing *pata_macio_find_timing(
> +					    struct pata_macio_priv *priv,
> +					    int mode)
> +{
> +	int i = 0;
> +
> +	while (priv->timings[i].mode > 0) {
> +		if (priv->timings[i].mode == mode)
> +			return &priv->timings[i];
> +		i++;
> +	}
> +	return NULL;

Wouldn't for (i = 0; ...) look better?

> +static void pata_macio_bmdma_start(struct ata_queued_cmd *qc)
> +{
> +	struct ata_port *ap = qc->ap;
> +	struct pata_macio_priv *priv = ap->private_data;
> +	struct dbdma_regs __iomem *dma_regs = ap->ioaddr.bmdma_addr;
> +
> +	dev_dbgdma(priv->dev, "%s: qc %p\n", __func__, qc);
> +
> +	writel((RUN << 16) | RUN, &dma_regs->control);
> +	/* Make sure it gets to the controller right now */
> +	(void)readl(&dma_regs->control);

Is flushing necessary here?  There's no ordering issue here, right?

> +static void pata_macio_bmdma_stop(struct ata_queued_cmd *qc)
> +{
> +	struct ata_port *ap = qc->ap;
> +	struct pata_macio_priv *priv = ap->private_data;
> +	struct dbdma_regs __iomem *dma_regs = ap->ioaddr.bmdma_addr;
> +
> +	dev_dbgdma(priv->dev, "%s: qc %p\n", __func__, qc);
> +
> +	/* Stop the DMA engine and wait for it to full halt */
> +	writel (((RUN|WAKE|DEAD) << 16), &dma_regs->control);
> +	while (readl(&dma_regs->status) & RUN)
> +		udelay(1);

Heh... this is a scary looking loop.  It would be great if the above
loop can be capped somehow.

> +static u8 pata_macio_bmdma_status(struct ata_port *ap)
> +{
> +	struct pata_macio_priv *priv = ap->private_data;
> +	struct dbdma_regs __iomem *dma_regs = ap->ioaddr.bmdma_addr;
> +	u32 dstat, rstat = ATA_DMA_INTR;
> +	unsigned long timeout = 0;
> +
> +	dstat = readl(&dma_regs->status);
> +
> +	dev_dbgdma(priv->dev, "%s: dstat=%x\n", __func__, dstat);
> +
> +	/* We have to things to deal with here:
                   ^^
                   two

> +/* port_start is when we allocate the DMA command list */
> +static int pata_macio_port_start(struct ata_port *ap)
> +{
> +	struct pata_macio_priv *priv = ap->private_data;
> +	struct dbdma_regs __iomem *dma_regs = ap->ioaddr.bmdma_addr;
> +
> +	if (dma_regs == NULL)
> +		return 0;
> +
> +	/* Make sure DMA controller is stopped */
> +	writel((RUN|PAUSE|FLUSH|WAKE|DEAD) << 16, &dma_regs->control);
> +	while (readl(&dma_regs->status) & RUN)
> +		udelay(1);

Hmmm.... this probably belongs to ->freeze() which is responsible for
stopping any in-flight operations and masking IRQ and libata will call
it during initialization before requesting IRQ, so you won't need to
call it explicitly here.

> +#ifdef CONFIG_PMAC_MEDIABAY
> +static void pata_macio_mb_event(struct macio_dev* mdev, int mb_state)
> +{
> +	struct ata_host *host = macio_get_drvdata(mdev);
> +	struct ata_port *ap;
> +	struct ata_eh_info *ehi;
> +	struct ata_device *dev;
> +	unsigned long flags;
> +
> +	if (!host)
> +		return;
> +	ap = host->ports[0];
> +	spin_lock_irqsave(ap->lock, flags);
> +	ehi = &ap->link.eh_info;
> +	if (mb_state == MB_CD) {
> +		ata_ehi_push_desc(ehi, "mediabay plug");
> +		ata_ehi_hotplugged(ehi);
> +		ata_port_freeze(ap);
> +	} else {
> +		ata_ehi_push_desc(ehi, "mediabay unplug");
> +		ata_for_each_dev(dev, &ap->link, ALL)
> +			dev->flags |= ATA_DFLAG_DETACH;
> +		ata_port_schedule_eh(ap);

I think you'll need an ata_port_freeze() or abort() here because at
this point the drive is already gone and all in-flight commands need
to be failed right away.  Holger, do you remember why
ata_acpi_detach_device() is using ata_port_schedule_eh() instead?  Was
it because ata_port_freeze() might end up poking registers after
hotunplug happened?  ISTR reports where accessing any register there
causing the whole system to lock up but then why can't it use
ata_port_abort() instead?

Thanks.

-- 
tejun

WARNING: multiple messages have this Message-ID (diff)
From: Tejun Heo <tj@kernel.org>
To: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: linux-ide@vger.kernel.org, Holger Macht <hmacht@suse.de>,
	linuxppc-dev@lists.ozlabs.org, Jeff Garzik <jeff@garzik.org>
Subject: Re: [PATCH 5/5] libata/drivers: Add pata_macio, driver Apple PowerMac/PowerBook IDE controller
Date: Tue, 01 Dec 2009 17:00:34 +0900	[thread overview]
Message-ID: <4B14CD22.4020806@kernel.org> (raw)
In-Reply-To: <20091201070834.6A840B7B63@ozlabs.org>

(cc'ing Holger Macht, please read the comment below pata_macio_mb_event())
Hello,

On 12/01/2009 04:08 PM, Benjamin Herrenschmidt wrote:
> This is a libata driver for the "macio" IDE controller used on most Apple
> PowerMac and PowerBooks. It's a libata equivalent of drivers/ide/ppc/pmac.c

Don't know much about the controller or the platform so my comments
will be pretty confined.

> +/*
> + * Wait 1s for disk to answer on IDE bus after a hard reset
> + * of the device (via GPIO/FCR).
> + *
> + * Some devices seem to "pollute" the bus even after dropping
> + * the BSY bit (typically some combo drives slave on the UDMA
> + * bus) after a hard reset. Since we hard reset all drives on
> + * KeyLargo ATA66, we have to keep that delay around. I may end
> + * up not hard resetting anymore on these and keep the delay only
> + * for older interfaces instead (we have to reset when coming
> + * from MacOS...) --BenH.
> + */
> +#define IDE_WAKEUP_DELAY	(1*HZ)

nitpick: In libata, it's common to use msecs for timing values so that
might be a better option.

> +static const struct pata_macio_timing *pata_macio_find_timing(
> +					    struct pata_macio_priv *priv,
> +					    int mode)
> +{
> +	int i = 0;
> +
> +	while (priv->timings[i].mode > 0) {
> +		if (priv->timings[i].mode == mode)
> +			return &priv->timings[i];
> +		i++;
> +	}
> +	return NULL;

Wouldn't for (i = 0; ...) look better?

> +static void pata_macio_bmdma_start(struct ata_queued_cmd *qc)
> +{
> +	struct ata_port *ap = qc->ap;
> +	struct pata_macio_priv *priv = ap->private_data;
> +	struct dbdma_regs __iomem *dma_regs = ap->ioaddr.bmdma_addr;
> +
> +	dev_dbgdma(priv->dev, "%s: qc %p\n", __func__, qc);
> +
> +	writel((RUN << 16) | RUN, &dma_regs->control);
> +	/* Make sure it gets to the controller right now */
> +	(void)readl(&dma_regs->control);

Is flushing necessary here?  There's no ordering issue here, right?

> +static void pata_macio_bmdma_stop(struct ata_queued_cmd *qc)
> +{
> +	struct ata_port *ap = qc->ap;
> +	struct pata_macio_priv *priv = ap->private_data;
> +	struct dbdma_regs __iomem *dma_regs = ap->ioaddr.bmdma_addr;
> +
> +	dev_dbgdma(priv->dev, "%s: qc %p\n", __func__, qc);
> +
> +	/* Stop the DMA engine and wait for it to full halt */
> +	writel (((RUN|WAKE|DEAD) << 16), &dma_regs->control);
> +	while (readl(&dma_regs->status) & RUN)
> +		udelay(1);

Heh... this is a scary looking loop.  It would be great if the above
loop can be capped somehow.

> +static u8 pata_macio_bmdma_status(struct ata_port *ap)
> +{
> +	struct pata_macio_priv *priv = ap->private_data;
> +	struct dbdma_regs __iomem *dma_regs = ap->ioaddr.bmdma_addr;
> +	u32 dstat, rstat = ATA_DMA_INTR;
> +	unsigned long timeout = 0;
> +
> +	dstat = readl(&dma_regs->status);
> +
> +	dev_dbgdma(priv->dev, "%s: dstat=%x\n", __func__, dstat);
> +
> +	/* We have to things to deal with here:
                   ^^
                   two

> +/* port_start is when we allocate the DMA command list */
> +static int pata_macio_port_start(struct ata_port *ap)
> +{
> +	struct pata_macio_priv *priv = ap->private_data;
> +	struct dbdma_regs __iomem *dma_regs = ap->ioaddr.bmdma_addr;
> +
> +	if (dma_regs == NULL)
> +		return 0;
> +
> +	/* Make sure DMA controller is stopped */
> +	writel((RUN|PAUSE|FLUSH|WAKE|DEAD) << 16, &dma_regs->control);
> +	while (readl(&dma_regs->status) & RUN)
> +		udelay(1);

Hmmm.... this probably belongs to ->freeze() which is responsible for
stopping any in-flight operations and masking IRQ and libata will call
it during initialization before requesting IRQ, so you won't need to
call it explicitly here.

> +#ifdef CONFIG_PMAC_MEDIABAY
> +static void pata_macio_mb_event(struct macio_dev* mdev, int mb_state)
> +{
> +	struct ata_host *host = macio_get_drvdata(mdev);
> +	struct ata_port *ap;
> +	struct ata_eh_info *ehi;
> +	struct ata_device *dev;
> +	unsigned long flags;
> +
> +	if (!host)
> +		return;
> +	ap = host->ports[0];
> +	spin_lock_irqsave(ap->lock, flags);
> +	ehi = &ap->link.eh_info;
> +	if (mb_state == MB_CD) {
> +		ata_ehi_push_desc(ehi, "mediabay plug");
> +		ata_ehi_hotplugged(ehi);
> +		ata_port_freeze(ap);
> +	} else {
> +		ata_ehi_push_desc(ehi, "mediabay unplug");
> +		ata_for_each_dev(dev, &ap->link, ALL)
> +			dev->flags |= ATA_DFLAG_DETACH;
> +		ata_port_schedule_eh(ap);

I think you'll need an ata_port_freeze() or abort() here because at
this point the drive is already gone and all in-flight commands need
to be failed right away.  Holger, do you remember why
ata_acpi_detach_device() is using ata_port_schedule_eh() instead?  Was
it because ata_port_freeze() might end up poking registers after
hotunplug happened?  ISTR reports where accessing any register there
causing the whole system to lock up but then why can't it use
ata_port_abort() instead?

Thanks.

-- 
tejun

  reply	other threads:[~2009-12-01  8:00 UTC|newest]

Thread overview: 37+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-12-01  7:08 [PATCH 5/5] libata/drivers: Add pata_macio, driver Apple PowerMac/PowerBook IDE controller Benjamin Herrenschmidt
2009-12-01  7:08 ` Benjamin Herrenschmidt
2009-12-01  8:00 ` Tejun Heo [this message]
2009-12-01  8:00   ` Tejun Heo
2009-12-01 12:44   ` Holger Macht
2009-12-01 12:44     ` Holger Macht
2009-12-01 12:48     ` Tejun Heo
2009-12-01 12:48       ` Tejun Heo
2009-12-01 23:19   ` Benjamin Herrenschmidt
2009-12-01 23:27     ` Tejun Heo
2009-12-01 23:27       ` Tejun Heo
2009-12-01 23:35       ` Benjamin Herrenschmidt
2009-12-01 23:44         ` Tejun Heo
2009-12-01 23:44           ` Tejun Heo
2009-12-02  0:00           ` Benjamin Herrenschmidt
2009-12-02  0:00             ` Benjamin Herrenschmidt
2009-12-01 10:48 ` Mikael Pettersson
2009-12-01 10:48   ` Mikael Pettersson
2009-12-01 10:53   ` Benjamin Herrenschmidt
2009-12-01 20:43 ` Andreas Schwab
2009-12-01 20:43   ` Andreas Schwab
2009-12-01 22:34   ` Benjamin Herrenschmidt
2009-12-01 22:58   ` Benjamin Herrenschmidt
2009-12-01 22:58     ` Benjamin Herrenschmidt
  -- strict thread matches above, loose matches on Subject: below --
2009-12-02  0:36 Benjamin Herrenschmidt
2009-12-02  0:36 ` Benjamin Herrenschmidt
2009-12-02  1:07 ` Tejun Heo
2009-12-02  1:51   ` Benjamin Herrenschmidt
2009-12-02  1:55     ` Tejun Heo
2009-12-02 11:44 ` Andreas Schwab
2009-12-02 11:44   ` Andreas Schwab
2009-12-03  8:12 ` Jeff Garzik
2009-12-03  8:12   ` Jeff Garzik
2009-12-03 23:55   ` Benjamin Herrenschmidt
2009-12-03 23:55     ` Benjamin Herrenschmidt
2009-12-03 15:10 ` Mikael Pettersson
2009-12-03 15:10   ` Mikael Pettersson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4B14CD22.4020806@kernel.org \
    --to=tj@kernel.org \
    --cc=benh@kernel.crashing.org \
    --cc=hmacht@suse.de \
    --cc=jeff@garzik.org \
    --cc=linux-ide@vger.kernel.org \
    --cc=linuxppc-dev@lists.ozlabs.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.