2005-10-11 01:53:58 +04:00
/*
* pdc_adma . c - Pacific Digital Corporation ADMA
*
* Maintained by : Mark Lord < mlord @ pobox . com >
*
* Copyright 2005 Mark Lord
*
2005-10-11 09:44:14 +04:00
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 , or ( at your option )
* any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; see the file COPYING . If not , write to
* the Free Software Foundation , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*
*
* libata documentation is available via ' make { ps | pdf } docs ' ,
* as Documentation / DocBook / libata . *
2005-10-11 01:53:58 +04:00
*
*
* Supports ATA disks in single - packet ADMA mode .
* Uses PIO for everything else .
*
* TODO : Use ADMA transfers for ATAPI devices , when possible .
* This requires careful attention to a number of quirks of the chip .
*
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/pci.h>
# include <linux/init.h>
# include <linux/blkdev.h>
# include <linux/delay.h>
# include <linux/interrupt.h>
# include <linux/sched.h>
2005-10-30 22:39:11 +03:00
# include <linux/device.h>
2005-10-11 01:53:58 +04:00
# include <scsi/scsi_host.h>
# include <asm/io.h>
# include <linux/libata.h>
# define DRV_NAME "pdc_adma"
2006-04-03 04:41:36 +04:00
# define DRV_VERSION "0.04"
2005-10-11 01:53:58 +04:00
/* macro to calculate base address for ATA regs */
# define ADMA_ATA_REGS(base,port_no) ((base) + ((port_no) * 0x40))
/* macro to calculate base address for ADMA regs */
# define ADMA_REGS(base,port_no) ((base) + 0x80 + ((port_no) * 0x20))
enum {
ADMA_PORTS = 2 ,
ADMA_CPB_BYTES = 40 ,
ADMA_PRD_BYTES = LIBATA_MAX_PRD * 16 ,
ADMA_PKT_BYTES = ADMA_CPB_BYTES + ADMA_PRD_BYTES ,
ADMA_DMA_BOUNDARY = 0xffffffff ,
/* global register offsets */
ADMA_MODE_LOCK = 0x00c7 ,
/* per-channel register offsets */
ADMA_CONTROL = 0x0000 , /* ADMA control */
ADMA_STATUS = 0x0002 , /* ADMA status */
ADMA_CPB_COUNT = 0x0004 , /* CPB count */
ADMA_CPB_CURRENT = 0x000c , /* current CPB address */
ADMA_CPB_NEXT = 0x000c , /* next CPB address */
ADMA_CPB_LOOKUP = 0x0010 , /* CPB lookup table */
ADMA_FIFO_IN = 0x0014 , /* input FIFO threshold */
ADMA_FIFO_OUT = 0x0016 , /* output FIFO threshold */
/* ADMA_CONTROL register bits */
aNIEN = ( 1 < < 8 ) , /* irq mask: 1==masked */
aGO = ( 1 < < 7 ) , /* packet trigger ("Go!") */
aRSTADM = ( 1 < < 5 ) , /* ADMA logic reset */
aPIOMD4 = 0x0003 , /* PIO mode 4 */
/* ADMA_STATUS register bits */
aPSD = ( 1 < < 6 ) ,
aUIRQ = ( 1 < < 4 ) ,
aPERR = ( 1 < < 0 ) ,
/* CPB bits */
cDONE = ( 1 < < 0 ) ,
cVLD = ( 1 < < 0 ) ,
cDAT = ( 1 < < 2 ) ,
cIEN = ( 1 < < 3 ) ,
/* PRD bits */
pORD = ( 1 < < 4 ) ,
pDIRO = ( 1 < < 5 ) ,
pEND = ( 1 < < 7 ) ,
/* ATA register flags */
rIGN = ( 1 < < 5 ) ,
rEND = ( 1 < < 7 ) ,
/* ATA register addresses */
ADMA_REGS_CONTROL = 0x0e ,
ADMA_REGS_SECTOR_COUNT = 0x12 ,
ADMA_REGS_LBA_LOW = 0x13 ,
ADMA_REGS_LBA_MID = 0x14 ,
ADMA_REGS_LBA_HIGH = 0x15 ,
ADMA_REGS_DEVICE = 0x16 ,
ADMA_REGS_COMMAND = 0x17 ,
/* PCI device IDs */
board_1841_idx = 0 , /* ADMA 2-port controller */
} ;
typedef enum { adma_state_idle , adma_state_pkt , adma_state_mmio } adma_state_t ;
struct adma_port_priv {
u8 * pkt ;
dma_addr_t pkt_dma ;
adma_state_t state ;
} ;
static int adma_ata_init_one ( struct pci_dev * pdev ,
const struct pci_device_id * ent ) ;
static irqreturn_t adma_intr ( int irq , void * dev_instance ,
struct pt_regs * regs ) ;
static int adma_port_start ( struct ata_port * ap ) ;
2006-08-24 11:19:22 +04:00
static void adma_host_stop ( struct ata_host * host ) ;
2005-10-11 01:53:58 +04:00
static void adma_port_stop ( struct ata_port * ap ) ;
static void adma_phy_reset ( struct ata_port * ap ) ;
static void adma_qc_prep ( struct ata_queued_cmd * qc ) ;
2006-01-23 07:09:36 +03:00
static unsigned int adma_qc_issue ( struct ata_queued_cmd * qc ) ;
2005-10-11 01:53:58 +04:00
static int adma_check_atapi_dma ( struct ata_queued_cmd * qc ) ;
static void adma_bmdma_stop ( struct ata_queued_cmd * qc ) ;
static u8 adma_bmdma_status ( struct ata_port * ap ) ;
static void adma_irq_clear ( struct ata_port * ap ) ;
static void adma_eng_timeout ( struct ata_port * ap ) ;
2005-11-07 08:59:37 +03:00
static struct scsi_host_template adma_ata_sht = {
2005-10-11 01:53:58 +04:00
. module = THIS_MODULE ,
. name = DRV_NAME ,
. ioctl = ata_scsi_ioctl ,
. queuecommand = ata_scsi_queuecmd ,
. can_queue = ATA_DEF_QUEUE ,
. this_id = ATA_SHT_THIS_ID ,
. sg_tablesize = LIBATA_MAX_PRD ,
. cmd_per_lun = ATA_SHT_CMD_PER_LUN ,
. emulated = ATA_SHT_EMULATED ,
. use_clustering = ENABLE_CLUSTERING ,
. proc_name = DRV_NAME ,
. dma_boundary = ADMA_DMA_BOUNDARY ,
. slave_configure = ata_scsi_slave_config ,
2006-05-31 13:28:09 +04:00
. slave_destroy = ata_scsi_slave_destroy ,
2005-10-11 01:53:58 +04:00
. bios_param = ata_std_bios_param ,
} ;
2005-10-22 22:27:05 +04:00
static const struct ata_port_operations adma_ata_ops = {
2005-10-11 01:53:58 +04:00
. port_disable = ata_port_disable ,
. tf_load = ata_tf_load ,
. tf_read = ata_tf_read ,
. check_status = ata_check_status ,
. check_atapi_dma = adma_check_atapi_dma ,
. exec_command = ata_exec_command ,
. dev_select = ata_std_dev_select ,
. phy_reset = adma_phy_reset ,
. qc_prep = adma_qc_prep ,
. qc_issue = adma_qc_issue ,
. eng_timeout = adma_eng_timeout ,
2006-06-09 09:15:42 +04:00
. data_xfer = ata_mmio_data_xfer ,
2005-10-11 01:53:58 +04:00
. irq_handler = adma_intr ,
. irq_clear = adma_irq_clear ,
. port_start = adma_port_start ,
. port_stop = adma_port_stop ,
. host_stop = adma_host_stop ,
. bmdma_stop = adma_bmdma_stop ,
. bmdma_status = adma_bmdma_status ,
} ;
static struct ata_port_info adma_port_info [ ] = {
/* board_1841_idx */
{
. sht = & adma_ata_sht ,
2006-08-24 11:19:22 +04:00
. flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST |
2006-08-09 14:36:22 +04:00
ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO |
ATA_FLAG_PIO_POLLING ,
2005-10-11 01:53:58 +04:00
. pio_mask = 0x10 , /* pio4 */
. udma_mask = 0x1f , /* udma0-4 */
. port_ops = & adma_ata_ops ,
} ,
} ;
2005-11-10 19:04:11 +03:00
static const struct pci_device_id adma_ata_pci_tbl [ ] = {
2006-09-28 06:20:11 +04:00
{ PCI_VDEVICE ( PDC , 0x1841 ) , board_1841_idx } ,
2005-10-11 01:53:58 +04:00
{ } /* terminate list */
} ;
static struct pci_driver adma_ata_pci_driver = {
. name = DRV_NAME ,
. id_table = adma_ata_pci_tbl ,
. probe = adma_ata_init_one ,
. remove = ata_pci_remove_one ,
} ;
static int adma_check_atapi_dma ( struct ata_queued_cmd * qc )
{
return 1 ; /* ATAPI DMA not yet supported */
}
static void adma_bmdma_stop ( struct ata_queued_cmd * qc )
{
/* nothing */
}
static u8 adma_bmdma_status ( struct ata_port * ap )
{
return 0 ;
}
static void adma_irq_clear ( struct ata_port * ap )
{
/* nothing */
}
static void adma_reset_engine ( void __iomem * chan )
{
/* reset ADMA to idle state */
writew ( aPIOMD4 | aNIEN | aRSTADM , chan + ADMA_CONTROL ) ;
udelay ( 2 ) ;
writew ( aPIOMD4 , chan + ADMA_CONTROL ) ;
udelay ( 2 ) ;
}
static void adma_reinit_engine ( struct ata_port * ap )
{
struct adma_port_priv * pp = ap - > private_data ;
2006-08-24 11:19:22 +04:00
void __iomem * mmio_base = ap - > host - > mmio_base ;
2005-10-11 01:53:58 +04:00
void __iomem * chan = ADMA_REGS ( mmio_base , ap - > port_no ) ;
/* mask/clear ATA interrupts */
writeb ( ATA_NIEN , ( void __iomem * ) ap - > ioaddr . ctl_addr ) ;
ata_check_status ( ap ) ;
/* reset the ADMA engine */
adma_reset_engine ( chan ) ;
/* set in-FIFO threshold to 0x100 */
writew ( 0x100 , chan + ADMA_FIFO_IN ) ;
/* set CPB pointer */
writel ( ( u32 ) pp - > pkt_dma , chan + ADMA_CPB_NEXT ) ;
/* set out-FIFO threshold to 0x100 */
writew ( 0x100 , chan + ADMA_FIFO_OUT ) ;
/* set CPB count */
writew ( 1 , chan + ADMA_CPB_COUNT ) ;
/* read/discard ADMA status */
readb ( chan + ADMA_STATUS ) ;
}
static inline void adma_enter_reg_mode ( struct ata_port * ap )
{
2006-08-24 11:19:22 +04:00
void __iomem * chan = ADMA_REGS ( ap - > host - > mmio_base , ap - > port_no ) ;
2005-10-11 01:53:58 +04:00
writew ( aPIOMD4 , chan + ADMA_CONTROL ) ;
readb ( chan + ADMA_STATUS ) ; /* flush */
}
static void adma_phy_reset ( struct ata_port * ap )
{
struct adma_port_priv * pp = ap - > private_data ;
pp - > state = adma_state_idle ;
adma_reinit_engine ( ap ) ;
ata_port_probe ( ap ) ;
ata_bus_reset ( ap ) ;
}
static void adma_eng_timeout ( struct ata_port * ap )
{
struct adma_port_priv * pp = ap - > private_data ;
if ( pp - > state ! = adma_state_idle ) /* healthy paranoia */
pp - > state = adma_state_mmio ;
adma_reinit_engine ( ap ) ;
ata_eng_timeout ( ap ) ;
}
static int adma_fill_sg ( struct ata_queued_cmd * qc )
{
2005-10-19 06:14:54 +04:00
struct scatterlist * sg ;
2005-10-11 01:53:58 +04:00
struct ata_port * ap = qc - > ap ;
struct adma_port_priv * pp = ap - > private_data ;
u8 * buf = pp - > pkt ;
2005-10-19 06:14:54 +04:00
int i = ( 2 + buf [ 3 ] ) * 8 ;
2005-10-11 01:53:58 +04:00
u8 pFLAGS = pORD | ( ( qc - > tf . flags & ATA_TFLAG_WRITE ) ? pDIRO : 0 ) ;
2005-10-19 06:14:54 +04:00
ata_for_each_sg ( sg , qc ) {
2005-10-11 01:53:58 +04:00
u32 addr ;
u32 len ;
addr = ( u32 ) sg_dma_address ( sg ) ;
* ( __le32 * ) ( buf + i ) = cpu_to_le32 ( addr ) ;
i + = 4 ;
len = sg_dma_len ( sg ) > > 3 ;
* ( __le32 * ) ( buf + i ) = cpu_to_le32 ( len ) ;
i + = 4 ;
2005-10-19 06:14:54 +04:00
if ( ata_sg_is_last ( sg , qc ) )
2005-10-11 01:53:58 +04:00
pFLAGS | = pEND ;
buf [ i + + ] = pFLAGS ;
buf [ i + + ] = qc - > dev - > dma_mode & 0xf ;
buf [ i + + ] = 0 ; /* pPKLW */
buf [ i + + ] = 0 ; /* reserved */
* ( __le32 * ) ( buf + i )
= ( pFLAGS & pEND ) ? 0 : cpu_to_le32 ( pp - > pkt_dma + i + 4 ) ;
i + = 4 ;
2006-03-21 18:54:24 +03:00
VPRINTK ( " PRD[%u] = (0x%lX, 0x%X) \n " , i / 4 ,
2005-10-11 01:53:58 +04:00
( unsigned long ) addr , len ) ;
}
return i ;
}
static void adma_qc_prep ( struct ata_queued_cmd * qc )
{
struct adma_port_priv * pp = qc - > ap - > private_data ;
u8 * buf = pp - > pkt ;
u32 pkt_dma = ( u32 ) pp - > pkt_dma ;
int i = 0 ;
VPRINTK ( " ENTER \n " ) ;
adma_enter_reg_mode ( qc - > ap ) ;
if ( qc - > tf . protocol ! = ATA_PROT_DMA ) {
ata_qc_prep ( qc ) ;
return ;
}
buf [ i + + ] = 0 ; /* Response flags */
buf [ i + + ] = 0 ; /* reserved */
buf [ i + + ] = cVLD | cDAT | cIEN ;
i + + ; /* cLEN, gets filled in below */
* ( __le32 * ) ( buf + i ) = cpu_to_le32 ( pkt_dma ) ; /* cNCPB */
i + = 4 ; /* cNCPB */
i + = 4 ; /* cPRD, gets filled in below */
buf [ i + + ] = 0 ; /* reserved */
buf [ i + + ] = 0 ; /* reserved */
buf [ i + + ] = 0 ; /* reserved */
buf [ i + + ] = 0 ; /* reserved */
/* ATA registers; must be a multiple of 4 */
buf [ i + + ] = qc - > tf . device ;
buf [ i + + ] = ADMA_REGS_DEVICE ;
if ( ( qc - > tf . flags & ATA_TFLAG_LBA48 ) ) {
buf [ i + + ] = qc - > tf . hob_nsect ;
buf [ i + + ] = ADMA_REGS_SECTOR_COUNT ;
buf [ i + + ] = qc - > tf . hob_lbal ;
buf [ i + + ] = ADMA_REGS_LBA_LOW ;
buf [ i + + ] = qc - > tf . hob_lbam ;
buf [ i + + ] = ADMA_REGS_LBA_MID ;
buf [ i + + ] = qc - > tf . hob_lbah ;
buf [ i + + ] = ADMA_REGS_LBA_HIGH ;
}
buf [ i + + ] = qc - > tf . nsect ;
buf [ i + + ] = ADMA_REGS_SECTOR_COUNT ;
buf [ i + + ] = qc - > tf . lbal ;
buf [ i + + ] = ADMA_REGS_LBA_LOW ;
buf [ i + + ] = qc - > tf . lbam ;
buf [ i + + ] = ADMA_REGS_LBA_MID ;
buf [ i + + ] = qc - > tf . lbah ;
buf [ i + + ] = ADMA_REGS_LBA_HIGH ;
buf [ i + + ] = 0 ;
buf [ i + + ] = ADMA_REGS_CONTROL ;
buf [ i + + ] = rIGN ;
buf [ i + + ] = 0 ;
buf [ i + + ] = qc - > tf . command ;
buf [ i + + ] = ADMA_REGS_COMMAND | rEND ;
buf [ 3 ] = ( i > > 3 ) - 2 ; /* cLEN */
* ( __le32 * ) ( buf + 8 ) = cpu_to_le32 ( pkt_dma + i ) ; /* cPRD */
i = adma_fill_sg ( qc ) ;
wmb ( ) ; /* flush PRDs and pkt to memory */
#if 0
/* dump out CPB + PRDs for debug */
{
int j , len = 0 ;
static char obuf [ 2048 ] ;
for ( j = 0 ; j < i ; + + j ) {
len + = sprintf ( obuf + len , " %02x " , buf [ j ] ) ;
if ( ( j & 7 ) = = 7 ) {
printk ( " %s \n " , obuf ) ;
len = 0 ;
}
}
if ( len )
printk ( " %s \n " , obuf ) ;
}
# endif
}
static inline void adma_packet_start ( struct ata_queued_cmd * qc )
{
struct ata_port * ap = qc - > ap ;
2006-08-24 11:19:22 +04:00
void __iomem * chan = ADMA_REGS ( ap - > host - > mmio_base , ap - > port_no ) ;
2005-10-11 01:53:58 +04:00
VPRINTK ( " ENTER, ap %p \n " , ap ) ;
/* fire up the ADMA engine */
2005-10-11 09:44:14 +04:00
writew ( aPIOMD4 | aGO , chan + ADMA_CONTROL ) ;
2005-10-11 01:53:58 +04:00
}
2006-01-23 07:09:36 +03:00
static unsigned int adma_qc_issue ( struct ata_queued_cmd * qc )
2005-10-11 01:53:58 +04:00
{
struct adma_port_priv * pp = qc - > ap - > private_data ;
switch ( qc - > tf . protocol ) {
case ATA_PROT_DMA :
pp - > state = adma_state_pkt ;
adma_packet_start ( qc ) ;
return 0 ;
case ATA_PROT_ATAPI_DMA :
BUG ( ) ;
break ;
default :
break ;
}
pp - > state = adma_state_mmio ;
return ata_qc_issue_prot ( qc ) ;
}
2006-08-24 11:19:22 +04:00
static inline unsigned int adma_intr_pkt ( struct ata_host * host )
2005-10-11 01:53:58 +04:00
{
unsigned int handled = 0 , port_no ;
2006-08-24 11:19:22 +04:00
u8 __iomem * mmio_base = host - > mmio_base ;
2005-10-11 01:53:58 +04:00
2006-08-24 11:19:22 +04:00
for ( port_no = 0 ; port_no < host - > n_ports ; + + port_no ) {
struct ata_port * ap = host - > ports [ port_no ] ;
2005-10-11 01:53:58 +04:00
struct adma_port_priv * pp ;
struct ata_queued_cmd * qc ;
void __iomem * chan = ADMA_REGS ( mmio_base , port_no ) ;
2005-10-30 12:44:42 +03:00
u8 status = readb ( chan + ADMA_STATUS ) ;
2005-10-11 01:53:58 +04:00
if ( status = = 0 )
continue ;
handled = 1 ;
adma_enter_reg_mode ( ap ) ;
2006-04-02 18:30:40 +04:00
if ( ap - > flags & ATA_FLAG_DISABLED )
2005-10-11 01:53:58 +04:00
continue ;
pp = ap - > private_data ;
if ( ! pp | | pp - > state ! = adma_state_pkt )
continue ;
qc = ata_qc_from_tag ( ap , ap - > active_tag ) ;
2005-10-30 10:15:08 +03:00
if ( qc & & ( ! ( qc - > tf . flags & ATA_TFLAG_POLLING ) ) ) {
2005-10-28 23:43:16 +04:00
if ( ( status & ( aPERR | aPSD | aUIRQ ) ) )
2005-12-05 10:38:02 +03:00
qc - > err_mask | = AC_ERR_OTHER ;
2005-10-28 23:43:16 +04:00
else if ( pp - > pkt [ 0 ] ! = cDONE )
2005-12-05 10:38:02 +03:00
qc - > err_mask | = AC_ERR_OTHER ;
2005-10-30 12:44:42 +03:00
2005-12-05 10:38:02 +03:00
ata_qc_complete ( qc ) ;
2005-10-28 23:43:16 +04:00
}
2005-10-11 01:53:58 +04:00
}
return handled ;
}
2006-08-24 11:19:22 +04:00
static inline unsigned int adma_intr_mmio ( struct ata_host * host )
2005-10-11 01:53:58 +04:00
{
unsigned int handled = 0 , port_no ;
2006-08-24 11:19:22 +04:00
for ( port_no = 0 ; port_no < host - > n_ports ; + + port_no ) {
2005-10-11 01:53:58 +04:00
struct ata_port * ap ;
2006-08-24 11:19:22 +04:00
ap = host - > ports [ port_no ] ;
2006-04-02 18:30:40 +04:00
if ( ap & & ( ! ( ap - > flags & ATA_FLAG_DISABLED ) ) ) {
2005-10-11 01:53:58 +04:00
struct ata_queued_cmd * qc ;
struct adma_port_priv * pp = ap - > private_data ;
if ( ! pp | | pp - > state ! = adma_state_mmio )
continue ;
qc = ata_qc_from_tag ( ap , ap - > active_tag ) ;
2005-10-19 05:27:34 +04:00
if ( qc & & ( ! ( qc - > tf . flags & ATA_TFLAG_POLLING ) ) ) {
2005-10-11 01:53:58 +04:00
/* check main status, clearing INTRQ */
2005-10-29 21:58:21 +04:00
u8 status = ata_check_status ( ap ) ;
2005-10-11 01:53:58 +04:00
if ( ( status & ATA_BUSY ) )
continue ;
DPRINTK ( " ata%u: protocol %d (dev_stat 0x%X) \n " ,
ap - > id , qc - > tf . protocol , status ) ;
2006-08-31 08:02:15 +04:00
2005-10-11 01:53:58 +04:00
/* complete taskfile transaction */
pp - > state = adma_state_idle ;
2005-12-05 10:38:02 +03:00
qc - > err_mask | = ac_err_mask ( status ) ;
ata_qc_complete ( qc ) ;
2005-10-11 01:53:58 +04:00
handled = 1 ;
}
}
}
return handled ;
}
static irqreturn_t adma_intr ( int irq , void * dev_instance , struct pt_regs * regs )
{
2006-08-24 11:19:22 +04:00
struct ata_host * host = dev_instance ;
2005-10-11 01:53:58 +04:00
unsigned int handled = 0 ;
VPRINTK ( " ENTER \n " ) ;
2006-08-24 11:19:22 +04:00
spin_lock ( & host - > lock ) ;
handled = adma_intr_pkt ( host ) | adma_intr_mmio ( host ) ;
spin_unlock ( & host - > lock ) ;
2005-10-11 01:53:58 +04:00
VPRINTK ( " EXIT \n " ) ;
return IRQ_RETVAL ( handled ) ;
}
static void adma_ata_setup_port ( struct ata_ioports * port , unsigned long base )
{
port - > cmd_addr =
port - > data_addr = base + 0x000 ;
port - > error_addr =
port - > feature_addr = base + 0x004 ;
port - > nsect_addr = base + 0x008 ;
port - > lbal_addr = base + 0x00c ;
port - > lbam_addr = base + 0x010 ;
port - > lbah_addr = base + 0x014 ;
port - > device_addr = base + 0x018 ;
port - > status_addr =
port - > command_addr = base + 0x01c ;
port - > altstatus_addr =
port - > ctl_addr = base + 0x038 ;
}
static int adma_port_start ( struct ata_port * ap )
{
2006-08-24 11:19:22 +04:00
struct device * dev = ap - > host - > dev ;
2005-10-11 01:53:58 +04:00
struct adma_port_priv * pp ;
int rc ;
rc = ata_port_start ( ap ) ;
if ( rc )
return rc ;
adma_enter_reg_mode ( ap ) ;
rc = - ENOMEM ;
pp = kcalloc ( 1 , sizeof ( * pp ) , GFP_KERNEL ) ;
if ( ! pp )
goto err_out ;
pp - > pkt = dma_alloc_coherent ( dev , ADMA_PKT_BYTES , & pp - > pkt_dma ,
GFP_KERNEL ) ;
if ( ! pp - > pkt )
goto err_out_kfree ;
/* paranoia? */
if ( ( pp - > pkt_dma & 7 ) ! = 0 ) {
printk ( " bad alignment for pp->pkt_dma: %08x \n " ,
( u32 ) pp - > pkt_dma ) ;
2005-10-28 23:43:16 +04:00
dma_free_coherent ( dev , ADMA_PKT_BYTES ,
pp - > pkt , pp - > pkt_dma ) ;
goto err_out_kfree ;
2005-10-11 01:53:58 +04:00
}
memset ( pp - > pkt , 0 , ADMA_PKT_BYTES ) ;
ap - > private_data = pp ;
adma_reinit_engine ( ap ) ;
return 0 ;
err_out_kfree :
kfree ( pp ) ;
err_out :
ata_port_stop ( ap ) ;
return rc ;
}
static void adma_port_stop ( struct ata_port * ap )
{
2006-08-24 11:19:22 +04:00
struct device * dev = ap - > host - > dev ;
2005-10-11 01:53:58 +04:00
struct adma_port_priv * pp = ap - > private_data ;
2006-08-24 11:19:22 +04:00
adma_reset_engine ( ADMA_REGS ( ap - > host - > mmio_base , ap - > port_no ) ) ;
2005-10-11 01:53:58 +04:00
if ( pp ! = NULL ) {
ap - > private_data = NULL ;
if ( pp - > pkt ! = NULL )
dma_free_coherent ( dev , ADMA_PKT_BYTES ,
pp - > pkt , pp - > pkt_dma ) ;
kfree ( pp ) ;
}
ata_port_stop ( ap ) ;
}
2006-08-24 11:19:22 +04:00
static void adma_host_stop ( struct ata_host * host )
2005-10-11 01:53:58 +04:00
{
unsigned int port_no ;
for ( port_no = 0 ; port_no < ADMA_PORTS ; + + port_no )
2006-08-24 11:19:22 +04:00
adma_reset_engine ( ADMA_REGS ( host - > mmio_base , port_no ) ) ;
2005-10-11 01:53:58 +04:00
2006-08-24 11:19:22 +04:00
ata_pci_host_stop ( host ) ;
2005-10-11 01:53:58 +04:00
}
static void adma_host_init ( unsigned int chip_id ,
struct ata_probe_ent * probe_ent )
{
unsigned int port_no ;
void __iomem * mmio_base = probe_ent - > mmio_base ;
/* enable/lock aGO operation */
writeb ( 7 , mmio_base + ADMA_MODE_LOCK ) ;
/* reset the ADMA logic */
for ( port_no = 0 ; port_no < ADMA_PORTS ; + + port_no )
adma_reset_engine ( ADMA_REGS ( mmio_base , port_no ) ) ;
}
static int adma_set_dma_masks ( struct pci_dev * pdev , void __iomem * mmio_base )
{
int rc ;
rc = pci_set_dma_mask ( pdev , DMA_32BIT_MASK ) ;
if ( rc ) {
2005-10-30 22:39:11 +03:00
dev_printk ( KERN_ERR , & pdev - > dev ,
" 32-bit DMA enable failed \n " ) ;
2005-10-11 01:53:58 +04:00
return rc ;
}
rc = pci_set_consistent_dma_mask ( pdev , DMA_32BIT_MASK ) ;
if ( rc ) {
2005-10-30 22:39:11 +03:00
dev_printk ( KERN_ERR , & pdev - > dev ,
" 32-bit consistent DMA enable failed \n " ) ;
2005-10-11 01:53:58 +04:00
return rc ;
}
return 0 ;
}
static int adma_ata_init_one ( struct pci_dev * pdev ,
const struct pci_device_id * ent )
{
static int printed_version ;
struct ata_probe_ent * probe_ent = NULL ;
void __iomem * mmio_base ;
unsigned int board_idx = ( unsigned int ) ent - > driver_data ;
int rc , port_no ;
if ( ! printed_version + + )
2005-10-30 22:39:11 +03:00
dev_printk ( KERN_DEBUG , & pdev - > dev , " version " DRV_VERSION " \n " ) ;
2005-10-11 01:53:58 +04:00
rc = pci_enable_device ( pdev ) ;
if ( rc )
return rc ;
rc = pci_request_regions ( pdev , DRV_NAME ) ;
if ( rc )
goto err_out ;
if ( ( pci_resource_flags ( pdev , 4 ) & IORESOURCE_MEM ) = = 0 ) {
rc = - ENODEV ;
goto err_out_regions ;
}
mmio_base = pci_iomap ( pdev , 4 , 0 ) ;
if ( mmio_base = = NULL ) {
rc = - ENOMEM ;
goto err_out_regions ;
}
rc = adma_set_dma_masks ( pdev , mmio_base ) ;
if ( rc )
goto err_out_iounmap ;
probe_ent = kcalloc ( 1 , sizeof ( * probe_ent ) , GFP_KERNEL ) ;
if ( probe_ent = = NULL ) {
rc = - ENOMEM ;
goto err_out_iounmap ;
}
probe_ent - > dev = pci_dev_to_dev ( pdev ) ;
INIT_LIST_HEAD ( & probe_ent - > node ) ;
probe_ent - > sht = adma_port_info [ board_idx ] . sht ;
2006-08-24 11:19:22 +04:00
probe_ent - > port_flags = adma_port_info [ board_idx ] . flags ;
2005-10-11 01:53:58 +04:00
probe_ent - > pio_mask = adma_port_info [ board_idx ] . pio_mask ;
probe_ent - > mwdma_mask = adma_port_info [ board_idx ] . mwdma_mask ;
probe_ent - > udma_mask = adma_port_info [ board_idx ] . udma_mask ;
probe_ent - > port_ops = adma_port_info [ board_idx ] . port_ops ;
probe_ent - > irq = pdev - > irq ;
2006-07-02 06:29:42 +04:00
probe_ent - > irq_flags = IRQF_SHARED ;
2005-10-11 01:53:58 +04:00
probe_ent - > mmio_base = mmio_base ;
probe_ent - > n_ports = ADMA_PORTS ;
for ( port_no = 0 ; port_no < probe_ent - > n_ports ; + + port_no ) {
adma_ata_setup_port ( & probe_ent - > port [ port_no ] ,
ADMA_ATA_REGS ( ( unsigned long ) mmio_base , port_no ) ) ;
}
pci_set_master ( pdev ) ;
/* initialize adapter */
adma_host_init ( board_idx , probe_ent ) ;
rc = ata_device_add ( probe_ent ) ;
kfree ( probe_ent ) ;
if ( rc ! = ADMA_PORTS )
goto err_out_iounmap ;
return 0 ;
err_out_iounmap :
pci_iounmap ( pdev , mmio_base ) ;
err_out_regions :
pci_release_regions ( pdev ) ;
err_out :
pci_disable_device ( pdev ) ;
return rc ;
}
static int __init adma_ata_init ( void )
{
2006-08-10 13:13:18 +04:00
return pci_register_driver ( & adma_ata_pci_driver ) ;
2005-10-11 01:53:58 +04:00
}
static void __exit adma_ata_exit ( void )
{
pci_unregister_driver ( & adma_ata_pci_driver ) ;
}
MODULE_AUTHOR ( " Mark Lord " ) ;
MODULE_DESCRIPTION ( " Pacific Digital Corporation ADMA low-level driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_DEVICE_TABLE ( pci , adma_ata_pci_tbl ) ;
MODULE_VERSION ( DRV_VERSION ) ;
module_init ( adma_ata_init ) ;
module_exit ( adma_ata_exit ) ;