* [PATCH 2.6.23.11]: [sata_svw]: Add ATAPI DMA support for HT1x00 SATA controller
@ 2008-01-09 19:13 Anantha Subramanyam
2008-02-02 0:30 ` Jeff Garzik
0 siblings, 1 reply; 3+ messages in thread
From: Anantha Subramanyam @ 2008-01-09 19:13 UTC (permalink / raw)
To: linux-ide; +Cc: Jeff Garzik
This patch adds ATAPI DMA support for HT1000 (aka BCM5785) & HT1100 (aka
BCM11000) SATA Controller.
Signed-off-by: Anantha Subramanyam <ananth@broadcom.com>
---
--- linux-2.6.23.11/drivers/ata/sata_svw.c.orig 2008-01-07
05:22:29.000000000 -0800
+++ linux-2.6.23.11/drivers/ata/sata_svw.c 2008-01-08
03:23:31.000000000 -0800
@@ -45,6 +45,8 @@
#include <linux/interrupt.h>
#include <linux/device.h>
#include <scsi/scsi_host.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi.h>
#include <linux/libata.h>
#ifdef CONFIG_PPC_OF
@@ -53,12 +55,13 @@
#endif /* CONFIG_PPC_OF */
#define DRV_NAME "sata_svw"
-#define DRV_VERSION "2.3"
+#define DRV_VERSION "2.3.1"
enum {
/* ap->flags bits */
K2_FLAG_SATA_8_PORTS = (1 << 24),
K2_FLAG_NO_ATAPI_DMA = (1 << 25),
+ K2_FLAG_BAR_POS_3 = (1 << 26),
/* Taskfile registers offsets */
K2_SATA_TF_CMD_OFFSET = 0x00,
@@ -88,17 +91,216 @@ enum {
/* Port stride */
K2_SATA_PORT_OFFSET = 0x100,
- board_svw4 = 0,
- board_svw8 = 1,
+// ATAPI QDMA start
+ K2_ATAPI_FEAT_DMA_BIT = 0x01,
+
+ /* qdma reg offsets */
+ K2_SATA_QAL_OFFSET = 0xA0,
+ K2_SATA_QAU_OFFSET = 0xA4,
+ K2_SATA_QPI_OFFSET = 0xA8,
+ K2_SATA_QCI_OFFSET = 0xAC,
+ K2_SATA_QCR_OFFSET = 0xB0,
+ K2_SATA_QDR_OFFSET = 0xB4,
+ K2_SATA_QSR_OFFSET = 0xB8,
+ K2_SATA_QMR_OFFSET = 0xBC,
+
+ K2_SATA_GLB_CTL_OFFSET = 0x1000,
+ K2_SATA_GLB_STS_OFFSET = 0x1004,
+
+ K2_SATA_ENABLE_INTRS = 0x21, // 0x3F, want
only done & common error
+ K2_SATA_CLEAR_ALL_INTRS = 0xFFFFFFFF,
+
+ K2_SATA_NUM_DESCRIPTORS = 4, // min 2 for
ATAPI, but min 4 for our hw
+ K2_SATA_QDMA_MODE_ON = 1,
+ K2_SATA_QDMA_ENABLE = 0x01,
+
+ K2_SATA_QDMA_PORT_RESET = 0x08,
+ K2_SATA_QDMA_PORT_ABORT = 0x04,
+ K2_SATA_QDMA_PORT_PAUSE = 0x02,
+ K2_SATA_CLEAR_QDMA_QPI_REG = 0x00,
+
+ K2_SATA_INTR_CMD_ERROR = 0x00000020,
+ K2_SATA_INTR_DEV_CHANGE = 0x10,
+ K2_SATA_INTR_RESET_ACK = 0x08,
+ K2_SATA_INTR_ABORT_ACK = 0x04,
+ K2_SATA_INTR_PAUSE_ACK = 0x02,
+ K2_SATA_INTR_CMD_DONE = 0x00000001,
+
+ K2_SATA_DESC_TYPE = 0x00,
+ K2_SATA_DESC_PIO_DATA = 0x00,
+ K2_SATA_DESC_PIO_NON_DATA = 0x02,
+
+ K2_SATA_CTRL_FLAG_PIO_BIT = 0x80, // PIO bit
+ K2_SATA_CTRL_FLAG_ATAPI = 0x40, // ATAPI
bit
+ K2_SATA_CTRL_FLAG_SKIP = 0x10, // SKIP
bit
+ K2_SATA_CTRL_FLAG_IGNR = 0x08, // IGNR
bit
+ K2_SATA_CTRL_FLAG_RD_DIR_BIT = 0x02, // READ Dir bit
+ K2_SATA_CTRL_FLAG_EIN_BIT = 0x01, // Enable Interrupt
bit
+
+ K2_SATA_DESC_D_BIT = 0x01,
+ K2_CMD_ONLY_FRM = 0x010, /*
No data associated with command */
+
+ K2_ATAPI_CDB_BUFSZ = ATAPI_CDB_LEN,
+
+ K2_SATA_SELECT_DEV0 = 0xA0,
+ K2_SATA_CMD_DEVICE_RESET = 0x08,
+ K2_SATA_STS_BSY = 0x80, // busy
+
+ K2_SATA_SCR2_RESET_PHY = 0x00000001,
+ K2_SATA_SCR2_CLEAR_REG = 0x00000000,
+
+ K2_SATA_DET_MASK = 0x000F,
+ K2_SATA_INTF_MASK = 0x0F00,
+ K2_DEV_DET_PHY_RDY = 0x3,
+ K2_SATA_INFT_ACTIVE = 0x1,
+
+ K2_SATA_10MS_WAIT = 10000,
+ K2_SATA_100MS_WAIT = 100000,
+ K2_SATA_PAUSE_ACK_TIME = 100,
+ K2_SATA_CLEAR_ALL_ERRORS = 0xffffffff,
+ K2_SATA_COM_RESET_WAIT = 1500, //1.5ms
+
+ K2_SATA_QSR_PCI_MASTER_ABORT = (1<<21),
+ K2_SATA_QSR_DATA_CRC_ERR = (1<<20),
+ K2_SATA_QSR_UNDER_FLOW = (1<<19),
+ K2_SATA_QSR_OVER_FLOW = (1<<18),
+ K2_SATA_QSR_ATA_CMD_ERR = (1<<17),
+ K2_SATA_QSR_PCI_BUS_MASTER_ERR = (1<<16),
+ K2_SATA_QSR_SATA_INTF_ERR = (1<<6),
+ K2_SATA_QSR_ATAPI_UNDERRUN = (1<<22),
+
+ chip_svw4 = 0,
+ chip_svw8 = 1,
+ chip_svwx = 2,
+ chip_svw41 = 3,
+// ATAPI QDMA end
+
+// HT1100 additions
+ K2_SATA_SATADBGREG = 0xF0,
+ // K2_SATA_LEDENREG = 0x5000,
+ K2_SATA_TESTCTRLREG = 0x10f0,
+ K2_SATA_MDIOCTRLREG = 0x8c,
+ // K2_SATA_PLLCTRLREG = 0x84,
+
+ K2_SATA_PLL_WAIT = 990,//100000,//90000,
+ K2_SATA_LED_ENABLE_VALUE = 0x00000002,
+ K2_SATA_TEST_CTRL_VALUE = 0x40000001,
+ K2_SATA_PLL_CTRL_VALUE = 0x08000000,
+ K2_SATA_PLL_1P5_GIG = 0,
+ K2_SATA_PLL_3P0_GIG = 1,
+ K2_SATA_RESET_PHY_DELAY = 0x3000,
+
+ // phy vals
+ BCM_SATA_PHY_TXCNT_1G5 = 0x7830,
+ BCM_SATA_PHY_TXCNT_3G0 = 0xF620,
+ BCM_SATA_PHY_RXCNT_1G5 = 0x0180,
+ BCM_SATA_PHY_RXCNT_3G0 = 0x0190,
+
+ chip_svw42 = 4, // HT1100 bar 3
+ chip_svw43 = 5, // HT1100 bar 5
+ // HT1100 addns end
+
};
+/* SATA Command Descriptor Structure */
+
+typedef struct _k2_sata_cmd_desc_s {
+#ifdef __BIG_ENDIAN
+ u8 ss_Rsvd3;
+ u8 ss_PortMul;
+ u8 ss_CtrlFlags;
+ u8 ss_DescType;
+ u16 sw_Tag;
+ u16 sw_HostMemDataBuffAddr;
+ u32 sl_PrdTblBaseLow;
+ u16 sw_PrdCount;
+ u16 sw_PrdTblBaseHigh;
+ u16 sw_Features;
+ u8 ss_DevHead;
+ u8 ss_SataCmd;
+ u32 sl_LbaLow;
+ u16 sw_SectorCount;
+ u16 sw_LbaHigh;
+ u32 sl_Rsvd1c;
+#else
+ u8 ss_DescType;
+ u8 ss_CtrlFlags;
+ u8 ss_PortMul;
+ u8 ss_Rsvd3;
+ u16 sw_HostMemDataBuffAddr;
+ u16 sw_Tag;
+ u32 sl_PrdTblBaseLow;
+ u16 sw_PrdTblBaseHigh;
+ u16 sw_PrdCount;
+ u8 ss_SataCmd;
+ u8 ss_DevHead;
+ u16 sw_Features;
+ u32 sl_LbaLow;
+ u16 sw_LbaHigh;
+ u16 sw_SectorCount;
+ u32 sl_Rsvd1c;
+#endif
+} k2_sata_cmd_desc_t;
+
+
+typedef struct _k2_sata_port_info_s {
+ u8 qpi;
+ u8 qci;
+ u8 qdma_mode;
+ u32 qcr_local;
+
+ // qdma related addrs
+ void __iomem *qal_addr;
+ void __iomem *qau_addr;
+ void __iomem *qpi_addr;
+ void __iomem *qci_addr;
+ void __iomem *qcr_addr;
+ void __iomem *qdr_addr;
+ void __iomem *qsr_addr;
+ void __iomem *qmr_addr;
+
+ // desc area and addresses
+ dma_addr_t cmd_desc_addr;
+ k2_sata_cmd_desc_t* pcmd_desc;
+
+ dma_addr_t cdb_phy_addr;
+ u8 *pcdb_cpybuf;
+
+ u8 needs_reset;
+
+ // atapi related
+ u8 is_atapi_device;
+ u32 qsr_saved;
+ u32 atapi_reset_cnt;
+ u32 atapi_capabilities;
+
+} k2_sata_port_info;
+
+
+int skip_init = 0;
+module_param(skip_init, int, 0444);
+MODULE_PARM_DESC( skip_init, "Initialization done by BIOS");
+
+
static u8 k2_stat_check_status(struct ata_port *ap);
static int k2_sata_check_atapi_dma(struct ata_queued_cmd *qc)
{
+ u8 command = qc->scsicmd->cmnd[0];
+
if (qc->ap->flags & K2_FLAG_NO_ATAPI_DMA)
return -1; /* ATAPI DMA not supported */
+ else
+ {
+ // DMA is for only read or write commands
+ if( (command == READ_10) || (command == READ_16) ||
(command == READ_12)
+ || (command == WRITE_10) || (command ==
WRITE_16) || (command == WRITE_12))
+ // TODO may need to check the dynamic flag in
pspi rather than unconditional ok
+ return 0;
+ else
+ return -1;
+ }
return 0;
}
@@ -305,6 +507,612 @@ static int k2_sata_proc_info(struct Scsi
}
#endif /* CONFIG_PPC_OF */
+// ATAPI QDMA start
+
+#define K2_IS_SATA_STS_GOOD(sata_sts) \
+ (((sata_sts & K2_SATA_DET_MASK) == K2_DEV_DET_PHY_RDY) &&
(((sata_sts & K2_SATA_INTF_MASK)>>8) == K2_SATA_INFT_ACTIVE))
+
+
+void k2_ht1x_qdma_disable(struct ata_port *ap);
+
+
+int k2_ht1x_port_start (struct ata_port *ap)
+{
+ struct device *dev = ap->dev;
+ int rc;
+ k2_sata_port_info* pspi;
+ ap->private_data = NULL;
+
+ rc = ata_port_start( ap);
+ if( rc)
+ return rc;
+
+ // do our qdma descriptor space alloc, we use prd from ata port
itself
+ pspi = kmalloc(sizeof(k2_sata_port_info), GFP_KERNEL);
+ if (pspi == NULL) {
+ rc = -ENOMEM;
+ goto start_err_out;
+ }
+
+ ap->private_data = pspi;
+
+ pspi->pcmd_desc = dma_alloc_coherent(dev, sizeof(
k2_sata_cmd_desc_t) * K2_SATA_NUM_DESCRIPTORS, &pspi->cmd_desc_addr,
GFP_KERNEL);
+ if (pspi->pcmd_desc == NULL) {
+ kfree( pspi);
+ rc = -ENOMEM;
+ goto start_err_out;
+ }
+
+ pspi->pcdb_cpybuf = dma_alloc_coherent(dev, K2_ATAPI_CDB_BUFSZ,
&pspi->cdb_phy_addr, GFP_KERNEL);
+ if (pspi->pcdb_cpybuf == NULL)
+ {
+ dma_free_coherent(dev, sizeof( k2_sata_cmd_desc_t) *
K2_SATA_NUM_DESCRIPTORS, pspi->pcmd_desc, pspi->cmd_desc_addr);
+ kfree( pspi);
+ rc = -ENOMEM;
+ goto start_err_out;
+ }
+
+ // data_addr is at 0 offset
+ pspi->qal_addr = ap->ioaddr.data_addr + K2_SATA_QAL_OFFSET;
+ pspi->qau_addr = ap->ioaddr.data_addr + K2_SATA_QAU_OFFSET;
+ pspi->qpi_addr = ap->ioaddr.data_addr + K2_SATA_QPI_OFFSET;
+ pspi->qci_addr = ap->ioaddr.data_addr + K2_SATA_QCI_OFFSET;
+ pspi->qcr_addr = ap->ioaddr.data_addr + K2_SATA_QCR_OFFSET;
+ pspi->qdr_addr = ap->ioaddr.data_addr + K2_SATA_QDR_OFFSET;
+ pspi->qsr_addr = ap->ioaddr.data_addr + K2_SATA_QSR_OFFSET;
+ pspi->qmr_addr = ap->ioaddr.data_addr + K2_SATA_QMR_OFFSET;
+
+ VPRINTK("svw qal 0x%x qsr addr 0x%x ioaddr 0x%x\n",
pspi->qal_addr, pspi->qsr_addr, ap->ioaddr.data_addr);
+
+ // init our stuff
+ pspi->qpi = 0;
+ pspi->qci = 0;
+ pspi->qdma_mode = 0;
+
+ writeb( 0, pspi->qci_addr);
+ writeb( 0, pspi->qpi_addr);
+ pspi->qcr_local = 0;
+ writel( pspi->qcr_local, pspi->qcr_addr);
+ writel( K2_SATA_CLEAR_ALL_INTRS, pspi->qsr_addr);
+
+ // writel( K2_SATA_ENABLE_INTRS, pspi->qmr_addr);
+ writel( K2_SATA_NUM_DESCRIPTORS - 1, pspi->qdr_addr);
+
+ pspi->needs_reset = 0;
+ pspi->is_atapi_device = 0; // will be set anytime we get a
atapi cmd on the port
+ pspi->atapi_reset_cnt = 0;
+ pspi->atapi_capabilities = 0; // if v need to disable
dma on the fly becoz of too many errors etc
+
+ return 0;
+
+start_err_out:
+
+ return rc;
+}
+
+void k2_ht1x_port_stop (struct ata_port *ap)
+{
+ struct device *dev = ap->dev;
+ k2_sata_port_info* pspi = (k2_sata_port_info*)ap->private_data;
+
+ if( pspi == NULL)
+ return;
+
+ k2_ht1x_qdma_disable( ap);
+
+ // free our private data first, then call generic
+ dma_free_coherent(dev, sizeof( k2_sata_cmd_desc_t) *
K2_SATA_NUM_DESCRIPTORS, pspi->pcmd_desc, pspi->cmd_desc_addr);
+ dma_free_coherent(dev, K2_ATAPI_CDB_BUFSZ, pspi->pcdb_cpybuf,
pspi->cdb_phy_addr);
+ kfree( pspi);
+
+}
+
+/*
+ Some helper functions
+*/
+
+void k2_ht1x_qdma_enable(struct ata_port *ap)
+{
+ k2_sata_port_info* pspi = (k2_sata_port_info*)ap->private_data;
+
+ pspi->qpi = 0;
+ pspi->qci = 0;
+
+ pspi->qcr_local = K2_SATA_QDMA_ENABLE;
+
+ writel( cpu_to_le32(pspi->cmd_desc_addr & 0xffffffff),
pspi->qal_addr);
+
+ // our dma mask is 32bit, so v assume 0 for upper bits
+ // similar to what libata does for prd addresses
+ // as below causes grief in 32bit single CPU flavour
+ // writel( cpu_to_le32( (pspi->cmd_desc_addr >> 32) & 0xffff),
pspi->qau_addr);
+ writel( 0, pspi->qau_addr);
+
+ writeb( 0, pspi->qci_addr);
+ writeb( 0, pspi->qpi_addr);
+ writel( K2_SATA_CLEAR_ALL_INTRS, pspi->qsr_addr);
+ writel( K2_SATA_NUM_DESCRIPTORS - 1, pspi->qdr_addr);
+
+ writel( K2_SATA_ENABLE_INTRS, pspi->qmr_addr);
+ writel( pspi->qcr_local, pspi->qcr_addr);
+
+
+}
+
+void k2_ht1x_qdma_disable(struct ata_port *ap)
+{
+ k2_sata_port_info* pspi = (k2_sata_port_info*)ap->private_data;
+
+ // disable qdma first
+ pspi->qcr_local = 0;
+ writel( pspi->qcr_local, pspi->qcr_addr);
+
+ pspi->qpi = 0;
+ pspi->qci = 0;
+ pspi->qdma_mode = 0;
+
+ writeb( 0, pspi->qci_addr);
+ writeb( 0, pspi->qpi_addr);
+ writel( K2_SATA_CLEAR_ALL_INTRS, pspi->qsr_addr);
+ writel( 0, pspi->qmr_addr);
+ writel( 0, pspi->qdr_addr);
+
+}
+
+int k2_ht1x_qdma_pause(struct ata_port *ap, int pause)
+{
+ k2_sata_port_info* pspi = (k2_sata_port_info*)ap->private_data;
+ u32 qsr;
+ volatile int i = 0;
+
+ // if qdma is not enabled nothing todo, pause or unpause
+ if( !(pspi->qcr_local & K2_SATA_QDMA_ENABLE) )
+ return 0;
+
+ // pause qdma first,
+ // disable intr on pause ack, we will poll for it as we don't q
cmds
+ if( !(pspi->qcr_local & K2_SATA_QDMA_PORT_PAUSE) && pause)
+ {
+ pspi->qcr_local |= K2_SATA_QDMA_PORT_PAUSE;
+ writel( pspi->qcr_local, pspi->qcr_addr);
+
+ // wait for pause ack
+ while( i++ < 200)
+ {
+ udelay( 5);
+
+ if( (qsr = readl( pspi->qsr_addr)) &
K2_SATA_INTR_PAUSE_ACK)
+ {
+ writel( qsr, pspi->qsr_addr);
+ break;
+ }
+ }
+
+ if( i == 200)
+ {
+ pspi->qcr_local &= ~K2_SATA_QDMA_PORT_PAUSE;
+ return -1; // we couldn't pause in 10
msecs, we have problems.....
+ }
+
+ }
+ else
+ // we need to unpause
+ if( (pspi->qcr_local & K2_SATA_QDMA_PORT_PAUSE) && !pause)
+ {
+
+ pspi->qcr_local &= ~K2_SATA_QDMA_PORT_PAUSE;
+ writel( pspi->qcr_local, pspi->qcr_addr);
+ }
+
+ return 0;
+}
+
+
+int k2_build_atapi_cmd_desc(struct ata_queued_cmd *qc,
k2_sata_cmd_desc_t *desc, u8 flags)
+{
+ struct ata_port *ap = qc->ap;
+ k2_sata_port_info* pspi = (k2_sata_port_info*)ap->private_data;
+
+ memset(desc, 0, sizeof(k2_sata_cmd_desc_t));
+
+ desc->ss_CtrlFlags = flags;
+ desc->ss_SataCmd = 0xA0; // ATAPI Pkt Cmd
+ desc->ss_DevHead = 0xA0;
+
+ // as per libata atapi_xlat func, this is set for only pio
+ desc->sl_LbaLow = 0;
+ desc->sw_LbaHigh = 0;
+
+ if (flags & K2_SATA_CTRL_FLAG_ATAPI)
+ {
+ // ATAPI CDB Packet Transfer
+ // Set the CDB pad to zero
+ memset(pspi->pcdb_cpybuf, 0, K2_ATAPI_CDB_BUFSZ);
+ memcpy(pspi->pcdb_cpybuf, qc->cdb, qc->dev->cdb_len);
+
+ desc->sl_PrdTblBaseLow = cpu_to_le32( pspi->cdb_phy_addr
| 0x01);
+ desc->sw_PrdTblBaseHigh = 0;
+ desc->sw_PrdCount = qc->dev->cdb_len;
+ desc->sw_Features = K2_ATAPI_FEAT_DMA_BIT;
+ }
+ else // it is the data desc
+ {
+ // libata does not update this field when splitting
prd's for 64kb crossover
+ // so examine eot bit in first prd element to confirm
+ // if(qc->n_elem == 1) {
+ if( (ap->prd[0].flags_len & cpu_to_le32(ATA_PRD_EOT) )
!= 0) {
+ desc->sl_PrdTblBaseLow = ap->prd[0].addr |
0x01; // already in le format
+ desc->sw_PrdTblBaseHigh = 0; // revisit to
add >4GB support, ata_fill_sg can't be used then
+ desc->sw_PrdCount = ap->prd[0].flags_len
& 0xFFFF;
+
+ }
+ else
+ {
+ desc->sl_PrdTblBaseLow =
cpu_to_le32(ap->prd_dma);
+ desc->sw_PrdTblBaseHigh = 0; // v reuse same
prd table everytime
+ }
+
+ }
+
+ return 0;
+}
+
+void k2_ht1x_qdma_post_atapi(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ k2_sata_port_info* pspi = (k2_sata_port_info*)ap->private_data;
+
+ u8 flags = 0;
+
+ k2_sata_cmd_desc_t* pcdesc = pspi->pcmd_desc + pspi->qpi;
+
+ flags = K2_SATA_CTRL_FLAG_ATAPI | K2_SATA_CTRL_FLAG_PIO_BIT;
// | K2_SATA_CTRL_FLAG_EIN_BIT;
+ k2_build_atapi_cmd_desc( qc, pcdesc, flags);
+
+ flags = K2_SATA_CTRL_FLAG_EIN_BIT;
+
+ if( !(qc->tf.flags & ATA_TFLAG_WRITE) )
+ flags |= K2_SATA_CTRL_FLAG_RD_DIR_BIT;
+ pcdesc++;
+ k2_build_atapi_cmd_desc( qc, pcdesc, flags);
+
+ pspi->qpi = (pspi->qpi + 2) % K2_SATA_NUM_DESCRIPTORS;
+
+ writel( pspi->qpi, pspi->qpi_addr);
+
+
+}
+
+
+/*
+later version of libata (kernel 2.6.18 & later) have a elaborate
+error handling mech that includes multilevel of resets (soft, hard,
post...)
+so we plug into that
+
+*/
+int k2_ht1x_atapi_soft_reset(struct ata_port *ap, unsigned int *class)
+{
+ u8 dev_sts;
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+ int count = 5;
+
+ writel( K2_SATA_SELECT_DEV0, ioaddr->device_addr );
+ udelay( 500);
+ writel( K2_SATA_CMD_DEVICE_RESET, ioaddr->command_addr );
+
+ // this can take upto 5 secs
+ do
+ {
+ dev_sts = ata_busy_wait( ap, 100000, K2_SATA_STS_BSY);
+ count--;
+ } while( ( dev_sts & K2_SATA_STS_BSY) && (count > 0) );
+
+ if (dev_sts & K2_SATA_STS_BSY) {
+ printk("sata_svw : Busy still set after soft reset
dev_sts=%x\n", dev_sts);
+ return -EIO;
+ }
+
+ *class = ata_dev_try_classify(ap, 0, NULL);
+ return 0;
+}
+
+
+int k2_ht1x_atapi_reset(struct ata_port *ap, unsigned int *class)
+{
+ u32 dev_sts, sata_sts, qsr, i;
+ k2_sata_port_info* pspi = (k2_sata_port_info*)ap->private_data;
+ int ret = 0;
+
+
+ // if (port->atapi.capabilities & ELR_ATAPI_QDMA)
+ {
+ k2_ht1x_qdma_disable( ap);
+
+ // Do a PHY reset
+ // Power Down Phy
+ k2_sata_scr_write( ap, (K2_SATA_SCR_CONTROL_OFFSET -
K2_SATA_SCR_STATUS_OFFSET), K2_SATA_SCR2_RESET_PHY );
+ // Delay 1.5ms
+ udelay( K2_SATA_COM_RESET_WAIT);
+ // Power Up Phy
+ k2_sata_scr_write( ap, (K2_SATA_SCR_CONTROL_OFFSET -
K2_SATA_SCR_STATUS_OFFSET), K2_SATA_SCR2_CLEAR_REG );
+ // Delay 1ms : Most drives should be ready within 1ms
+ udelay( K2_SATA_COM_RESET_WAIT);
+ // delay up to 2 seconds, this should be ok for SATA I
and SATA II drives
+ for (i = 0; i < 20; i++) {
+ // check if drive exist again
+ k2_sata_scr_read( ap, 0, &sata_sts );
+ dev_sts = k2_stat_check_status( ap);
+ // drive exist and ready
+ if (K2_IS_SATA_STS_GOOD(sata_sts) && (!(dev_sts
& K2_SATA_STS_BSY))) {
+ // Initialize Registers
+ k2_sata_scr_write( ap,
(K2_SATA_SCR_ERROR_OFFSET - K2_SATA_SCR_STATUS_OFFSET),
K2_SATA_CLEAR_ALL_ERRORS );
+ qsr = readl( pspi->qsr_addr);
+ writel( qsr, pspi->qsr_addr);
+
+ VPRINTK( "PHY Reset on Port[%x] i=%x
DrvSts=%x SataSts=%x SUCCESSFULLY Completed\n",
+ ap->port_no, i, dev_sts,
sata_sts);
+ break;
+ }
+ // check every 1 milli second, most of the
drive will be ready in a milli second
+ msleep( K2_SATA_100MS_WAIT / 1000);
+ }
+ if (i == 20) {
+ DPRINTK("\n\nPHY Reset on Port[%x] DrvSts=%x
SataSts=%x FAILED\n\n",
+ ap->port_no, dev_sts, sata_sts);
+ ret = -EIO;
+ }
+
+ // QDMA Reset
+ writel( (K2_SATA_QDMA_PORT_RESET|K2_SATA_QDMA_ENABLE),
pspi->qcr_addr);
+ // Wait for the Reset ack
+ for (i = 0; i < K2_SATA_PAUSE_ACK_TIME; i++) {
+ qsr = readl( pspi->qsr_addr);
+ if (qsr & K2_SATA_INTR_RESET_ACK) break;
+ udelay( K2_SATA_10MS_WAIT);
+ }
+ if (i == K2_SATA_PAUSE_ACK_TIME) {
+ printk("sata_svw : Port[%x] ATAPI Reset FAILED QSR=%x\n",
ap->port_no, qsr);
+ ret = -EIO;
+ }
+
+ qsr = readl( pspi->qsr_addr);
+ writel( qsr, pspi->qsr_addr);
+ // Clear bit 5 in QSR if set
+ if (qsr & K2_SATA_INTR_CMD_ERROR)
+ writel( qsr, pspi->qsr_addr);
+ k2_sata_scr_write( ap, (K2_SATA_SCR_ERROR_OFFSET -
K2_SATA_SCR_STATUS_OFFSET), K2_SATA_CLEAR_ALL_ERRORS );
+ }
+
+ if( ret != 0)
+ return ret;
+
+
+ // Enable QDMA
+ k2_ht1x_qdma_enable( ap);
+
+ *class = ata_dev_try_classify(ap, 0, NULL);
+ return 0;
+}
+
+
+inline unsigned int k2_ht1x_handle_qdma_error (struct ata_port *ap,
+ struct ata_queued_cmd *qc, u32 qsr)
+{
+ u8 status;
+ k2_sata_port_info* pspi = (k2_sata_port_info*)ap->private_data;
+
+ k2_ht1x_qdma_pause( ap, 1);
+ DPRINTK("qdma atapi error 0x%x\n", qsr);
+
+ // all tf registers specifically sts maintain their contents, so
fall into libata's complete fn
+ if( qsr & K2_SATA_QSR_PCI_BUS_MASTER_ERR)
+ {
+ qc->err_mask |= AC_ERR_HOST_BUS;
+ ap->hsm_task_state = HSM_ST_ERR;
+ }
+
+ status = k2_stat_check_status( ap);
+
+ if( (qsr & K2_SATA_QSR_OVER_FLOW) || ( pspi->qci != pspi->qpi) )
+ {
+ printk( "sata_svw needs_reset=1 qsr 0x%x\n", qsr);
+ pspi->qsr_saved = qsr;
+ pspi->needs_reset = 1;
+ qc->err_mask |= AC_ERR_HSM;
+ // this will freeze the port & ops->error_handler is
then invoked to thaw the port
+ // and do other bad things like reset (hard, soft) etc
+ }
+
+ ata_hsm_move( ap, qc, status, 0);
+ return 0;
+
+}
+
+inline unsigned int k2_ht1x_qdma_intr (struct ata_port *ap,
+ struct ata_queued_cmd *qc)
+{
+ u32 qsr;
+ k2_sata_port_info* pspi = (k2_sata_port_info*)ap->private_data;
+
+ VPRINTK("ata%u: protocol %d task_state %d\n",
+ ap->id, qc->tf.protocol, ap->hsm_task_state);
+
+ /* Check whether we are expecting interrupt in this state */
+ switch (ap->hsm_task_state) {
+ case HSM_ST_LAST:
+ if (qc->tf.protocol == ATA_PROT_ATAPI_DMA)
+ {
+
+ // do some qdma qsr processing here
+ qsr = readl( pspi->qsr_addr);
+
+ // check if there is an error, if not make sure
it is the done for the 2nd cmd
+ writel( qsr, pspi->qsr_addr);
+ pspi->qci = readl( pspi->qci_addr);
+ if( qsr & K2_SATA_INTR_CMD_ERROR)
+ {
+ // clear qsr common error bit
+ writel( qsr, pspi->qsr_addr);
+
+ k2_ht1x_handle_qdma_error( ap, qc, qsr);
+ return 1; /* irq handled */
+ }
+ else
+ {
+ if( pspi->qci != pspi->qpi)
+ {
+ printk("sata_svw STOP stuck
without error qsr 0x%x\n", qsr);
+ return 0;
+ }
+
+
+ // yay! v got a normal completion, let
us finish it
+ ap->hsm_task_state = HSM_ST_IDLE;
+
+ // for now just clear tf read flag,
hopefully it is used only in error path
+ qc->flags &= ~ATA_QCFLAG_RESULT_TF;
+ ata_qc_complete( qc);
+ return 1; /* irq handled */
+ }
+ }
+ else
+ printk("wrong protocol, we shouldn't hv been
here %d \n", qc->tf.protocol);
+ break;
+
+
+ default:
+ break; // goto idle_irq;
+ }
+
+ return 0; /* irq not handled */
+}
+
+
+irqreturn_t k2_ht1x_interrupt (int irq, void *dev_instance)
+{
+ struct ata_host *host = dev_instance;
+ unsigned int i;
+ unsigned int handled = 0;
+ unsigned long flags;
+ k2_sata_port_info* pspi;
+ u32 glbsts;
+ struct ata_port *ap;
+ struct ata_queued_cmd *qc;
+
+ /* TODO: make _irqsave conditional on x86 PCI IDE legacy mode */
+ spin_lock_irqsave(&host->lock, flags);
+
+ ap = host->ports[0];
+ glbsts = readl( ap->ioaddr.data_addr + K2_SATA_GLB_STS_OFFSET);
+ for (i = 0; i < host->n_ports; i++)
+ {
+ if( glbsts & (1 << i) )
+ // '1' bit indicates no interrupt on this port,
keep moving
+ continue;
+
+ ap = host->ports[i];
+
+ if (ap &&
+ !(ap->flags & ATA_FLAG_DISABLED)) {
+ pspi = (k2_sata_port_info*)ap->private_data;
+ if( !pspi)
+ {
+ VPRINTK("pspi not set port %d \n", i);
+ continue;
+ }
+
+ qc = ata_qc_from_tag(ap, ap->active_tag);
+ if (qc &&
+ (qc->flags & ATA_QCFLAG_ACTIVE))
+ {
+ if( (pspi->qcr_local &
K2_SATA_QDMA_ENABLE) &&
+ !(pspi->qcr_local &
K2_SATA_QDMA_PORT_PAUSE) )
+ handled |= k2_ht1x_qdma_intr(
ap, qc);
+ else
+ if( !(qc->tf.flags & ATA_TFLAG_POLLING))
+ // let libata's nice handler
take care of it
+ handled |= ata_host_intr(ap,
qc);
+ }
+
+ }
+ }
+
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ return IRQ_RETVAL(handled);
+}
+
+unsigned int k2_ht1x_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ k2_sata_port_info* pspi = (k2_sata_port_info*)ap->private_data;
+
+ /* start the command */
+ switch (qc->tf.protocol) {
+
+ // ATA stuff fall through to libata
+ case ATA_PROT_NODATA:
+ case ATA_PROT_PIO:
+ case ATA_PROT_DMA:
+ pspi->is_atapi_device = 0;
+ return ata_qc_issue_prot( qc);
+ break;
+
+ case ATA_PROT_ATAPI:
+ case ATA_PROT_ATAPI_NODATA:
+ pspi->is_atapi_device = 1;
+ if( (pspi->qcr_local & K2_SATA_QDMA_ENABLE) &&
+ !(pspi->qcr_local & K2_SATA_QDMA_PORT_PAUSE) )
+ k2_ht1x_qdma_pause( ap, 1);
+
+ return ata_qc_issue_prot( qc);
+ break;
+
+
+ case ATA_PROT_ATAPI_DMA:
+ WARN_ON(qc->tf.flags & ATA_TFLAG_POLLING);
+ pspi->is_atapi_device = 1;
+
+ if( !(pspi->qcr_local & K2_SATA_QDMA_ENABLE) )
+ k2_ht1x_qdma_enable( ap);
+ else
+ // unpause if needed
+ if( pspi->qcr_local & K2_SATA_QDMA_PORT_PAUSE)
+ k2_ht1x_qdma_pause( ap, 0);
+
+ k2_ht1x_qdma_post_atapi( qc);
+
+ ap->hsm_task_state = HSM_ST_LAST;
+ break;
+
+ default:
+ WARN_ON(1);
+ return AC_ERR_SYSTEM;
+ }
+
+ return 0;
+}
+
+void k2_sata_error_handler(struct ata_port *ap)
+{
+ k2_sata_port_info* pspi = (k2_sata_port_info*)ap->private_data;
+
+ if( !pspi->is_atapi_device)
+ {
+ // let libata do all the hard work
+ ata_bmdma_error_handler( ap);
+ return;
+ }
+
+ // if we have atapi then likely we used qdma and hung on that
+ // so we use our soft & hardresets
+ ata_bmdma_drive_eh(ap, ata_std_prereset,
k2_ht1x_atapi_soft_reset, k2_ht1x_atapi_reset,
+ ata_std_postreset);
+
+}
+
+// ATAPI QDMA end
+
static struct scsi_host_template k2_sata_sht = {
.module = THIS_MODULE,
@@ -346,6 +1154,7 @@ static const struct ata_port_operations
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
+ .irq_handler = ata_interrupt,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
@@ -355,8 +1164,42 @@ static const struct ata_port_operations
.port_start = ata_port_start,
};
+// ATAPI QDMA start
+
+static const struct ata_port_operations k2_ht1x_ops = {
+ .port_disable = ata_port_disable,
+ .tf_load = k2_sata_tf_load,
+ .tf_read = k2_sata_tf_read,
+ .check_status = k2_stat_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+ .check_atapi_dma = k2_sata_check_atapi_dma,
+ .bmdma_setup = k2_bmdma_setup_mmio,
+ .bmdma_start = k2_bmdma_start_mmio,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = k2_ht1x_qc_issue_prot,
+ .data_xfer = ata_data_xfer,
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = k2_sata_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .irq_handler = k2_ht1x_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
+ .scr_read = k2_sata_scr_read,
+ .scr_write = k2_sata_scr_write,
+ .port_start = k2_ht1x_port_start,
+ .port_stop = k2_ht1x_port_stop,
+};
+
+// ATAPI QDMA end
+
+
static const struct ata_port_info k2_port_info[] = {
- /* board_svw4 */
+ /* chip_svw4 */
{
.flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_MMIO | K2_FLAG_NO_ATAPI_DMA,
@@ -365,7 +1208,7 @@ static const struct ata_port_info k2_por
.udma_mask = ATA_UDMA6,
.port_ops = &k2_sata_ops,
},
- /* board_svw8 */
+ /* chip_svw8 */
{
.flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_MMIO | K2_FLAG_NO_ATAPI_DMA |
@@ -375,8 +1218,156 @@ static const struct ata_port_info k2_por
.udma_mask = ATA_UDMA6,
.port_ops = &k2_sata_ops,
},
+ /* chip_svwx */
+ {
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_MMIO | K2_FLAG_BAR_POS_3,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &k2_ht1x_ops,
+ },
+ /* chip_svw41 */
+ {
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_MMIO,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &k2_ht1x_ops,
+ },
+ /* chip_svw42 */
+ {
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_MMIO | K2_FLAG_BAR_POS_3,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &k2_sata_ops,
+ },
+ /* chip_svw43 */
+ {
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_MMIO,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &k2_sata_ops,
+ },
};
+// HT1100 addns
+inline void k2_lnx_sleep( u32 usec_delay)
+{
+ (usec_delay > 1000) ? mdelay(usec_delay/1000 + 1):
udelay(usec_delay);
+}
+
+
+#define K2_SATA_WAIT_MDIO_DONE(reg) \
+{ \
+ u32 tmp_reg, to = 1000; \
+ while (to) { \
+ tmp_reg = cpu_to_le32( readl(reg) ); \
+ if (tmp_reg & (1 << 15)) { \
+ break; \
+ } \
+ k2_lnx_sleep( 10); \
+ to--; \
+ } \
+}
+
+#define K2_IS_SATA_STS_GOOD(sata_sts) \
+ (((sata_sts & K2_SATA_DET_MASK) == K2_DEV_DET_PHY_RDY) &&
(((sata_sts & K2_SATA_INTF_MASK)>>8) == K2_SATA_INFT_ACTIVE))
+
+
+inline void k2_sata_port_reset_phy_start_oob( void __iomem
*mmio_port_base, u32 ul_satainitval)
+{
+ u32 oob_try = 0, sata_sts;
+
+ writel( ul_satainitval, (mmio_port_base + K2_SATA_SATADBGREG) );
+ k2_lnx_sleep( K2_SATA_RESET_PHY_DELAY);
+
+ // Retry oob up to 5 times
+ do {
+ writel( K2_SATA_SCR2_RESET_PHY, (mmio_port_base +
K2_SATA_SCR_CONTROL_OFFSET) );
+ k2_lnx_sleep( K2_SATA_RESET_PHY_DELAY);
+
+ writel( K2_SATA_SCR2_CLEAR_REG, (mmio_port_base +
K2_SATA_SCR_CONTROL_OFFSET) );
+ k2_lnx_sleep( K2_SATA_RESET_PHY_DELAY);
+
+ sata_sts = readl( mmio_port_base + K2_SATA_SCR_STATUS_OFFSET);
+ } while ((!K2_IS_SATA_STS_GOOD(sata_sts)) && (++oob_try < 5));
+
+}
+
+
+inline void k2_sata_pll_init(void __iomem *mmio_base, u32 link_rate,
u32 portnum)
+{
+ u32 ul_PortSelect=0;
+ u32 ul_initval, ul_voltval, mdioctrl;
+
+
+ /* MDIO access is accessible only through Port 0, so we take mmio
base as input */
+
+ // Enable MDIO Space
+ writel( K2_SATA_TEST_CTRL_VALUE, ( mmio_base + K2_SATA_TESTCTRLREG)
);
+ k2_lnx_sleep( K2_SATA_PLL_WAIT);
+
+ /* mdio reg: 31:16 - r/w data
+ * 15 - done
+ * 14:13 - r(10) w(01)
+ * 12:8 - device address
+ * 7:5 - res
+ * 4:0 - reg addr
+ */
+
+ // pll workaround
+ writel( 0x4002, (mmio_base + K2_SATA_MDIOCTRLREG));
+ K2_SATA_WAIT_MDIO_DONE(mmio_base + K2_SATA_MDIOCTRLREG);
+ mdioctrl = readl( mmio_base + K2_SATA_MDIOCTRLREG) >> 16;
+ // clear bit 2
+ mdioctrl &= ~0x04;
+ mdioctrl = mdioctrl << 16;
+ writel( mdioctrl | 0x2002, (mmio_base + K2_SATA_MDIOCTRLREG));
+ K2_SATA_WAIT_MDIO_DONE(mmio_base + K2_SATA_MDIOCTRLREG);
+
+
+ ul_PortSelect = (((1 << portnum) << 16) | (0x2007));
+
+ if (link_rate == K2_SATA_PLL_1P5_GIG)
+ {
+ //550 mV (Main Driver), 0% pre-emphasis, 0% Bias for SATA 1.5G
: voltval=0x7830
+ ul_voltval = (BCM_SATA_PHY_TXCNT_1G5 << 16) | 0x200a;
+ ul_initval = (BCM_SATA_PHY_RXCNT_1G5 << 16) | 0x2008;
+ }
+ else
+ {
+ //750 mV (Main Driver), 20% pre-emphasis, 0% Bias for 3G :
voltval=0xF620
+ ul_voltval = (BCM_SATA_PHY_TXCNT_3G0 << 16) | 0x200a;
+ ul_initval = (BCM_SATA_PHY_RXCNT_3G0 << 16) | 0x2008;
+ }
+
+ writel( ul_PortSelect, (mmio_base + K2_SATA_MDIOCTRLREG));
+ K2_SATA_WAIT_MDIO_DONE(mmio_base + K2_SATA_MDIOCTRLREG);
+
+ writel( ul_initval, (mmio_base + K2_SATA_MDIOCTRLREG));
+ K2_SATA_WAIT_MDIO_DONE(mmio_base + K2_SATA_MDIOCTRLREG);
+
+ writel( ul_voltval, (mmio_base + K2_SATA_MDIOCTRLREG));
+ K2_SATA_WAIT_MDIO_DONE(mmio_base + K2_SATA_MDIOCTRLREG);
+
+ // Disable MDIO Access
+ mdioctrl = readl( mmio_base + K2_SATA_TESTCTRLREG);
+ mdioctrl &= (~K2_SATA_TEST_CTRL_VALUE);
+ writel( mdioctrl | 0x01, (mmio_base + K2_SATA_TESTCTRLREG) );
+ k2_lnx_sleep( K2_SATA_PLL_WAIT);
+
+}
+
+// HT1100 end
+
+
+
static void k2_sata_setup_port(struct ata_ioports *port, void __iomem
*base)
{
port->cmd_addr = base + K2_SATA_TF_CMD_OFFSET;
@@ -399,12 +1390,12 @@ static void k2_sata_setup_port(struct at
static int k2_sata_init_one (struct pci_dev *pdev, const struct
pci_device_id *ent)
{
- static int printed_version;
+ static int printed_version = 0;
const struct ata_port_info *ppi[] =
{ &k2_port_info[ent->driver_data], NULL };
struct ata_host *host;
void __iomem *mmio_base;
- int n_ports, i, rc;
+ int n_ports, i, rc, bar_pos;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version "
DRV_VERSION "\n");
@@ -418,6 +1409,10 @@ static int k2_sata_init_one (struct pci_
if (!host)
return -ENOMEM;
+ bar_pos = 5;
+ if (ppi[0]->flags & K2_FLAG_BAR_POS_3)
+ bar_pos = 3;
+
/*
* If this driver happens to only be useful on Apple's K2, then
* we should check that here as it has a normal Serverworks ID
@@ -430,25 +1425,51 @@ static int k2_sata_init_one (struct pci_
* Check if we have resources mapped at all (second function may
* have been disabled by firmware)
*/
- if (pci_resource_len(pdev, 5) == 0)
+ if (pci_resource_len(pdev, bar_pos) == 0)
return -ENODEV;
/* Request and iomap PCI regions */
- rc = pcim_iomap_regions(pdev, 1 << 5, DRV_NAME);
+ // rc = pcim_iomap_regions(pdev, 1 << 5, DRV_NAME);
+ rc = pcim_iomap_regions(pdev, 1 << bar_pos, DRV_NAME);
if (rc == -EBUSY)
pcim_pin_device(pdev);
if (rc)
return rc;
host->iomap = pcim_iomap_table(pdev);
- mmio_base = host->iomap[5];
+ mmio_base = host->iomap[bar_pos];
/* different controllers have different number of ports -
currently 4 or 8 */
/* All ports are on the same function. Multi-function device is
no
* longer available. This should not be seen in any system. */
for (i = 0; i < host->n_ports; i++)
+ {
+// HT1100 addns start
+ if( ent->device == 0x0410)
+ {
+ if( !skip_init)
+ {
+ // set mode, phy vals etc
+ // ht1100 needs a global phy enable bit,
so we do that for port zero iteration
+ if( i == 0)
+ writel( readl( mmio_base +
0x10F0) | 0x01, (mmio_base + 0x10F0) );
+
+ k2_sata_pll_init( mmio_base,
K2_SATA_PLL_1P5_GIG, i);
+
+ k2_sata_port_reset_phy_start_oob(
mmio_base + (i * K2_SATA_PORT_OFFSET), 0x10100 );
+
+ }
+
+ writel( readl( mmio_base + (i *
K2_SATA_PORT_OFFSET) + 0x84) | 0x2000f800, (mmio_base + (i *
K2_SATA_PORT_OFFSET) + 0x84) );
+ writel( readl( mmio_base + (i *
K2_SATA_PORT_OFFSET) + 0xE0) | 0x2, (mmio_base + (i *
K2_SATA_PORT_OFFSET) + 0xE0) );
+ }
+// HT1100 addns end
+
k2_sata_setup_port(&host->ports[i]->ioaddr,
mmio_base + i * K2_SATA_PORT_OFFSET);
+ }
+
+
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
return rc;
@@ -468,7 +1489,7 @@ static int k2_sata_init_one (struct pci_
writel(0x0, mmio_base + K2_SATA_SIM_OFFSET);
pci_set_master(pdev);
- return ata_host_activate(host, pdev->irq, ata_interrupt,
IRQF_SHARED,
+ return ata_host_activate(host, pdev->irq,
ppi[0]->port_ops->irq_handler, IRQF_SHARED,
&k2_sata_sht);
}
@@ -477,14 +1498,19 @@ static int k2_sata_init_one (struct pci_
* 0x242 is device ID for Serverworks Frodo8
* 0x24a is device ID for BCM5785 (aka HT1000) HT southbridge
integrated SATA
* controller
+ * 0x41x is device ID for HT1100 southbridge integrated SATA storage
controller
* */
static const struct pci_device_id k2_sata_pci_tbl[] = {
- { PCI_VDEVICE(SERVERWORKS, 0x0240), board_svw4 },
- { PCI_VDEVICE(SERVERWORKS, 0x0241), board_svw4 },
- { PCI_VDEVICE(SERVERWORKS, 0x0242), board_svw8 },
- { PCI_VDEVICE(SERVERWORKS, 0x024a), board_svw4 },
- { PCI_VDEVICE(SERVERWORKS, 0x024b), board_svw4 },
-
+ { PCI_VDEVICE(SERVERWORKS, 0x0240), chip_svw4 },
+ { PCI_VDEVICE(SERVERWORKS, 0x0241), chip_svw4 },
+ { PCI_VDEVICE(SERVERWORKS, 0x0242), chip_svw8 },
+// ATAPI QDMA start
+ { PCI_VDEVICE(SERVERWORKS, 0x024a), chip_svw41 },
+ { PCI_VDEVICE(SERVERWORKS, 0x024b), chip_svw41 },
+ { PCI_VDEVICE(SERVERWORKS, 0x024c), chip_svw4 },
+// ATAPI QDMA end
+ { PCI_VDEVICE(SERVERWORKS, 0x0410), chip_svw42 },
+ { PCI_VDEVICE(SERVERWORKS, 0x0411), chip_svw43 },
{ }
};
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: [PATCH 2.6.23.11]: [sata_svw]: Add ATAPI DMA support for HT1x00 SATA controller
2008-01-09 19:13 [PATCH 2.6.23.11]: [sata_svw]: Add ATAPI DMA support for HT1x00 SATA controller Anantha Subramanyam
@ 2008-02-02 0:30 ` Jeff Garzik
2008-02-02 3:11 ` Anantha Subramanyam
0 siblings, 1 reply; 3+ messages in thread
From: Jeff Garzik @ 2008-02-02 0:30 UTC (permalink / raw)
To: Anantha Subramanyam; +Cc: linux-ide
Anantha Subramanyam wrote:
> This patch adds ATAPI DMA support for HT1000 (aka BCM5785) & HT1100
> (aka BCM11000) SATA Controller.
>
> Signed-off-by: Anantha Subramanyam <ananth@broadcom.com>
Thanks much for your patience. Feedback:
Engineering process issues:
1) patch is word-wrapped, and cannot be applied by automatic tools. In
Linux, email is second only to the C compiler as a tool critical to
development work. It might take some time to get things set up
correctly -- but that's a one-time cost.
2) several occurences of "whitespace mangling": tabs were converted to
spaces, again making our automated tools unable to apply the patch.
Consistency (with other Linux drivers) issues:
1) avoid C++ comments. The rest of the driver exclusively uses /* style
(and 95% of the rest of the kernel does too). You should follow the
existing coding style whenever modifying existing code.
2) don't define a struct twice, once for each endian
(_k2_sata_cmd_desc_s). We use a very specific style, which the "sparse"
source code checking tool knows and checks:
a) define a single version of the struct
b) use C types that indicate endianness: __le32, __be16, etc.
c) in the source code, add endian conversions:
foo->prd_tbl_base_lo = cpu_to_le32(address);
These endian conversions are automatically optimized out
on like-endian platforms, and are heavily optimized on
unlike-endian platforms.
3) use POSIX-style struct definitions:
OK:
struct foo {
...
};
Not OK:
typedef struct _foo {
...
} foo_t;
4) avoid what we call "StudlyCaps" :) The preferred Linux style used in
the vast majority of code is lower case, with underscores separating words:
OK:
prd_tbl_hi
prd_cnt
prd_tbl_lo
Not OK:
sl_PrdTblBaseLow
sw_PrdCount
sw_PrdTblBaseHigh
5) similarly, avoid Hungarian notation, where the type is indicated in
the variable/member name.
OK: prd_tbl_lo
Not OK: sl_prd_tbl_lo
6) No need to add an extra indentation level after a 'return' statement:
> static int k2_sata_check_atapi_dma(struct ata_queued_cmd *qc) { + u8
> command = qc->scsicmd->cmnd[0]; + if (qc->ap->flags &
> K2_FLAG_NO_ATAPI_DMA) return -1; /* ATAPI DMA not supported */ + else
> + {
7) static inline functions are preferred over cpp macros, because they
are far more type-safe.
> +#define K2_IS_SATA_STS_GOOD(sata_sts) \ + (((sata_sts &
> K2_SATA_DET_MASK) == K2_DEV_DET_PHY_RDY) && (((sata_sts &
> K2_SATA_INTF_MASK)>>8) == K2_SATA_INFT_ACTIVE))
The C compiler is smart enough to ensure there is no penalty for using a
function rather than a macro.
8) in k2_ht1x_port_start(), use the standard Linux 'goto unwind' method
of error handling:
pspi = kmalloc(sizeof(k2_sata_port_info), GFP_KERNEL);
if (!pspi)
goto err_out;
pspi->pcmd_desc = dma_alloc_coherent(dev, ...);
if (!pspi->pcmd_desc)
goto err_out_pspi;
pspi->pcdb_cpybuf = dma_alloc_coherent(dev, ...);
if (!pspi->pcdb_cpybuf)
goto err_out_pcmd;
/* ... etc ... */
return 0;
err_out_pcmd:
dma_free_coherent(pspi->pcmd_desc);
err_out_pspi:
kfree(pspi);
err_out:
return rc;
9) don't add unnecessary casts from a void pointer:
> k2_sata_port_info* pspi = (k2_sata_port_info*)ap->private_data;
10) remove redundant comment... by definition this statement is always
true, since your patch will be merged into a kernel later than 2.6.18.
> +/*
> +later version of libata (kernel 2.6.18 & later) have a elaborate
> +error handling mech that includes multilevel of resets (soft, hard,
> post...)
> +so we plug into that
> +
> +*/
11) K2_SATA_WAIT_MDIO_DONE() should be a function, not a macro
12) overall, make sure your patch passes 'sparse' (see
Documentation/sparse.txt) and 'checkpatch' (see scripts/checkpatch.pl)
checks before submission. There are other minor issues I did not bother
to outline here.
Operational issues:
1) Use of 'volatile' is almost always the wrong thing to do:
> int k2_ht1x_qdma_pause(struct ata_port *ap, int pause)
> +{
> + k2_sata_port_info* pspi = (k2_sata_port_info*)ap->private_data;
> + u32 qsr;
> + volatile int i = 0;
In Linux, if you feel you need 'volatile', then really you most likely
need (a) to remove it, (b) to use a barrier(), or (c) use a spinlock.
'volatile' across SMP machines is rather useless, and ill-defined in the
C specifications.
2) remove redundant initialization of static var. Static variables are,
by definition, initialized to zero. Explicit initialization simply
wastes space in the initialized variable area.
> - static int printed_version;
> + static int printed_version = 0;
3) we try _very_ hard to avoid all dependencies on the state produced by
BIOS. The three main reasons:
a) the driver may be used on non-x86 platforms, where
x86 BIOS code simply cannot be executed
b) during suspend/resume, the driver must be able to
initialize the controller fully after transition
from PCI D3 to PCI D0
c) PCI controller hotplug
Thus, I would like to avoid the need for the 'skip_init' module
parameter. Users and automated Linux install tools will be completely
unaware of skip_init, and will not have enough knowledge to use it. It
is best to simply Do The Right Thing in all cases.
4) don't use udelay/mdelay when you can sleep:
> +inline void k2_lnx_sleep( u32 usec_delay)
> +{
> + (usec_delay > 1000) ? mdelay(usec_delay/1000 + 1):
> udelay(usec_delay);
> +}
5) is it reasonable to use QDMA for ATA also?
6) use spin_lock() rather than spin_lock_irqsave() in
k2_ht1x_interrupt(). You're not competing with other interrupts AFAICS.
7) in k2_ht1x_qdma_intr(), ap->hsm_task_state generally refers to PIO
state. ditto for the use of ata_hsm_move() in k2_ht1x_handle_qdma_error().
Can you explain the need, there?
It is more likely that you should override ->qc_issue and handle things
at a top level, rather than overriding specific pieces of the ATAPI host
state machine. The HSM was not really designed to be overridden piecemeal.
^ permalink raw reply [flat|nested] 3+ messages in thread* RE: [PATCH 2.6.23.11]: [sata_svw]: Add ATAPI DMA support for HT1x00 SATA controller
2008-02-02 0:30 ` Jeff Garzik
@ 2008-02-02 3:11 ` Anantha Subramanyam
0 siblings, 0 replies; 3+ messages in thread
From: Anantha Subramanyam @ 2008-02-02 3:11 UTC (permalink / raw)
To: Jeff Garzik; +Cc: linux-ide
>
> Thanks much for your patience. Feedback:
>
.
.
.
> > - static int printed_version;
> > + static int printed_version = 0;
>
Thanks for the detailed feedback, will take care of points raised above.
>
> 3) we try _very_ hard to avoid all dependencies on the state
> produced by
> BIOS. The three main reasons:
>
> a) the driver may be used on non-x86 platforms, where
> x86 BIOS code simply cannot be executed
>
> b) during suspend/resume, the driver must be able to
> initialize the controller fully after transition
> from PCI D3 to PCI D0
>
> c) PCI controller hotplug
>
> Thus, I would like to avoid the need for the 'skip_init' module
> parameter. Users and automated Linux install tools will be
> completely
> unaware of skip_init, and will not have enough knowledge to
> use it. It
> is best to simply Do The Right Thing in all cases.
>
Can be left out, but the reasoning behind this was :
1. For our embedded customers who spin their own kernels, this code was
meant to be a placeholder to optimize the pre-emphasis etc values as
needed.
2. Default was left as BIOS controlled for the customers who use
standard linux distributions but will always have BIOS to optimize these
values.
Good point about the hotplus, but this controller is part of the
motherboard chipset so hotplug should not be an issue.
>
> 4) don't use udelay/mdelay when you can sleep:
>
> > +inline void k2_lnx_sleep( u32 usec_delay)
> > +{
> > + (usec_delay > 1000) ? mdelay(usec_delay/1000 + 1):
> > udelay(usec_delay);
> > +}
>
>
> 5) is it reasonable to use QDMA for ATA also?
>
Yes QDMA could be used for ATA also. Due to time considerations plan to
do this at a later stage, currently the brunt of the patch is aimed at
providing DMA support for ATAPI devices by working around a busmaster
issue with ATAPI.
>
> 6) use spin_lock() rather than spin_lock_irqsave() in
> k2_ht1x_interrupt(). You're not competing with other
> interrupts AFAICS.
>
Interrupt could come from other ports before completing processing for
the currently interrupting ports, or am I missing something. Based this
function on the current generic handler ata_interrupt.
>
> 7) in k2_ht1x_qdma_intr(), ap->hsm_task_state generally refers to PIO
> state. ditto for the use of ata_hsm_move() in
> k2_ht1x_handle_qdma_error().
>
> Can you explain the need, there?
>
Maybe I misunderstood the code, but k2_ht1x_qdma_intr was based on
ata_host_intr.
> It is more likely that you should override ->qc_issue and
> handle things
> at a top level, rather than overriding specific pieces of the
> ATAPI host
> state machine. The HSM was not really designed to be
> overridden piecemeal.
>
>
Related to #5 above. Had considered it, but could not see a way to
override qc_issue without affecting the ATA interface. Suggestions ?
Thanks again.
-Ananth
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2008-02-02 5:12 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-01-09 19:13 [PATCH 2.6.23.11]: [sata_svw]: Add ATAPI DMA support for HT1x00 SATA controller Anantha Subramanyam
2008-02-02 0:30 ` Jeff Garzik
2008-02-02 3:11 ` Anantha Subramanyam
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).