Commit 22374677 authored by Jeff Garzik's avatar Jeff Garzik

[libata sata_mv] SATA probe, DMA boundary fixes

- DMA boundary was being handled incorrectly.  Copied the code from
  ata_fill_sg(), since Marvell has the same DMA boundary needs.
  (we can't use ata_fill_sg directly since we have different hardware
   descriptors)
- cleaned up the SATA phy reset code, to deal with various errata
parent 64f043d8
...@@ -321,6 +321,7 @@ static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val); ...@@ -321,6 +321,7 @@ static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in); static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in);
static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val); static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
static void mv_phy_reset(struct ata_port *ap); static void mv_phy_reset(struct ata_port *ap);
static void __mv_phy_reset(struct ata_port *ap, int can_sleep);
static void mv_host_stop(struct ata_host_set *host_set); static void mv_host_stop(struct ata_host_set *host_set);
static int mv_port_start(struct ata_port *ap); static int mv_port_start(struct ata_port *ap);
static void mv_port_stop(struct ata_port *ap); static void mv_port_stop(struct ata_port *ap);
...@@ -362,7 +363,7 @@ static struct scsi_host_template mv_sht = { ...@@ -362,7 +363,7 @@ static struct scsi_host_template mv_sht = {
.eh_strategy_handler = ata_scsi_error, .eh_strategy_handler = ata_scsi_error,
.can_queue = MV_USE_Q_DEPTH, .can_queue = MV_USE_Q_DEPTH,
.this_id = ATA_SHT_THIS_ID, .this_id = ATA_SHT_THIS_ID,
.sg_tablesize = MV_MAX_SG_CT, .sg_tablesize = MV_MAX_SG_CT / 2,
.max_sectors = ATA_MAX_SECTORS, .max_sectors = ATA_MAX_SECTORS,
.cmd_per_lun = ATA_SHT_CMD_PER_LUN, .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
.emulated = ATA_SHT_EMULATED, .emulated = ATA_SHT_EMULATED,
...@@ -893,20 +894,30 @@ static void mv_fill_sg(struct ata_queued_cmd *qc) ...@@ -893,20 +894,30 @@ static void mv_fill_sg(struct ata_queued_cmd *qc)
struct scatterlist *sg; struct scatterlist *sg;
ata_for_each_sg(sg, qc) { ata_for_each_sg(sg, qc) {
u32 sg_len;
dma_addr_t addr; dma_addr_t addr;
u32 sg_len, len, offset;
addr = sg_dma_address(sg); addr = sg_dma_address(sg);
sg_len = sg_dma_len(sg); sg_len = sg_dma_len(sg);
pp->sg_tbl[i].addr = cpu_to_le32(addr & 0xffffffff); while (sg_len) {
pp->sg_tbl[i].addr_hi = cpu_to_le32((addr >> 16) >> 16); offset = addr & MV_DMA_BOUNDARY;
assert(0 == (sg_len & ~MV_DMA_BOUNDARY)); len = sg_len;
pp->sg_tbl[i].flags_size = cpu_to_le32(sg_len); if ((offset + sg_len) > 0x10000)
if (ata_sg_is_last(sg, qc)) len = 0x10000 - offset;
pp->sg_tbl[i].flags_size |= cpu_to_le32(EPRD_FLAG_END_OF_TBL);
i++; pp->sg_tbl[i].addr = cpu_to_le32(addr & 0xffffffff);
pp->sg_tbl[i].addr_hi = cpu_to_le32((addr >> 16) >> 16);
pp->sg_tbl[i].flags_size = cpu_to_le32(len);
sg_len -= len;
addr += len;
if (!sg_len && ata_sg_is_last(sg, qc))
pp->sg_tbl[i].flags_size |= cpu_to_le32(EPRD_FLAG_END_OF_TBL);
i++;
}
} }
} }
...@@ -1693,11 +1704,19 @@ static void mv_stop_and_reset(struct ata_port *ap) ...@@ -1693,11 +1704,19 @@ static void mv_stop_and_reset(struct ata_port *ap)
mv_channel_reset(hpriv, mmio, ap->port_no); mv_channel_reset(hpriv, mmio, ap->port_no);
mv_phy_reset(ap); __mv_phy_reset(ap, 0);
}
static inline void __msleep(unsigned int msec, int can_sleep)
{
if (can_sleep)
msleep(msec);
else
mdelay(msec);
} }
/** /**
* mv_phy_reset - Perform eDMA reset followed by COMRESET * __mv_phy_reset - Perform eDMA reset followed by COMRESET
* @ap: ATA channel to manipulate * @ap: ATA channel to manipulate
* *
* Part of this is taken from __sata_phy_reset and modified to * Part of this is taken from __sata_phy_reset and modified to
...@@ -1707,13 +1726,16 @@ static void mv_stop_and_reset(struct ata_port *ap) ...@@ -1707,13 +1726,16 @@ static void mv_stop_and_reset(struct ata_port *ap)
* Inherited from caller. This is coded to safe to call at * Inherited from caller. This is coded to safe to call at
* interrupt level, i.e. it does not sleep. * interrupt level, i.e. it does not sleep.
*/ */
static void mv_phy_reset(struct ata_port *ap) static void __mv_phy_reset(struct ata_port *ap, int can_sleep)
{ {
struct mv_port_priv *pp = ap->private_data; struct mv_port_priv *pp = ap->private_data;
struct mv_host_priv *hpriv = ap->host_set->private_data;
void __iomem *port_mmio = mv_ap_base(ap); void __iomem *port_mmio = mv_ap_base(ap);
struct ata_taskfile tf; struct ata_taskfile tf;
struct ata_device *dev = &ap->device[0]; struct ata_device *dev = &ap->device[0];
unsigned long timeout; unsigned long timeout;
int retry = 5;
u32 sstatus;
VPRINTK("ENTER, port %u, mmio 0x%p\n", ap->port_no, port_mmio); VPRINTK("ENTER, port %u, mmio 0x%p\n", ap->port_no, port_mmio);
...@@ -1721,18 +1743,28 @@ static void mv_phy_reset(struct ata_port *ap) ...@@ -1721,18 +1743,28 @@ static void mv_phy_reset(struct ata_port *ap)
"SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS), "SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS),
mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL)); mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL));
/* proceed to init communications via the scr_control reg */ /* Issue COMRESET via SControl */
comreset_retry:
scr_write_flush(ap, SCR_CONTROL, 0x301); scr_write_flush(ap, SCR_CONTROL, 0x301);
mdelay(1); __msleep(1, can_sleep);
scr_write_flush(ap, SCR_CONTROL, 0x300); scr_write_flush(ap, SCR_CONTROL, 0x300);
timeout = jiffies + (HZ * 1); __msleep(20, can_sleep);
timeout = jiffies + msecs_to_jiffies(200);
do { do {
mdelay(10); sstatus = scr_read(ap, SCR_STATUS) & 0x3;
if ((scr_read(ap, SCR_STATUS) & 0xf) != 1) if ((sstatus == 3) || (sstatus == 0))
break; break;
__msleep(1, can_sleep);
} while (time_before(jiffies, timeout)); } while (time_before(jiffies, timeout));
mv_scr_write(ap, SCR_ERROR, mv_scr_read(ap, SCR_ERROR)); /* work around errata */
if (IS_60XX(hpriv) &&
(sstatus != 0x0) && (sstatus != 0x113) && (sstatus != 0x123) &&
(retry-- > 0))
goto comreset_retry;
DPRINTK("S-regs after PHY wake: SStat 0x%08x SErr 0x%08x " DPRINTK("S-regs after PHY wake: SStat 0x%08x SErr 0x%08x "
"SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS), "SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS),
...@@ -1748,6 +1780,21 @@ static void mv_phy_reset(struct ata_port *ap) ...@@ -1748,6 +1780,21 @@ static void mv_phy_reset(struct ata_port *ap)
} }
ap->cbl = ATA_CBL_SATA; ap->cbl = ATA_CBL_SATA;
/* even after SStatus reflects that device is ready,
* it seems to take a while for link to be fully
* established (and thus Status no longer 0x80/0x7F),
* so we poll a bit for that, here.
*/
retry = 20;
while (1) {
u8 drv_stat = ata_check_status(ap);
if ((drv_stat != 0x80) && (drv_stat != 0x7f))
break;
__msleep(500, can_sleep);
if (retry-- <= 0)
break;
}
tf.lbah = readb((void __iomem *) ap->ioaddr.lbah_addr); tf.lbah = readb((void __iomem *) ap->ioaddr.lbah_addr);
tf.lbam = readb((void __iomem *) ap->ioaddr.lbam_addr); tf.lbam = readb((void __iomem *) ap->ioaddr.lbam_addr);
tf.lbal = readb((void __iomem *) ap->ioaddr.lbal_addr); tf.lbal = readb((void __iomem *) ap->ioaddr.lbal_addr);
...@@ -1766,6 +1813,11 @@ static void mv_phy_reset(struct ata_port *ap) ...@@ -1766,6 +1813,11 @@ static void mv_phy_reset(struct ata_port *ap)
VPRINTK("EXIT\n"); VPRINTK("EXIT\n");
} }
static void mv_phy_reset(struct ata_port *ap)
{
__mv_phy_reset(ap, 1);
}
/** /**
* mv_eng_timeout - Routine called by libata when SCSI times out I/O * mv_eng_timeout - Routine called by libata when SCSI times out I/O
* @ap: ATA channel to manipulate * @ap: ATA channel to manipulate
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment