mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-24 07:40:53 +07:00
Merge master.kernel.org:/pub/scm/linux/kernel/git/bart/ide-2.6
* master.kernel.org:/pub/scm/linux/kernel/git/bart/ide-2.6: (23 commits) ide-acpi support warning fix ACPI support for IDE devices IDE Driver for Delkin/Lexar/etc.. cardbus CF adapter ide: it8213 IDE driver update (version 2) ide: add it8213 IDE driver tc86c001: add missing __init tag for tc86c001_ide_init() tc86c001: mark init_chipset_tc86c001() with __devinit tag tc86c001: init_hwif_tc86c001() can be static ide: add Toshiba TC86C001 IDE driver (take 2) pdc202xx_new: remove check_in_drive_lists abomination pdc202xx_new: remove useless code slc90e66: carry over fixes from piix driver piix: tuneproc() fixes/cleanups piix: fix 82371MX enablebits hpt366: HPT36x PCI clock detection fix hpt366: init code rewrite hpt366: clean up DMA timeout handling for HPT370 hpt366: merge HPT37x speedproc handlers hpt366: cache channel's MCR address hpt366: switch to using pci_get_slot ...
This commit is contained in:
commit
905adce409
@ -167,6 +167,13 @@ config BLK_DEV_IDECS
|
||||
Support for Compact Flash cards, outboard IDE disks, tape drives,
|
||||
and CD-ROM drives connected through a PCMCIA card.
|
||||
|
||||
config BLK_DEV_DELKIN
|
||||
tristate "Cardbus IDE support (Delkin/ASKA/Workbit)"
|
||||
depends on CARDBUS && PCI
|
||||
help
|
||||
Support for Delkin, ASKA, and Workbit Cardbus CompactFlash
|
||||
Adapters. This may also work for similar SD and XD adapters.
|
||||
|
||||
config BLK_DEV_IDECD
|
||||
tristate "Include IDE/ATAPI CDROM support"
|
||||
---help---
|
||||
@ -264,6 +271,13 @@ config BLK_DEV_IDESCSI
|
||||
If both this SCSI emulation and native ATAPI support are compiled
|
||||
into the kernel, the native support will be used.
|
||||
|
||||
config BLK_DEV_IDEACPI
|
||||
bool "IDE ACPI support"
|
||||
depends on ACPI
|
||||
---help---
|
||||
Implement ACPI support for generic IDE devices. On modern
|
||||
machines ACPI support is required to properly handle ACPI S3 states.
|
||||
|
||||
config IDE_TASK_IOCTL
|
||||
bool "IDE Taskfile Access"
|
||||
help
|
||||
@ -606,6 +620,11 @@ config BLK_DEV_PIIX
|
||||
the kernel to change PIO, DMA and UDMA speeds and to configure
|
||||
the chip to optimum performance.
|
||||
|
||||
config BLK_DEV_IT8213
|
||||
tristate "IT8213 IDE support"
|
||||
help
|
||||
This driver adds support for the ITE 8213 IDE controller.
|
||||
|
||||
config BLK_DEV_IT821X
|
||||
tristate "IT821X IDE support"
|
||||
help
|
||||
@ -742,6 +761,11 @@ config BLK_DEV_VIA82CXXX
|
||||
This allows the kernel to change PIO, DMA and UDMA speeds and to
|
||||
configure the chip to optimum performance.
|
||||
|
||||
config BLK_DEV_TC86C001
|
||||
tristate "Toshiba TC86C001 support"
|
||||
help
|
||||
This driver adds support for Toshiba TC86C001 GOKU-S chip.
|
||||
|
||||
endif
|
||||
|
||||
config BLK_DEV_IDE_PMAC
|
||||
|
@ -22,6 +22,7 @@ ide-core-$(CONFIG_BLK_DEV_IDEPCI) += setup-pci.o
|
||||
ide-core-$(CONFIG_BLK_DEV_IDEDMA) += ide-dma.o
|
||||
ide-core-$(CONFIG_PROC_FS) += ide-proc.o
|
||||
ide-core-$(CONFIG_BLK_DEV_IDEPNP) += ide-pnp.o
|
||||
ide-core-$(CONFIG_BLK_DEV_IDEACPI) += ide-acpi.o
|
||||
|
||||
# built-in only drivers from arm/
|
||||
ide-core-$(CONFIG_IDE_ARM) += arm/ide_arm.o
|
||||
|
697
drivers/ide/ide-acpi.c
Normal file
697
drivers/ide/ide-acpi.c
Normal file
@ -0,0 +1,697 @@
|
||||
/*
|
||||
* ide-acpi.c
|
||||
* Provides ACPI support for IDE drives.
|
||||
*
|
||||
* Copyright (C) 2005 Intel Corp.
|
||||
* Copyright (C) 2005 Randy Dunlap
|
||||
* Copyright (C) 2006 SUSE Linux Products GmbH
|
||||
* Copyright (C) 2006 Hannes Reinecke
|
||||
*/
|
||||
|
||||
#include <linux/ata.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <acpi/acpi.h>
|
||||
#include <linux/ide.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include <acpi/acpi_bus.h>
|
||||
#include <acpi/acnames.h>
|
||||
#include <acpi/acnamesp.h>
|
||||
#include <acpi/acparser.h>
|
||||
#include <acpi/acexcep.h>
|
||||
#include <acpi/acmacros.h>
|
||||
#include <acpi/actypes.h>
|
||||
|
||||
#define REGS_PER_GTF 7
|
||||
struct taskfile_array {
|
||||
u8 tfa[REGS_PER_GTF]; /* regs. 0x1f1 - 0x1f7 */
|
||||
};
|
||||
|
||||
struct GTM_buffer {
|
||||
u32 PIO_speed0;
|
||||
u32 DMA_speed0;
|
||||
u32 PIO_speed1;
|
||||
u32 DMA_speed1;
|
||||
u32 GTM_flags;
|
||||
};
|
||||
|
||||
struct ide_acpi_drive_link {
|
||||
ide_drive_t *drive;
|
||||
acpi_handle obj_handle;
|
||||
u8 idbuff[512];
|
||||
};
|
||||
|
||||
struct ide_acpi_hwif_link {
|
||||
ide_hwif_t *hwif;
|
||||
acpi_handle obj_handle;
|
||||
struct GTM_buffer gtm;
|
||||
struct ide_acpi_drive_link master;
|
||||
struct ide_acpi_drive_link slave;
|
||||
};
|
||||
|
||||
#undef DEBUGGING
|
||||
/* note: adds function name and KERN_DEBUG */
|
||||
#ifdef DEBUGGING
|
||||
#define DEBPRINT(fmt, args...) \
|
||||
printk(KERN_DEBUG "%s: " fmt, __FUNCTION__, ## args)
|
||||
#else
|
||||
#define DEBPRINT(fmt, args...) do {} while (0)
|
||||
#endif /* DEBUGGING */
|
||||
|
||||
extern int ide_noacpi;
|
||||
extern int ide_noacpitfs;
|
||||
extern int ide_noacpionboot;
|
||||
|
||||
/**
|
||||
* ide_get_dev_handle - finds acpi_handle and PCI device.function
|
||||
* @dev: device to locate
|
||||
* @handle: returned acpi_handle for @dev
|
||||
* @pcidevfn: return PCI device.func for @dev
|
||||
*
|
||||
* Returns the ACPI object handle to the corresponding PCI device.
|
||||
*
|
||||
* Returns 0 on success, <0 on error.
|
||||
*/
|
||||
static int ide_get_dev_handle(struct device *dev, acpi_handle *handle,
|
||||
acpi_integer *pcidevfn)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
unsigned int bus, devnum, func;
|
||||
acpi_integer addr;
|
||||
acpi_handle dev_handle;
|
||||
struct acpi_buffer buffer = {.length = ACPI_ALLOCATE_BUFFER,
|
||||
.pointer = NULL};
|
||||
acpi_status status;
|
||||
struct acpi_device_info *dinfo = NULL;
|
||||
int ret = -ENODEV;
|
||||
|
||||
bus = pdev->bus->number;
|
||||
devnum = PCI_SLOT(pdev->devfn);
|
||||
func = PCI_FUNC(pdev->devfn);
|
||||
/* ACPI _ADR encoding for PCI bus: */
|
||||
addr = (acpi_integer)(devnum << 16 | func);
|
||||
|
||||
DEBPRINT("ENTER: pci %02x:%02x.%01x\n", bus, devnum, func);
|
||||
|
||||
dev_handle = DEVICE_ACPI_HANDLE(dev);
|
||||
if (!dev_handle) {
|
||||
DEBPRINT("no acpi handle for device\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
status = acpi_get_object_info(dev_handle, &buffer);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
DEBPRINT("get_object_info for device failed\n");
|
||||
goto err;
|
||||
}
|
||||
dinfo = buffer.pointer;
|
||||
if (dinfo && (dinfo->valid & ACPI_VALID_ADR) &&
|
||||
dinfo->address == addr) {
|
||||
*pcidevfn = addr;
|
||||
*handle = dev_handle;
|
||||
} else {
|
||||
DEBPRINT("get_object_info for device has wrong "
|
||||
" address: %llu, should be %u\n",
|
||||
dinfo ? (unsigned long long)dinfo->address : -1ULL,
|
||||
(unsigned int)addr);
|
||||
goto err;
|
||||
}
|
||||
|
||||
DEBPRINT("for dev=0x%x.%x, addr=0x%llx, *handle=0x%p\n",
|
||||
devnum, func, (unsigned long long)addr, *handle);
|
||||
ret = 0;
|
||||
err:
|
||||
kfree(dinfo);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ide_acpi_hwif_get_handle - Get ACPI object handle for a given hwif
|
||||
* @hwif: device to locate
|
||||
*
|
||||
* Retrieves the object handle for a given hwif.
|
||||
*
|
||||
* Returns handle on success, 0 on error.
|
||||
*/
|
||||
static acpi_handle ide_acpi_hwif_get_handle(ide_hwif_t *hwif)
|
||||
{
|
||||
struct device *dev = hwif->gendev.parent;
|
||||
acpi_handle dev_handle;
|
||||
acpi_integer pcidevfn;
|
||||
acpi_handle chan_handle;
|
||||
int err;
|
||||
|
||||
DEBPRINT("ENTER: device %s\n", hwif->name);
|
||||
|
||||
if (!dev) {
|
||||
DEBPRINT("no PCI device for %s\n", hwif->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
err = ide_get_dev_handle(dev, &dev_handle, &pcidevfn);
|
||||
if (err < 0) {
|
||||
DEBPRINT("ide_get_dev_handle failed (%d)\n", err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* get child objects of dev_handle == channel objects,
|
||||
* + _their_ children == drive objects */
|
||||
/* channel is hwif->channel */
|
||||
chan_handle = acpi_get_child(dev_handle, hwif->channel);
|
||||
DEBPRINT("chan adr=%d: handle=0x%p\n",
|
||||
hwif->channel, chan_handle);
|
||||
|
||||
return chan_handle;
|
||||
}
|
||||
|
||||
/**
|
||||
* ide_acpi_drive_get_handle - Get ACPI object handle for a given drive
|
||||
* @drive: device to locate
|
||||
*
|
||||
* Retrieves the object handle of a given drive. According to the ACPI
|
||||
* spec the drive is a child of the hwif.
|
||||
*
|
||||
* Returns handle on success, 0 on error.
|
||||
*/
|
||||
static acpi_handle ide_acpi_drive_get_handle(ide_drive_t *drive)
|
||||
{
|
||||
ide_hwif_t *hwif = HWIF(drive);
|
||||
int port;
|
||||
acpi_handle drive_handle;
|
||||
|
||||
if (!hwif->acpidata)
|
||||
return NULL;
|
||||
|
||||
if (!hwif->acpidata->obj_handle)
|
||||
return NULL;
|
||||
|
||||
port = hwif->channel ? drive->dn - 2: drive->dn;
|
||||
|
||||
DEBPRINT("ENTER: %s at channel#: %d port#: %d\n",
|
||||
drive->name, hwif->channel, port);
|
||||
|
||||
|
||||
/* TBD: could also check ACPI object VALID bits */
|
||||
drive_handle = acpi_get_child(hwif->acpidata->obj_handle, port);
|
||||
DEBPRINT("drive %s handle 0x%p\n", drive->name, drive_handle);
|
||||
|
||||
return drive_handle;
|
||||
}
|
||||
|
||||
/**
|
||||
* do_drive_get_GTF - get the drive bootup default taskfile settings
|
||||
* @drive: the drive for which the taskfile settings should be retrieved
|
||||
* @gtf_length: number of bytes of _GTF data returned at @gtf_address
|
||||
* @gtf_address: buffer containing _GTF taskfile arrays
|
||||
*
|
||||
* The _GTF method has no input parameters.
|
||||
* It returns a variable number of register set values (registers
|
||||
* hex 1F1..1F7, taskfiles).
|
||||
* The <variable number> is not known in advance, so have ACPI-CA
|
||||
* allocate the buffer as needed and return it, then free it later.
|
||||
*
|
||||
* The returned @gtf_length and @gtf_address are only valid if the
|
||||
* function return value is 0.
|
||||
*/
|
||||
static int do_drive_get_GTF(ide_drive_t *drive,
|
||||
unsigned int *gtf_length, unsigned long *gtf_address,
|
||||
unsigned long *obj_loc)
|
||||
{
|
||||
acpi_status status;
|
||||
struct acpi_buffer output;
|
||||
union acpi_object *out_obj;
|
||||
ide_hwif_t *hwif = HWIF(drive);
|
||||
struct device *dev = hwif->gendev.parent;
|
||||
int err = -ENODEV;
|
||||
int port;
|
||||
|
||||
*gtf_length = 0;
|
||||
*gtf_address = 0UL;
|
||||
*obj_loc = 0UL;
|
||||
|
||||
if (ide_noacpi)
|
||||
return 0;
|
||||
|
||||
if (!dev) {
|
||||
DEBPRINT("no PCI device for %s\n", hwif->name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!hwif->acpidata) {
|
||||
DEBPRINT("no ACPI data for %s\n", hwif->name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
port = hwif->channel ? drive->dn - 2: drive->dn;
|
||||
|
||||
if (!drive->acpidata) {
|
||||
if (port == 0) {
|
||||
drive->acpidata = &hwif->acpidata->master;
|
||||
hwif->acpidata->master.drive = drive;
|
||||
} else {
|
||||
drive->acpidata = &hwif->acpidata->slave;
|
||||
hwif->acpidata->slave.drive = drive;
|
||||
}
|
||||
}
|
||||
|
||||
DEBPRINT("ENTER: %s at %s, port#: %d, hard_port#: %d\n",
|
||||
hwif->name, dev->bus_id, port, hwif->channel);
|
||||
|
||||
if (!drive->present) {
|
||||
DEBPRINT("%s drive %d:%d not present\n",
|
||||
hwif->name, hwif->channel, port);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Get this drive's _ADR info. if not already known. */
|
||||
if (!drive->acpidata->obj_handle) {
|
||||
drive->acpidata->obj_handle = ide_acpi_drive_get_handle(drive);
|
||||
if (!drive->acpidata->obj_handle) {
|
||||
DEBPRINT("No ACPI object found for %s\n",
|
||||
drive->name);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Setting up output buffer */
|
||||
output.length = ACPI_ALLOCATE_BUFFER;
|
||||
output.pointer = NULL; /* ACPI-CA sets this; save/free it later */
|
||||
|
||||
/* _GTF has no input parameters */
|
||||
err = -EIO;
|
||||
status = acpi_evaluate_object(drive->acpidata->obj_handle, "_GTF",
|
||||
NULL, &output);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
printk(KERN_DEBUG
|
||||
"%s: Run _GTF error: status = 0x%x\n",
|
||||
__FUNCTION__, status);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!output.length || !output.pointer) {
|
||||
DEBPRINT("Run _GTF: "
|
||||
"length or ptr is NULL (0x%llx, 0x%p)\n",
|
||||
(unsigned long long)output.length,
|
||||
output.pointer);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out_obj = output.pointer;
|
||||
if (out_obj->type != ACPI_TYPE_BUFFER) {
|
||||
DEBPRINT("Run _GTF: error: "
|
||||
"expected object type of ACPI_TYPE_BUFFER, "
|
||||
"got 0x%x\n", out_obj->type);
|
||||
err = -ENOENT;
|
||||
kfree(output.pointer);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!out_obj->buffer.length || !out_obj->buffer.pointer ||
|
||||
out_obj->buffer.length % REGS_PER_GTF) {
|
||||
printk(KERN_ERR
|
||||
"%s: unexpected GTF length (%d) or addr (0x%p)\n",
|
||||
__FUNCTION__, out_obj->buffer.length,
|
||||
out_obj->buffer.pointer);
|
||||
err = -ENOENT;
|
||||
kfree(output.pointer);
|
||||
goto out;
|
||||
}
|
||||
|
||||
*gtf_length = out_obj->buffer.length;
|
||||
*gtf_address = (unsigned long)out_obj->buffer.pointer;
|
||||
*obj_loc = (unsigned long)out_obj;
|
||||
DEBPRINT("returning gtf_length=%d, gtf_address=0x%lx, obj_loc=0x%lx\n",
|
||||
*gtf_length, *gtf_address, *obj_loc);
|
||||
err = 0;
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* taskfile_load_raw - send taskfile registers to drive
|
||||
* @drive: drive to which output is sent
|
||||
* @gtf: raw ATA taskfile register set (0x1f1 - 0x1f7)
|
||||
*
|
||||
* Outputs IDE taskfile to the drive.
|
||||
*/
|
||||
static int taskfile_load_raw(ide_drive_t *drive,
|
||||
const struct taskfile_array *gtf)
|
||||
{
|
||||
ide_task_t args;
|
||||
int err = 0;
|
||||
|
||||
DEBPRINT("(0x1f1-1f7): hex: "
|
||||
"%02x %02x %02x %02x %02x %02x %02x\n",
|
||||
gtf->tfa[0], gtf->tfa[1], gtf->tfa[2],
|
||||
gtf->tfa[3], gtf->tfa[4], gtf->tfa[5], gtf->tfa[6]);
|
||||
|
||||
memset(&args, 0, sizeof(ide_task_t));
|
||||
args.command_type = IDE_DRIVE_TASK_NO_DATA;
|
||||
args.data_phase = TASKFILE_IN;
|
||||
args.handler = &task_no_data_intr;
|
||||
|
||||
/* convert gtf to IDE Taskfile */
|
||||
args.tfRegister[1] = gtf->tfa[0]; /* 0x1f1 */
|
||||
args.tfRegister[2] = gtf->tfa[1]; /* 0x1f2 */
|
||||
args.tfRegister[3] = gtf->tfa[2]; /* 0x1f3 */
|
||||
args.tfRegister[4] = gtf->tfa[3]; /* 0x1f4 */
|
||||
args.tfRegister[5] = gtf->tfa[4]; /* 0x1f5 */
|
||||
args.tfRegister[6] = gtf->tfa[5]; /* 0x1f6 */
|
||||
args.tfRegister[7] = gtf->tfa[6]; /* 0x1f7 */
|
||||
|
||||
if (ide_noacpitfs) {
|
||||
DEBPRINT("_GTF execution disabled\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = ide_raw_taskfile(drive, &args, NULL);
|
||||
if (err)
|
||||
printk(KERN_ERR "%s: ide_raw_taskfile failed: %u\n",
|
||||
__FUNCTION__, err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* do_drive_set_taskfiles - write the drive taskfile settings from _GTF
|
||||
* @drive: the drive to which the taskfile command should be sent
|
||||
* @gtf_length: total number of bytes of _GTF taskfiles
|
||||
* @gtf_address: location of _GTF taskfile arrays
|
||||
*
|
||||
* Write {gtf_address, length gtf_length} in groups of
|
||||
* REGS_PER_GTF bytes.
|
||||
*/
|
||||
static int do_drive_set_taskfiles(ide_drive_t *drive,
|
||||
unsigned int gtf_length,
|
||||
unsigned long gtf_address)
|
||||
{
|
||||
int rc = -ENODEV, err;
|
||||
int gtf_count = gtf_length / REGS_PER_GTF;
|
||||
int ix;
|
||||
struct taskfile_array *gtf;
|
||||
|
||||
if (ide_noacpi)
|
||||
return 0;
|
||||
|
||||
DEBPRINT("ENTER: %s, hard_port#: %d\n", drive->name, drive->dn);
|
||||
|
||||
if (!drive->present)
|
||||
goto out;
|
||||
if (!gtf_count) /* shouldn't be here */
|
||||
goto out;
|
||||
|
||||
DEBPRINT("total GTF bytes=%u (0x%x), gtf_count=%d, addr=0x%lx\n",
|
||||
gtf_length, gtf_length, gtf_count, gtf_address);
|
||||
|
||||
if (gtf_length % REGS_PER_GTF) {
|
||||
printk(KERN_ERR "%s: unexpected GTF length (%d)\n",
|
||||
__FUNCTION__, gtf_length);
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
for (ix = 0; ix < gtf_count; ix++) {
|
||||
gtf = (struct taskfile_array *)
|
||||
(gtf_address + ix * REGS_PER_GTF);
|
||||
|
||||
/* send all TaskFile registers (0x1f1-0x1f7) *in*that*order* */
|
||||
err = taskfile_load_raw(drive, gtf);
|
||||
if (err)
|
||||
rc = err;
|
||||
}
|
||||
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* ide_acpi_exec_tfs - get then write drive taskfile settings
|
||||
* @drive: the drive for which the taskfile settings should be
|
||||
* written.
|
||||
*
|
||||
* According to the ACPI spec this should be called after _STM
|
||||
* has been evaluated for the interface. Some ACPI vendors interpret
|
||||
* that as a hard requirement and modify the taskfile according
|
||||
* to the Identify Drive information passed down with _STM.
|
||||
* So one should really make sure to call this only after _STM has
|
||||
* been executed.
|
||||
*/
|
||||
int ide_acpi_exec_tfs(ide_drive_t *drive)
|
||||
{
|
||||
int ret;
|
||||
unsigned int gtf_length;
|
||||
unsigned long gtf_address;
|
||||
unsigned long obj_loc;
|
||||
|
||||
if (ide_noacpi)
|
||||
return 0;
|
||||
|
||||
DEBPRINT("call get_GTF, drive=%s port=%d\n", drive->name, drive->dn);
|
||||
|
||||
ret = do_drive_get_GTF(drive, >f_length, >f_address, &obj_loc);
|
||||
if (ret < 0) {
|
||||
DEBPRINT("get_GTF error (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
DEBPRINT("call set_taskfiles, drive=%s\n", drive->name);
|
||||
|
||||
ret = do_drive_set_taskfiles(drive, gtf_length, gtf_address);
|
||||
kfree((void *)obj_loc);
|
||||
if (ret < 0) {
|
||||
DEBPRINT("set_taskfiles error (%d)\n", ret);
|
||||
}
|
||||
|
||||
DEBPRINT("ret=%d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ide_acpi_exec_tfs);
|
||||
|
||||
/**
|
||||
* ide_acpi_get_timing - get the channel (controller) timings
|
||||
* @hwif: target IDE interface (channel)
|
||||
*
|
||||
* This function executes the _GTM ACPI method for the target channel.
|
||||
*
|
||||
*/
|
||||
void ide_acpi_get_timing(ide_hwif_t *hwif)
|
||||
{
|
||||
acpi_status status;
|
||||
struct acpi_buffer output;
|
||||
union acpi_object *out_obj;
|
||||
|
||||
if (ide_noacpi)
|
||||
return;
|
||||
|
||||
DEBPRINT("ENTER:\n");
|
||||
|
||||
if (!hwif->acpidata) {
|
||||
DEBPRINT("no ACPI data for %s\n", hwif->name);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Setting up output buffer for _GTM */
|
||||
output.length = ACPI_ALLOCATE_BUFFER;
|
||||
output.pointer = NULL; /* ACPI-CA sets this; save/free it later */
|
||||
|
||||
/* _GTM has no input parameters */
|
||||
status = acpi_evaluate_object(hwif->acpidata->obj_handle, "_GTM",
|
||||
NULL, &output);
|
||||
|
||||
DEBPRINT("_GTM status: %d, outptr: 0x%p, outlen: 0x%llx\n",
|
||||
status, output.pointer,
|
||||
(unsigned long long)output.length);
|
||||
|
||||
if (ACPI_FAILURE(status)) {
|
||||
DEBPRINT("Run _GTM error: status = 0x%x\n", status);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!output.length || !output.pointer) {
|
||||
DEBPRINT("Run _GTM: length or ptr is NULL (0x%llx, 0x%p)\n",
|
||||
(unsigned long long)output.length,
|
||||
output.pointer);
|
||||
kfree(output.pointer);
|
||||
return;
|
||||
}
|
||||
|
||||
out_obj = output.pointer;
|
||||
if (out_obj->type != ACPI_TYPE_BUFFER) {
|
||||
kfree(output.pointer);
|
||||
DEBPRINT("Run _GTM: error: "
|
||||
"expected object type of ACPI_TYPE_BUFFER, "
|
||||
"got 0x%x\n", out_obj->type);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!out_obj->buffer.length || !out_obj->buffer.pointer ||
|
||||
out_obj->buffer.length != sizeof(struct GTM_buffer)) {
|
||||
kfree(output.pointer);
|
||||
printk(KERN_ERR
|
||||
"%s: unexpected _GTM length (0x%x)[should be 0x%zx] or "
|
||||
"addr (0x%p)\n",
|
||||
__FUNCTION__, out_obj->buffer.length,
|
||||
sizeof(struct GTM_buffer), out_obj->buffer.pointer);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&hwif->acpidata->gtm, out_obj->buffer.pointer,
|
||||
sizeof(struct GTM_buffer));
|
||||
|
||||
DEBPRINT("_GTM info: ptr: 0x%p, len: 0x%x, exp.len: 0x%Zx\n",
|
||||
out_obj->buffer.pointer, out_obj->buffer.length,
|
||||
sizeof(struct GTM_buffer));
|
||||
|
||||
DEBPRINT("_GTM fields: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n",
|
||||
hwif->acpidata->gtm.PIO_speed0,
|
||||
hwif->acpidata->gtm.DMA_speed0,
|
||||
hwif->acpidata->gtm.PIO_speed1,
|
||||
hwif->acpidata->gtm.DMA_speed1,
|
||||
hwif->acpidata->gtm.GTM_flags);
|
||||
|
||||
kfree(output.pointer);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ide_acpi_get_timing);
|
||||
|
||||
/**
|
||||
* ide_acpi_push_timing - set the channel (controller) timings
|
||||
* @hwif: target IDE interface (channel)
|
||||
*
|
||||
* This function executes the _STM ACPI method for the target channel.
|
||||
*
|
||||
* _STM requires Identify Drive data, which has to passed as an argument.
|
||||
* Unfortunately hd_driveid is a mangled version which we can't readily
|
||||
* use; hence we'll get the information afresh.
|
||||
*/
|
||||
void ide_acpi_push_timing(ide_hwif_t *hwif)
|
||||
{
|
||||
acpi_status status;
|
||||
struct acpi_object_list input;
|
||||
union acpi_object in_params[3];
|
||||
struct ide_acpi_drive_link *master = &hwif->acpidata->master;
|
||||
struct ide_acpi_drive_link *slave = &hwif->acpidata->slave;
|
||||
|
||||
if (ide_noacpi)
|
||||
return;
|
||||
|
||||
DEBPRINT("ENTER:\n");
|
||||
|
||||
if (!hwif->acpidata) {
|
||||
DEBPRINT("no ACPI data for %s\n", hwif->name);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Give the GTM buffer + drive Identify data to the channel via the
|
||||
* _STM method: */
|
||||
/* setup input parameters buffer for _STM */
|
||||
input.count = 3;
|
||||
input.pointer = in_params;
|
||||
in_params[0].type = ACPI_TYPE_BUFFER;
|
||||
in_params[0].buffer.length = sizeof(struct GTM_buffer);
|
||||
in_params[0].buffer.pointer = (u8 *)&hwif->acpidata->gtm;
|
||||
in_params[1].type = ACPI_TYPE_BUFFER;
|
||||
in_params[1].buffer.length = sizeof(struct hd_driveid);
|
||||
in_params[1].buffer.pointer = (u8 *)&master->idbuff;
|
||||
in_params[2].type = ACPI_TYPE_BUFFER;
|
||||
in_params[2].buffer.length = sizeof(struct hd_driveid);
|
||||
in_params[2].buffer.pointer = (u8 *)&slave->idbuff;
|
||||
/* Output buffer: _STM has no output */
|
||||
|
||||
status = acpi_evaluate_object(hwif->acpidata->obj_handle, "_STM",
|
||||
&input, NULL);
|
||||
|
||||
if (ACPI_FAILURE(status)) {
|
||||
DEBPRINT("Run _STM error: status = 0x%x\n", status);
|
||||
}
|
||||
DEBPRINT("_STM status: %d\n", status);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ide_acpi_push_timing);
|
||||
|
||||
/**
|
||||
* ide_acpi_init - initialize the ACPI link for an IDE interface
|
||||
* @hwif: target IDE interface (channel)
|
||||
*
|
||||
* The ACPI spec is not quite clear when the drive identify buffer
|
||||
* should be obtained. Calling IDENTIFY DEVICE during shutdown
|
||||
* is not the best of ideas as the drive might already being put to
|
||||
* sleep. And obviously we can't call it during resume.
|
||||
* So we get the information during startup; but this means that
|
||||
* any changes during run-time will be lost after resume.
|
||||
*/
|
||||
void ide_acpi_init(ide_hwif_t *hwif)
|
||||
{
|
||||
int unit;
|
||||
int err;
|
||||
struct ide_acpi_drive_link *master;
|
||||
struct ide_acpi_drive_link *slave;
|
||||
|
||||
hwif->acpidata = kzalloc(sizeof(struct ide_acpi_hwif_link), GFP_KERNEL);
|
||||
if (!hwif->acpidata)
|
||||
return;
|
||||
|
||||
hwif->acpidata->obj_handle = ide_acpi_hwif_get_handle(hwif);
|
||||
if (!hwif->acpidata->obj_handle) {
|
||||
DEBPRINT("no ACPI object for %s found\n", hwif->name);
|
||||
kfree(hwif->acpidata);
|
||||
hwif->acpidata = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* The ACPI spec mandates that we send information
|
||||
* for both drives, regardless whether they are connected
|
||||
* or not.
|
||||
*/
|
||||
hwif->acpidata->master.drive = &hwif->drives[0];
|
||||
hwif->drives[0].acpidata = &hwif->acpidata->master;
|
||||
master = &hwif->acpidata->master;
|
||||
|
||||
hwif->acpidata->slave.drive = &hwif->drives[1];
|
||||
hwif->drives[1].acpidata = &hwif->acpidata->slave;
|
||||
slave = &hwif->acpidata->slave;
|
||||
|
||||
|
||||
/*
|
||||
* Send IDENTIFY for each drive
|
||||
*/
|
||||
if (master->drive->present) {
|
||||
err = taskfile_lib_get_identify(master->drive, master->idbuff);
|
||||
if (err) {
|
||||
DEBPRINT("identify device %s failed (%d)\n",
|
||||
master->drive->name, err);
|
||||
}
|
||||
}
|
||||
|
||||
if (slave->drive->present) {
|
||||
err = taskfile_lib_get_identify(slave->drive, slave->idbuff);
|
||||
if (err) {
|
||||
DEBPRINT("identify device %s failed (%d)\n",
|
||||
slave->drive->name, err);
|
||||
}
|
||||
}
|
||||
|
||||
if (ide_noacpionboot) {
|
||||
DEBPRINT("ACPI methods disabled on boot\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* ACPI requires us to call _STM on startup
|
||||
*/
|
||||
ide_acpi_get_timing(hwif);
|
||||
ide_acpi_push_timing(hwif);
|
||||
|
||||
for (unit = 0; unit < MAX_DRIVES; ++unit) {
|
||||
ide_drive_t *drive = &hwif->drives[unit];
|
||||
|
||||
if (drive->present) {
|
||||
/* Execute ACPI startup code */
|
||||
ide_acpi_exec_tfs(drive);
|
||||
}
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ide_acpi_init);
|
@ -1384,6 +1384,9 @@ static int hwif_init(ide_hwif_t *hwif)
|
||||
|
||||
done:
|
||||
init_gendisk(hwif);
|
||||
|
||||
ide_acpi_init(hwif);
|
||||
|
||||
hwif->present = 1; /* success */
|
||||
return 1;
|
||||
|
||||
|
@ -187,6 +187,12 @@ int noautodma = 1;
|
||||
|
||||
EXPORT_SYMBOL(noautodma);
|
||||
|
||||
#ifdef CONFIG_BLK_DEV_IDEACPI
|
||||
int ide_noacpi = 0;
|
||||
int ide_noacpitfs = 1;
|
||||
int ide_noacpionboot = 1;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This is declared extern in ide.h, for access by other IDE modules:
|
||||
*/
|
||||
@ -1214,10 +1220,15 @@ EXPORT_SYMBOL(system_bus_clock);
|
||||
static int generic_ide_suspend(struct device *dev, pm_message_t mesg)
|
||||
{
|
||||
ide_drive_t *drive = dev->driver_data;
|
||||
ide_hwif_t *hwif = HWIF(drive);
|
||||
struct request rq;
|
||||
struct request_pm_state rqpm;
|
||||
ide_task_t args;
|
||||
|
||||
/* Call ACPI _GTM only once */
|
||||
if (!(drive->dn % 2))
|
||||
ide_acpi_get_timing(hwif);
|
||||
|
||||
memset(&rq, 0, sizeof(rq));
|
||||
memset(&rqpm, 0, sizeof(rqpm));
|
||||
memset(&args, 0, sizeof(args));
|
||||
@ -1235,10 +1246,17 @@ static int generic_ide_suspend(struct device *dev, pm_message_t mesg)
|
||||
static int generic_ide_resume(struct device *dev)
|
||||
{
|
||||
ide_drive_t *drive = dev->driver_data;
|
||||
ide_hwif_t *hwif = HWIF(drive);
|
||||
struct request rq;
|
||||
struct request_pm_state rqpm;
|
||||
ide_task_t args;
|
||||
|
||||
/* Call ACPI _STM only once */
|
||||
if (!(drive->dn % 2))
|
||||
ide_acpi_push_timing(hwif);
|
||||
|
||||
ide_acpi_exec_tfs(drive);
|
||||
|
||||
memset(&rq, 0, sizeof(rq));
|
||||
memset(&rqpm, 0, sizeof(rqpm));
|
||||
memset(&args, 0, sizeof(args));
|
||||
@ -1543,6 +1561,24 @@ static int __init ide_setup(char *s)
|
||||
}
|
||||
#endif /* CONFIG_BLK_DEV_IDEPCI */
|
||||
|
||||
#ifdef CONFIG_BLK_DEV_IDEACPI
|
||||
if (!strcmp(s, "ide=noacpi")) {
|
||||
//printk(" : Disable IDE ACPI support.\n");
|
||||
ide_noacpi = 1;
|
||||
return 1;
|
||||
}
|
||||
if (!strcmp(s, "ide=acpigtf")) {
|
||||
//printk(" : Enable IDE ACPI _GTF support.\n");
|
||||
ide_noacpitfs = 0;
|
||||
return 1;
|
||||
}
|
||||
if (!strcmp(s, "ide=acpionboot")) {
|
||||
//printk(" : Call IDE ACPI methods on boot.\n");
|
||||
ide_noacpionboot = 0;
|
||||
return 1;
|
||||
}
|
||||
#endif /* CONFIG_BLK_DEV_IDEACPI */
|
||||
|
||||
/*
|
||||
* Look for drive options: "hdx="
|
||||
*/
|
||||
|
@ -9,9 +9,10 @@ obj-$(CONFIG_BLK_DEV_CS5530) += cs5530.o
|
||||
obj-$(CONFIG_BLK_DEV_CS5535) += cs5535.o
|
||||
obj-$(CONFIG_BLK_DEV_SC1200) += sc1200.o
|
||||
obj-$(CONFIG_BLK_DEV_CY82C693) += cy82c693.o
|
||||
obj-$(CONFIG_BLK_DEV_DELKIN) += delkin_cb.o
|
||||
obj-$(CONFIG_BLK_DEV_HPT34X) += hpt34x.o
|
||||
obj-$(CONFIG_BLK_DEV_HPT366) += hpt366.o
|
||||
#obj-$(CONFIG_BLK_DEV_HPT37X) += hpt37x.o
|
||||
obj-$(CONFIG_BLK_DEV_IT8213) += it8213.o
|
||||
obj-$(CONFIG_BLK_DEV_IT821X) += it821x.o
|
||||
obj-$(CONFIG_BLK_DEV_JMICRON) += jmicron.o
|
||||
obj-$(CONFIG_BLK_DEV_NS87415) += ns87415.o
|
||||
@ -26,6 +27,7 @@ obj-$(CONFIG_BLK_DEV_SIIMAGE) += siimage.o
|
||||
obj-$(CONFIG_BLK_DEV_SIS5513) += sis5513.o
|
||||
obj-$(CONFIG_BLK_DEV_SL82C105) += sl82c105.o
|
||||
obj-$(CONFIG_BLK_DEV_SLC90E66) += slc90e66.o
|
||||
obj-$(CONFIG_BLK_DEV_TC86C001) += tc86c001.o
|
||||
obj-$(CONFIG_BLK_DEV_TRIFLEX) += triflex.o
|
||||
obj-$(CONFIG_BLK_DEV_TRM290) += trm290.o
|
||||
obj-$(CONFIG_BLK_DEV_VIA82CXXX) += via82cxxx.o
|
||||
|
140
drivers/ide/pci/delkin_cb.c
Normal file
140
drivers/ide/pci/delkin_cb.c
Normal file
@ -0,0 +1,140 @@
|
||||
/*
|
||||
* linux/drivers/ide/pci/delkin_cb.c
|
||||
*
|
||||
* Created 20 Oct 2004 by Mark Lord
|
||||
*
|
||||
* Basic support for Delkin/ASKA/Workbit Cardbus CompactFlash adapter
|
||||
*
|
||||
* Modeled after the 16-bit PCMCIA driver: ide-cs.c
|
||||
*
|
||||
* This is slightly peculiar, in that it is a PCI driver,
|
||||
* but is NOT an IDE PCI driver -- the IDE layer does not directly
|
||||
* support hot insertion/removal of PCI interfaces, so this driver
|
||||
* is unable to use the IDE PCI interfaces. Instead, it uses the
|
||||
* same interfaces as the ide-cs (PCMCIA) driver uses.
|
||||
* On the plus side, the driver is also smaller/simpler this way.
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file COPYING in the main directory of this archive for
|
||||
* more details.
|
||||
*/
|
||||
#include <linux/autoconf.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/hdreg.h>
|
||||
#include <linux/ide.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/pci.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
/*
|
||||
* No chip documentation has yet been found,
|
||||
* so these configuration values were pulled from
|
||||
* a running Win98 system using "debug".
|
||||
* This gives around 3MByte/second read performance,
|
||||
* which is about 2/3 of what the chip is capable of.
|
||||
*
|
||||
* There is also a 4KByte mmio region on the card,
|
||||
* but its purpose has yet to be reverse-engineered.
|
||||
*/
|
||||
static const u8 setup[] = {
|
||||
0x00, 0x05, 0xbe, 0x01, 0x20, 0x8f, 0x00, 0x00,
|
||||
0xa4, 0x1f, 0xb3, 0x1b, 0x00, 0x00, 0x00, 0x80,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xa4, 0x83, 0x02, 0x13,
|
||||
};
|
||||
|
||||
static int __devinit
|
||||
delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id)
|
||||
{
|
||||
unsigned long base;
|
||||
hw_regs_t hw;
|
||||
ide_hwif_t *hwif = NULL;
|
||||
ide_drive_t *drive;
|
||||
int i, rc;
|
||||
|
||||
rc = pci_enable_device(dev);
|
||||
if (rc) {
|
||||
printk(KERN_ERR "delkin_cb: pci_enable_device failed (%d)\n", rc);
|
||||
return rc;
|
||||
}
|
||||
rc = pci_request_regions(dev, "delkin_cb");
|
||||
if (rc) {
|
||||
printk(KERN_ERR "delkin_cb: pci_request_regions failed (%d)\n", rc);
|
||||
pci_disable_device(dev);
|
||||
return rc;
|
||||
}
|
||||
base = pci_resource_start(dev, 0);
|
||||
outb(0x02, base + 0x1e); /* set nIEN to block interrupts */
|
||||
inb(base + 0x17); /* read status to clear interrupts */
|
||||
for (i = 0; i < sizeof(setup); ++i) {
|
||||
if (setup[i])
|
||||
outb(setup[i], base + i);
|
||||
}
|
||||
pci_release_regions(dev); /* IDE layer handles regions itself */
|
||||
|
||||
memset(&hw, 0, sizeof(hw));
|
||||
ide_std_init_ports(&hw, base + 0x10, base + 0x1e);
|
||||
hw.irq = dev->irq;
|
||||
hw.chipset = ide_pci; /* this enables IRQ sharing */
|
||||
|
||||
rc = ide_register_hw_with_fixup(&hw, &hwif, ide_undecoded_slave);
|
||||
if (rc < 0) {
|
||||
printk(KERN_ERR "delkin_cb: ide_register_hw failed (%d)\n", rc);
|
||||
pci_disable_device(dev);
|
||||
return -ENODEV;
|
||||
}
|
||||
pci_set_drvdata(dev, hwif);
|
||||
hwif->pci_dev = dev;
|
||||
drive = &hwif->drives[0];
|
||||
if (drive->present) {
|
||||
drive->io_32bit = 1;
|
||||
drive->unmask = 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
delkin_cb_remove (struct pci_dev *dev)
|
||||
{
|
||||
ide_hwif_t *hwif = pci_get_drvdata(dev);
|
||||
|
||||
if (hwif)
|
||||
ide_unregister(hwif->index);
|
||||
pci_disable_device(dev);
|
||||
}
|
||||
|
||||
static struct pci_device_id delkin_cb_pci_tbl[] __devinitdata = {
|
||||
{ 0x1145, 0xf021, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
|
||||
{ 0, },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, delkin_cb_pci_tbl);
|
||||
|
||||
static struct pci_driver driver = {
|
||||
.name = "Delkin-ASKA-Workbit Cardbus IDE",
|
||||
.id_table = delkin_cb_pci_tbl,
|
||||
.probe = delkin_cb_probe,
|
||||
.remove = delkin_cb_remove,
|
||||
};
|
||||
|
||||
static int
|
||||
delkin_cb_init (void)
|
||||
{
|
||||
return pci_module_init(&driver);
|
||||
}
|
||||
|
||||
static void
|
||||
delkin_cb_exit (void)
|
||||
{
|
||||
pci_unregister_driver(&driver);
|
||||
}
|
||||
|
||||
module_init(delkin_cb_init);
|
||||
module_exit(delkin_cb_exit);
|
||||
|
||||
MODULE_AUTHOR("Mark Lord");
|
||||
MODULE_DESCRIPTION("Basic support for Delkin/ASKA/Workbit Cardbus IDE");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
File diff suppressed because it is too large
Load Diff
362
drivers/ide/pci/it8213.c
Normal file
362
drivers/ide/pci/it8213.c
Normal file
@ -0,0 +1,362 @@
|
||||
/*
|
||||
* ITE 8213 IDE driver
|
||||
*
|
||||
* Copyright (C) 2006 Jack Lee
|
||||
* Copyright (C) 2006 Alan Cox
|
||||
* Copyright (C) 2007 Bartlomiej Zolnierkiewicz
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/hdreg.h>
|
||||
#include <linux/ide.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
/*
|
||||
* it8213_ratemask - Compute available modes
|
||||
* @drive: IDE drive
|
||||
*
|
||||
* Compute the available speeds for the devices on the interface. This
|
||||
* is all modes to ATA133 clipped by drive cable setup.
|
||||
*/
|
||||
|
||||
static u8 it8213_ratemask (ide_drive_t *drive)
|
||||
{
|
||||
u8 mode = 4;
|
||||
if (!eighty_ninty_three(drive))
|
||||
mode = min_t(u8, mode, 1);
|
||||
return mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* it8213_dma_2_pio - return the PIO mode matching DMA
|
||||
* @xfer_rate: transfer speed
|
||||
*
|
||||
* Returns the nearest equivalent PIO timing for the PIO or DMA
|
||||
* mode requested by the controller.
|
||||
*/
|
||||
|
||||
static u8 it8213_dma_2_pio (u8 xfer_rate) {
|
||||
switch(xfer_rate) {
|
||||
case XFER_UDMA_6:
|
||||
case XFER_UDMA_5:
|
||||
case XFER_UDMA_4:
|
||||
case XFER_UDMA_3:
|
||||
case XFER_UDMA_2:
|
||||
case XFER_UDMA_1:
|
||||
case XFER_UDMA_0:
|
||||
case XFER_MW_DMA_2:
|
||||
case XFER_PIO_4:
|
||||
return 4;
|
||||
case XFER_MW_DMA_1:
|
||||
case XFER_PIO_3:
|
||||
return 3;
|
||||
case XFER_SW_DMA_2:
|
||||
case XFER_PIO_2:
|
||||
return 2;
|
||||
case XFER_MW_DMA_0:
|
||||
case XFER_SW_DMA_1:
|
||||
case XFER_SW_DMA_0:
|
||||
case XFER_PIO_1:
|
||||
case XFER_PIO_0:
|
||||
case XFER_PIO_SLOW:
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* it8213_tuneproc - tune a drive
|
||||
* @drive: drive to tune
|
||||
* @pio: desired PIO mode
|
||||
*
|
||||
* Set the interface PIO mode.
|
||||
*/
|
||||
|
||||
static void it8213_tuneproc (ide_drive_t *drive, u8 pio)
|
||||
{
|
||||
ide_hwif_t *hwif = HWIF(drive);
|
||||
struct pci_dev *dev = hwif->pci_dev;
|
||||
int is_slave = drive->dn & 1;
|
||||
int master_port = 0x40;
|
||||
int slave_port = 0x44;
|
||||
unsigned long flags;
|
||||
u16 master_data;
|
||||
u8 slave_data;
|
||||
static DEFINE_SPINLOCK(tune_lock);
|
||||
int control = 0;
|
||||
|
||||
static const u8 timings[][2]= {
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 1, 0 },
|
||||
{ 2, 1 },
|
||||
{ 2, 3 }, };
|
||||
|
||||
pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
|
||||
|
||||
spin_lock_irqsave(&tune_lock, flags);
|
||||
pci_read_config_word(dev, master_port, &master_data);
|
||||
|
||||
if (pio > 1)
|
||||
control |= 1; /* Programmable timing on */
|
||||
if (drive->media != ide_disk)
|
||||
control |= 4; /* ATAPI */
|
||||
if (pio > 2)
|
||||
control |= 2; /* IORDY */
|
||||
if (is_slave) {
|
||||
master_data |= 0x4000;
|
||||
master_data &= ~0x0070;
|
||||
if (pio > 1)
|
||||
master_data = master_data | (control << 4);
|
||||
pci_read_config_byte(dev, slave_port, &slave_data);
|
||||
slave_data = slave_data & 0xf0;
|
||||
slave_data = slave_data | (timings[pio][0] << 2) | timings[pio][1];
|
||||
} else {
|
||||
master_data &= ~0x3307;
|
||||
if (pio > 1)
|
||||
master_data = master_data | control;
|
||||
master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8);
|
||||
}
|
||||
pci_write_config_word(dev, master_port, master_data);
|
||||
if (is_slave)
|
||||
pci_write_config_byte(dev, slave_port, slave_data);
|
||||
spin_unlock_irqrestore(&tune_lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* it8213_tune_chipset - set controller timings
|
||||
* @drive: Drive to set up
|
||||
* @xferspeed: speed we want to achieve
|
||||
*
|
||||
* Tune the ITE chipset for the desired mode. If we can't achieve
|
||||
* the desired mode then tune for a lower one, but ultimately
|
||||
* make the thing work.
|
||||
*/
|
||||
|
||||
static int it8213_tune_chipset (ide_drive_t *drive, u8 xferspeed)
|
||||
{
|
||||
|
||||
ide_hwif_t *hwif = HWIF(drive);
|
||||
struct pci_dev *dev = hwif->pci_dev;
|
||||
u8 maslave = 0x40;
|
||||
u8 speed = ide_rate_filter(it8213_ratemask(drive), xferspeed);
|
||||
int a_speed = 3 << (drive->dn * 4);
|
||||
int u_flag = 1 << drive->dn;
|
||||
int v_flag = 0x01 << drive->dn;
|
||||
int w_flag = 0x10 << drive->dn;
|
||||
int u_speed = 0;
|
||||
u16 reg4042, reg4a;
|
||||
u8 reg48, reg54, reg55;
|
||||
|
||||
pci_read_config_word(dev, maslave, ®4042);
|
||||
pci_read_config_byte(dev, 0x48, ®48);
|
||||
pci_read_config_word(dev, 0x4a, ®4a);
|
||||
pci_read_config_byte(dev, 0x54, ®54);
|
||||
pci_read_config_byte(dev, 0x55, ®55);
|
||||
|
||||
switch(speed) {
|
||||
case XFER_UDMA_6:
|
||||
case XFER_UDMA_4:
|
||||
case XFER_UDMA_2: u_speed = 2 << (drive->dn * 4); break;
|
||||
case XFER_UDMA_5:
|
||||
case XFER_UDMA_3:
|
||||
case XFER_UDMA_1: u_speed = 1 << (drive->dn * 4); break;
|
||||
case XFER_UDMA_0: u_speed = 0 << (drive->dn * 4); break;
|
||||
break;
|
||||
case XFER_MW_DMA_2:
|
||||
case XFER_MW_DMA_1:
|
||||
case XFER_SW_DMA_2:
|
||||
break;
|
||||
case XFER_PIO_4:
|
||||
case XFER_PIO_3:
|
||||
case XFER_PIO_2:
|
||||
case XFER_PIO_1:
|
||||
case XFER_PIO_0:
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (speed >= XFER_UDMA_0) {
|
||||
if (!(reg48 & u_flag))
|
||||
pci_write_config_byte(dev, 0x48, reg48 | u_flag);
|
||||
if (speed >= XFER_UDMA_5) {
|
||||
pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag);
|
||||
} else {
|
||||
pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
|
||||
}
|
||||
|
||||
if ((reg4a & a_speed) != u_speed)
|
||||
pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed);
|
||||
if (speed > XFER_UDMA_2) {
|
||||
if (!(reg54 & v_flag))
|
||||
pci_write_config_byte(dev, 0x54, reg54 | v_flag);
|
||||
} else
|
||||
pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
|
||||
} else {
|
||||
if (reg48 & u_flag)
|
||||
pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);
|
||||
if (reg4a & a_speed)
|
||||
pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
|
||||
if (reg54 & v_flag)
|
||||
pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
|
||||
if (reg55 & w_flag)
|
||||
pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
|
||||
}
|
||||
it8213_tuneproc(drive, it8213_dma_2_pio(speed));
|
||||
return ide_config_drive_speed(drive, speed);
|
||||
}
|
||||
|
||||
/*
|
||||
* config_chipset_for_dma - configure for DMA
|
||||
* @drive: drive to configure
|
||||
*
|
||||
* Called by the IDE layer when it wants the timings set up.
|
||||
*/
|
||||
|
||||
static int config_chipset_for_dma (ide_drive_t *drive)
|
||||
{
|
||||
u8 speed = ide_dma_speed(drive, it8213_ratemask(drive));
|
||||
|
||||
if (!speed)
|
||||
return 0;
|
||||
|
||||
it8213_tune_chipset(drive, speed);
|
||||
|
||||
return ide_dma_enable(drive);
|
||||
}
|
||||
|
||||
/**
|
||||
* it8213_configure_drive_for_dma - set up for DMA transfers
|
||||
* @drive: drive we are going to set up
|
||||
*
|
||||
* Set up the drive for DMA, tune the controller and drive as
|
||||
* required. If the drive isn't suitable for DMA or we hit
|
||||
* other problems then we will drop down to PIO and set up
|
||||
* PIO appropriately
|
||||
*/
|
||||
|
||||
static int it8213_config_drive_for_dma (ide_drive_t *drive)
|
||||
{
|
||||
ide_hwif_t *hwif = drive->hwif;
|
||||
|
||||
if (ide_use_dma(drive)) {
|
||||
if (config_chipset_for_dma(drive))
|
||||
return hwif->ide_dma_on(drive);
|
||||
}
|
||||
|
||||
hwif->speedproc(drive, XFER_PIO_0
|
||||
+ ide_get_best_pio_mode(drive, 255, 4, NULL));
|
||||
|
||||
return hwif->ide_dma_off_quietly(drive);
|
||||
}
|
||||
|
||||
/**
|
||||
* init_hwif_it8213 - set up hwif structs
|
||||
* @hwif: interface to set up
|
||||
*
|
||||
* We do the basic set up of the interface structure. The IT8212
|
||||
* requires several custom handlers so we override the default
|
||||
* ide DMA handlers appropriately
|
||||
*/
|
||||
|
||||
static void __devinit init_hwif_it8213(ide_hwif_t *hwif)
|
||||
{
|
||||
u8 reg42h = 0, ata66 = 0;
|
||||
|
||||
hwif->speedproc = &it8213_tune_chipset;
|
||||
hwif->tuneproc = &it8213_tuneproc;
|
||||
|
||||
hwif->autodma = 0;
|
||||
|
||||
hwif->drives[0].autotune = 1;
|
||||
hwif->drives[1].autotune = 1;
|
||||
|
||||
if (!hwif->dma_base)
|
||||
return;
|
||||
|
||||
hwif->atapi_dma = 1;
|
||||
hwif->ultra_mask = 0x7f;
|
||||
hwif->mwdma_mask = 0x06;
|
||||
hwif->swdma_mask = 0x04;
|
||||
|
||||
pci_read_config_byte(hwif->pci_dev, 0x42, ®42h);
|
||||
ata66 = (reg42h & 0x02) ? 0 : 1;
|
||||
|
||||
hwif->ide_dma_check = &it8213_config_drive_for_dma;
|
||||
if (!(hwif->udma_four))
|
||||
hwif->udma_four = ata66;
|
||||
|
||||
/*
|
||||
* The BIOS often doesn't set up DMA on this controller
|
||||
* so we always do it.
|
||||
*/
|
||||
if (!noautodma)
|
||||
hwif->autodma = 1;
|
||||
|
||||
hwif->drives[0].autodma = hwif->autodma;
|
||||
hwif->drives[1].autodma = hwif->autodma;
|
||||
}
|
||||
|
||||
|
||||
#define DECLARE_ITE_DEV(name_str) \
|
||||
{ \
|
||||
.name = name_str, \
|
||||
.init_hwif = init_hwif_it8213, \
|
||||
.channels = 1, \
|
||||
.autodma = AUTODMA, \
|
||||
.enablebits = {{0x41,0x80,0x80}}, \
|
||||
.bootable = ON_BOARD, \
|
||||
}
|
||||
|
||||
static ide_pci_device_t it8213_chipsets[] __devinitdata = {
|
||||
/* 0 */ DECLARE_ITE_DEV("IT8213"),
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* it8213_init_one - pci layer discovery entry
|
||||
* @dev: PCI device
|
||||
* @id: ident table entry
|
||||
*
|
||||
* Called by the PCI code when it finds an ITE8213 controller. As
|
||||
* this device follows the standard interfaces we can use the
|
||||
* standard helper functions to do almost all the work for us.
|
||||
*/
|
||||
|
||||
static int __devinit it8213_init_one(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
{
|
||||
ide_setup_pci_device(dev, &it8213_chipsets[id->driver_data]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct pci_device_id it8213_pci_tbl[] = {
|
||||
{ PCI_VENDOR_ID_ITE, 0x8213, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
|
||||
{ 0, },
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, it8213_pci_tbl);
|
||||
|
||||
static struct pci_driver driver = {
|
||||
.name = "ITE8213_IDE",
|
||||
.id_table = it8213_pci_tbl,
|
||||
.probe = it8213_init_one,
|
||||
};
|
||||
|
||||
static int __init it8213_ide_init(void)
|
||||
{
|
||||
return ide_pci_register_driver(&driver);
|
||||
}
|
||||
|
||||
module_init(it8213_ide_init);
|
||||
|
||||
MODULE_AUTHOR("Jack Lee, Alan Cox");
|
||||
MODULE_DESCRIPTION("PCI driver module for the ITE 8213");
|
||||
MODULE_LICENSE("GPL");
|
@ -92,26 +92,6 @@ static u8 pdcnew_ratemask(ide_drive_t *drive)
|
||||
return mode;
|
||||
}
|
||||
|
||||
static int check_in_drive_lists(ide_drive_t *drive, const char **list)
|
||||
{
|
||||
struct hd_driveid *id = drive->id;
|
||||
|
||||
if (pdc_quirk_drives == list) {
|
||||
while (*list) {
|
||||
if (strstr(id->model, *list++)) {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while (*list) {
|
||||
if (!strcmp(*list++,id->model)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_indexed_reg - Get indexed register
|
||||
* @hwif: for the port address
|
||||
@ -249,13 +229,6 @@ static int pdcnew_tune_chipset(ide_drive_t *drive, u8 speed)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* 0 1 2 3 4 5 6 7 8
|
||||
* 960, 480, 390, 300, 240, 180, 120, 90, 60
|
||||
* 180, 150, 120, 90, 60
|
||||
* DMA_Speed
|
||||
* 180, 120, 90, 90, 90, 60, 30
|
||||
* 11, 5, 4, 3, 2, 1, 0
|
||||
*/
|
||||
static void pdcnew_tune_drive(ide_drive_t *drive, u8 pio)
|
||||
{
|
||||
pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
|
||||
@ -313,12 +286,10 @@ static int pdcnew_config_drive_xfer_rate(ide_drive_t *drive)
|
||||
|
||||
drive->init_speed = 0;
|
||||
|
||||
if (id && (id->capability & 1) && drive->autodma) {
|
||||
if ((id->capability & 1) && drive->autodma) {
|
||||
|
||||
if (ide_use_dma(drive)) {
|
||||
if (config_chipset_for_dma(drive))
|
||||
return hwif->ide_dma_on(drive);
|
||||
}
|
||||
if (ide_use_dma(drive) && config_chipset_for_dma(drive))
|
||||
return hwif->ide_dma_on(drive);
|
||||
|
||||
goto fast_ata_pio;
|
||||
|
||||
@ -333,21 +304,12 @@ static int pdcnew_config_drive_xfer_rate(ide_drive_t *drive)
|
||||
|
||||
static int pdcnew_quirkproc(ide_drive_t *drive)
|
||||
{
|
||||
return check_in_drive_lists(drive, pdc_quirk_drives);
|
||||
}
|
||||
const char **list, *model = drive->id->model;
|
||||
|
||||
static int pdcnew_ide_dma_lostirq(ide_drive_t *drive)
|
||||
{
|
||||
if (HWIF(drive)->resetproc != NULL)
|
||||
HWIF(drive)->resetproc(drive);
|
||||
return __ide_dma_lostirq(drive);
|
||||
}
|
||||
|
||||
static int pdcnew_ide_dma_timeout(ide_drive_t *drive)
|
||||
{
|
||||
if (HWIF(drive)->resetproc != NULL)
|
||||
HWIF(drive)->resetproc(drive);
|
||||
return __ide_dma_timeout(drive);
|
||||
for (list = pdc_quirk_drives; *list != NULL; list++)
|
||||
if (strstr(model, *list) != NULL)
|
||||
return 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pdcnew_reset(ide_drive_t *drive)
|
||||
@ -599,8 +561,6 @@ static void __devinit init_hwif_pdc202new(ide_hwif_t *hwif)
|
||||
hwif->err_stops_fifo = 1;
|
||||
|
||||
hwif->ide_dma_check = &pdcnew_config_drive_xfer_rate;
|
||||
hwif->ide_dma_lostirq = &pdcnew_ide_dma_lostirq;
|
||||
hwif->ide_dma_timeout = &pdcnew_ide_dma_timeout;
|
||||
|
||||
if (!hwif->udma_four)
|
||||
hwif->udma_four = pdcnew_cable_detect(hwif) ? 0 : 1;
|
||||
|
@ -123,26 +123,6 @@ static u8 pdc202xx_ratemask (ide_drive_t *drive)
|
||||
return mode;
|
||||
}
|
||||
|
||||
static int check_in_drive_lists (ide_drive_t *drive, const char **list)
|
||||
{
|
||||
struct hd_driveid *id = drive->id;
|
||||
|
||||
if (pdc_quirk_drives == list) {
|
||||
while (*list) {
|
||||
if (strstr(id->model, *list++)) {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while (*list) {
|
||||
if (!strcmp(*list++,id->model)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pdc202xx_tune_chipset (ide_drive_t *drive, u8 xferspeed)
|
||||
{
|
||||
ide_hwif_t *hwif = HWIF(drive);
|
||||
@ -377,7 +357,12 @@ static int pdc202xx_config_drive_xfer_rate (ide_drive_t *drive)
|
||||
|
||||
static int pdc202xx_quirkproc (ide_drive_t *drive)
|
||||
{
|
||||
return ((int) check_in_drive_lists(drive, pdc_quirk_drives));
|
||||
const char **list, *model = drive->id->model;
|
||||
|
||||
for (list = pdc_quirk_drives; *list != NULL; list++)
|
||||
if (strstr(model, *list) != NULL)
|
||||
return 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pdc202xx_old_ide_dma_start(ide_drive_t *drive)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* linux/drivers/ide/pci/piix.c Version 0.45 May 12, 2006
|
||||
* linux/drivers/ide/pci/piix.c Version 0.46 December 3, 2006
|
||||
*
|
||||
* Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
|
||||
* Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
|
||||
@ -163,7 +163,7 @@ static u8 piix_ratemask (ide_drive_t *drive)
|
||||
* if the drive cannot see an 80pin cable.
|
||||
*/
|
||||
if (!eighty_ninty_three(drive))
|
||||
mode = min(mode, (u8)1);
|
||||
mode = min_t(u8, mode, 1);
|
||||
return mode;
|
||||
}
|
||||
|
||||
@ -216,7 +216,7 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio)
|
||||
{
|
||||
ide_hwif_t *hwif = HWIF(drive);
|
||||
struct pci_dev *dev = hwif->pci_dev;
|
||||
int is_slave = (&hwif->drives[1] == drive);
|
||||
int is_slave = drive->dn & 1;
|
||||
int master_port = hwif->channel ? 0x42 : 0x40;
|
||||
int slave_port = 0x44;
|
||||
unsigned long flags;
|
||||
@ -225,7 +225,7 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio)
|
||||
static DEFINE_SPINLOCK(tune_lock);
|
||||
int control = 0;
|
||||
|
||||
/* ISP RTC */
|
||||
/* ISP RTC */
|
||||
static const u8 timings[][2]= {
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
@ -233,7 +233,7 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio)
|
||||
{ 2, 1 },
|
||||
{ 2, 3 }, };
|
||||
|
||||
pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
|
||||
pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
|
||||
|
||||
/*
|
||||
* Master vs slave is synchronized above us but the slave register is
|
||||
@ -243,25 +243,24 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio)
|
||||
spin_lock_irqsave(&tune_lock, flags);
|
||||
pci_read_config_word(dev, master_port, &master_data);
|
||||
|
||||
if (pio >= 2)
|
||||
if (pio > 1)
|
||||
control |= 1; /* Programmable timing on */
|
||||
if (drive->media == ide_disk)
|
||||
control |= 4; /* Prefetch, post write */
|
||||
if (pio >= 3)
|
||||
if (pio > 2)
|
||||
control |= 2; /* IORDY */
|
||||
if (is_slave) {
|
||||
master_data = master_data | 0x4000;
|
||||
master_data |= 0x4000;
|
||||
master_data &= ~0x0070;
|
||||
if (pio > 1) {
|
||||
/* enable PPE, IE and TIME */
|
||||
master_data = master_data | (control << 4);
|
||||
} else {
|
||||
master_data &= ~0x0070;
|
||||
}
|
||||
pci_read_config_byte(dev, slave_port, &slave_data);
|
||||
slave_data = slave_data & (hwif->channel ? 0x0f : 0xf0);
|
||||
slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) << (hwif->channel ? 4 : 0));
|
||||
} else {
|
||||
master_data = master_data & 0xccf8;
|
||||
master_data &= ~0x3307;
|
||||
if (pio > 1) {
|
||||
/* enable PPE, IE and TIME */
|
||||
master_data = master_data | control;
|
||||
@ -539,13 +538,19 @@ static ide_pci_device_t piix_pci_info[] __devinitdata = {
|
||||
/* 0 */ DECLARE_PIIX_DEV("PIIXa"),
|
||||
/* 1 */ DECLARE_PIIX_DEV("PIIXb"),
|
||||
|
||||
{ /* 2 */
|
||||
/* 2 */
|
||||
{ /*
|
||||
* MPIIX actually has only a single IDE channel mapped to
|
||||
* the primary or secondary ports depending on the value
|
||||
* of the bit 14 of the IDETIM register at offset 0x6c
|
||||
*/
|
||||
.name = "MPIIX",
|
||||
.init_hwif = init_hwif_piix,
|
||||
.channels = 2,
|
||||
.autodma = NODMA,
|
||||
.enablebits = {{0x6D,0x80,0x80}, {0x6F,0x80,0x80}},
|
||||
.enablebits = {{0x6d,0xc0,0x80}, {0x6d,0xc0,0xc0}},
|
||||
.bootable = ON_BOARD,
|
||||
.flags = IDEPCI_FLAG_ISA_PORTS
|
||||
},
|
||||
|
||||
/* 3 */ DECLARE_PIIX_DEV("PIIX3"),
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* linux/drivers/ide/pci/slc90e66.c Version 0.12 May 12, 2006
|
||||
* linux/drivers/ide/pci/slc90e66.c Version 0.13 December 30, 2006
|
||||
*
|
||||
* Copyright (C) 2000-2002 Andre Hedrick <andre@linux-ide.org>
|
||||
* Copyright (C) 2006 MontaVista Software, Inc. <source@mvista.com>
|
||||
@ -26,7 +26,7 @@ static u8 slc90e66_ratemask (ide_drive_t *drive)
|
||||
u8 mode = 2;
|
||||
|
||||
if (!eighty_ninty_three(drive))
|
||||
mode = min(mode, (u8)1);
|
||||
mode = min_t(u8, mode, 1);
|
||||
return mode;
|
||||
}
|
||||
|
||||
@ -65,36 +65,47 @@ static void slc90e66_tune_drive (ide_drive_t *drive, u8 pio)
|
||||
{
|
||||
ide_hwif_t *hwif = HWIF(drive);
|
||||
struct pci_dev *dev = hwif->pci_dev;
|
||||
int is_slave = (&hwif->drives[1] == drive);
|
||||
int is_slave = drive->dn & 1;
|
||||
int master_port = hwif->channel ? 0x42 : 0x40;
|
||||
int slave_port = 0x44;
|
||||
unsigned long flags;
|
||||
u16 master_data;
|
||||
u8 slave_data;
|
||||
/* ISP RTC */
|
||||
int control = 0;
|
||||
/* ISP RTC */
|
||||
static const u8 timings[][2]= {
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 1, 0 },
|
||||
{ 2, 1 },
|
||||
{ 2, 3 }, };
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 1, 0 },
|
||||
{ 2, 1 },
|
||||
{ 2, 3 }, };
|
||||
|
||||
pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
|
||||
pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
|
||||
spin_lock_irqsave(&ide_lock, flags);
|
||||
pci_read_config_word(dev, master_port, &master_data);
|
||||
|
||||
if (pio > 1)
|
||||
control |= 1; /* Programmable timing on */
|
||||
if (drive->media == ide_disk)
|
||||
control |= 4; /* Prefetch, post write */
|
||||
if (pio > 2)
|
||||
control |= 2; /* IORDY */
|
||||
if (is_slave) {
|
||||
master_data = master_data | 0x4000;
|
||||
if (pio > 1)
|
||||
master_data |= 0x4000;
|
||||
master_data &= ~0x0070;
|
||||
if (pio > 1) {
|
||||
/* enable PPE, IE and TIME */
|
||||
master_data = master_data | 0x0070;
|
||||
master_data = master_data | (control << 4);
|
||||
}
|
||||
pci_read_config_byte(dev, slave_port, &slave_data);
|
||||
slave_data = slave_data & (hwif->channel ? 0x0f : 0xf0);
|
||||
slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) << (hwif->channel ? 4 : 0));
|
||||
} else {
|
||||
master_data = master_data & 0xccf8;
|
||||
if (pio > 1)
|
||||
master_data &= ~0x3307;
|
||||
if (pio > 1) {
|
||||
/* enable PPE, IE and TIME */
|
||||
master_data = master_data | 0x0007;
|
||||
master_data = master_data | control;
|
||||
}
|
||||
master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8);
|
||||
}
|
||||
pci_write_config_word(dev, master_port, master_data);
|
||||
@ -173,7 +184,7 @@ static int slc90e66_config_drive_xfer_rate (ide_drive_t *drive)
|
||||
|
||||
drive->init_speed = 0;
|
||||
|
||||
if (id && (id->capability & 1) && drive->autodma) {
|
||||
if ((id->capability & 1) && drive->autodma) {
|
||||
|
||||
if (ide_use_dma(drive) && slc90e66_config_drive_for_dma(drive))
|
||||
return hwif->ide_dma_on(drive);
|
||||
@ -201,7 +212,7 @@ static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif)
|
||||
hwif->irq = hwif->channel ? 15 : 14;
|
||||
|
||||
hwif->speedproc = &slc90e66_tune_chipset;
|
||||
hwif->tuneproc = &slc90e66_tune_drive;
|
||||
hwif->tuneproc = &slc90e66_tune_drive;
|
||||
|
||||
pci_read_config_byte(hwif->pci_dev, 0x47, ®47);
|
||||
|
||||
@ -213,14 +224,16 @@ static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif)
|
||||
|
||||
hwif->atapi_dma = 1;
|
||||
hwif->ultra_mask = 0x1f;
|
||||
hwif->mwdma_mask = 0x07;
|
||||
hwif->swdma_mask = 0x07;
|
||||
hwif->mwdma_mask = 0x06;
|
||||
hwif->swdma_mask = 0x04;
|
||||
|
||||
if (!(hwif->udma_four))
|
||||
if (!hwif->udma_four) {
|
||||
/* bit[0(1)]: 0:80, 1:40 */
|
||||
hwif->udma_four = (reg47 & mask) ? 0 : 1;
|
||||
}
|
||||
|
||||
hwif->ide_dma_check = &slc90e66_config_drive_xfer_rate;
|
||||
|
||||
if (!noautodma)
|
||||
hwif->autodma = 1;
|
||||
hwif->drives[0].autodma = hwif->autodma;
|
||||
|
309
drivers/ide/pci/tc86c001.c
Normal file
309
drivers/ide/pci/tc86c001.c
Normal file
@ -0,0 +1,309 @@
|
||||
/*
|
||||
* drivers/ide/pci/tc86c001.c Version 1.00 Dec 12, 2006
|
||||
*
|
||||
* Copyright (C) 2002 Toshiba Corporation
|
||||
* Copyright (C) 2005-2006 MontaVista Software, Inc. <source@mvista.com>
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/ide.h>
|
||||
|
||||
static inline u8 tc86c001_ratemask(ide_drive_t *drive)
|
||||
{
|
||||
return eighty_ninty_three(drive) ? 2 : 1;
|
||||
}
|
||||
|
||||
static int tc86c001_tune_chipset(ide_drive_t *drive, u8 speed)
|
||||
{
|
||||
ide_hwif_t *hwif = HWIF(drive);
|
||||
unsigned long scr_port = hwif->config_data + (drive->dn ? 0x02 : 0x00);
|
||||
u16 mode, scr = hwif->INW(scr_port);
|
||||
|
||||
speed = ide_rate_filter(tc86c001_ratemask(drive), speed);
|
||||
|
||||
switch (speed) {
|
||||
case XFER_UDMA_4: mode = 0x00c0; break;
|
||||
case XFER_UDMA_3: mode = 0x00b0; break;
|
||||
case XFER_UDMA_2: mode = 0x00a0; break;
|
||||
case XFER_UDMA_1: mode = 0x0090; break;
|
||||
case XFER_UDMA_0: mode = 0x0080; break;
|
||||
case XFER_MW_DMA_2: mode = 0x0070; break;
|
||||
case XFER_MW_DMA_1: mode = 0x0060; break;
|
||||
case XFER_MW_DMA_0: mode = 0x0050; break;
|
||||
case XFER_PIO_4: mode = 0x0400; break;
|
||||
case XFER_PIO_3: mode = 0x0300; break;
|
||||
case XFER_PIO_2: mode = 0x0200; break;
|
||||
case XFER_PIO_1: mode = 0x0100; break;
|
||||
case XFER_PIO_0:
|
||||
default: mode = 0x0000; break;
|
||||
}
|
||||
|
||||
scr &= (speed < XFER_MW_DMA_0) ? 0xf8ff : 0xff0f;
|
||||
scr |= mode;
|
||||
hwif->OUTW(scr, scr_port);
|
||||
|
||||
return ide_config_drive_speed(drive, speed);
|
||||
}
|
||||
|
||||
static void tc86c001_tune_drive(ide_drive_t *drive, u8 pio)
|
||||
{
|
||||
pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
|
||||
(void) tc86c001_tune_chipset(drive, XFER_PIO_0 + pio);
|
||||
}
|
||||
|
||||
/*
|
||||
* HACKITY HACK
|
||||
*
|
||||
* This is a workaround for the limitation 5 of the TC86C001 IDE controller:
|
||||
* if a DMA transfer terminates prematurely, the controller leaves the device's
|
||||
* interrupt request (INTRQ) pending and does not generate a PCI interrupt (or
|
||||
* set the interrupt bit in the DMA status register), thus no PCI interrupt
|
||||
* will occur until a DMA transfer has been successfully completed.
|
||||
*
|
||||
* We work around this by initiating dummy, zero-length DMA transfer on
|
||||
* a DMA timeout expiration. I found no better way to do this with the current
|
||||
* IDE core than to temporarily replace a higher level driver's timer expiry
|
||||
* handler with our own backing up to that handler in case our recovery fails.
|
||||
*/
|
||||
static int tc86c001_timer_expiry(ide_drive_t *drive)
|
||||
{
|
||||
ide_hwif_t *hwif = HWIF(drive);
|
||||
ide_expiry_t *expiry = ide_get_hwifdata(hwif);
|
||||
ide_hwgroup_t *hwgroup = HWGROUP(drive);
|
||||
u8 dma_stat = hwif->INB(hwif->dma_status);
|
||||
|
||||
/* Restore a higher level driver's expiry handler first. */
|
||||
hwgroup->expiry = expiry;
|
||||
|
||||
if ((dma_stat & 5) == 1) { /* DMA active and no interrupt */
|
||||
unsigned long sc_base = hwif->config_data;
|
||||
unsigned long twcr_port = sc_base + (drive->dn ? 0x06 : 0x04);
|
||||
u8 dma_cmd = hwif->INB(hwif->dma_command);
|
||||
|
||||
printk(KERN_WARNING "%s: DMA interrupt possibly stuck, "
|
||||
"attempting recovery...\n", drive->name);
|
||||
|
||||
/* Stop DMA */
|
||||
hwif->OUTB(dma_cmd & ~0x01, hwif->dma_command);
|
||||
|
||||
/* Setup the dummy DMA transfer */
|
||||
hwif->OUTW(0, sc_base + 0x0a); /* Sector Count */
|
||||
hwif->OUTW(0, twcr_port); /* Transfer Word Count 1 or 2 */
|
||||
|
||||
/* Start the dummy DMA transfer */
|
||||
hwif->OUTB(0x00, hwif->dma_command); /* clear R_OR_WCTR for write */
|
||||
hwif->OUTB(0x01, hwif->dma_command); /* set START_STOPBM */
|
||||
|
||||
/*
|
||||
* If an interrupt was pending, it should come thru shortly.
|
||||
* If not, a higher level driver's expiry handler should
|
||||
* eventually cause some kind of recovery from the DMA stall.
|
||||
*/
|
||||
return WAIT_MIN_SLEEP;
|
||||
}
|
||||
|
||||
/* Chain to the restored expiry handler if DMA wasn't active. */
|
||||
if (likely(expiry != NULL))
|
||||
return expiry(drive);
|
||||
|
||||
/* If there was no handler, "emulate" that for ide_timer_expiry()... */
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void tc86c001_dma_start(ide_drive_t *drive)
|
||||
{
|
||||
ide_hwif_t *hwif = HWIF(drive);
|
||||
ide_hwgroup_t *hwgroup = HWGROUP(drive);
|
||||
unsigned long sc_base = hwif->config_data;
|
||||
unsigned long twcr_port = sc_base + (drive->dn ? 0x06 : 0x04);
|
||||
unsigned long nsectors = hwgroup->rq->nr_sectors;
|
||||
|
||||
/*
|
||||
* We have to manually load the sector count and size into
|
||||
* the appropriate system control registers for DMA to work
|
||||
* with LBA48 and ATAPI devices...
|
||||
*/
|
||||
hwif->OUTW(nsectors, sc_base + 0x0a); /* Sector Count */
|
||||
hwif->OUTW(SECTOR_SIZE / 2, twcr_port); /* Transfer Word Count 1/2 */
|
||||
|
||||
/* Install our timeout expiry hook, saving the current handler... */
|
||||
ide_set_hwifdata(hwif, hwgroup->expiry);
|
||||
hwgroup->expiry = &tc86c001_timer_expiry;
|
||||
|
||||
ide_dma_start(drive);
|
||||
}
|
||||
|
||||
static int tc86c001_busproc(ide_drive_t *drive, int state)
|
||||
{
|
||||
ide_hwif_t *hwif = HWIF(drive);
|
||||
unsigned long sc_base = hwif->config_data;
|
||||
u16 scr1;
|
||||
|
||||
/* System Control 1 Register bit 11 (ATA Hard Reset) read */
|
||||
scr1 = hwif->INW(sc_base + 0x00);
|
||||
|
||||
switch (state) {
|
||||
case BUSSTATE_ON:
|
||||
if (!(scr1 & 0x0800))
|
||||
return 0;
|
||||
scr1 &= ~0x0800;
|
||||
|
||||
hwif->drives[0].failures = hwif->drives[1].failures = 0;
|
||||
break;
|
||||
case BUSSTATE_OFF:
|
||||
if (scr1 & 0x0800)
|
||||
return 0;
|
||||
scr1 |= 0x0800;
|
||||
|
||||
hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
|
||||
hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* System Control 1 Register bit 11 (ATA Hard Reset) write */
|
||||
hwif->OUTW(scr1, sc_base + 0x00);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int config_chipset_for_dma(ide_drive_t *drive)
|
||||
{
|
||||
u8 speed = ide_dma_speed(drive, tc86c001_ratemask(drive));
|
||||
|
||||
if (!speed)
|
||||
return 0;
|
||||
|
||||
(void) tc86c001_tune_chipset(drive, speed);
|
||||
return ide_dma_enable(drive);
|
||||
}
|
||||
|
||||
static int tc86c001_config_drive_xfer_rate(ide_drive_t *drive)
|
||||
{
|
||||
ide_hwif_t *hwif = HWIF(drive);
|
||||
struct hd_driveid *id = drive->id;
|
||||
|
||||
if ((id->capability & 1) && drive->autodma) {
|
||||
|
||||
if (ide_use_dma(drive) && config_chipset_for_dma(drive))
|
||||
return hwif->ide_dma_on(drive);
|
||||
|
||||
goto fast_ata_pio;
|
||||
|
||||
} else if ((id->capability & 8) || (id->field_valid & 2)) {
|
||||
fast_ata_pio:
|
||||
tc86c001_tune_drive(drive, 255);
|
||||
return hwif->ide_dma_off_quietly(drive);
|
||||
}
|
||||
/* IORDY not supported */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __devinit init_hwif_tc86c001(ide_hwif_t *hwif)
|
||||
{
|
||||
unsigned long sc_base = pci_resource_start(hwif->pci_dev, 5);
|
||||
u16 scr1 = hwif->INW(sc_base + 0x00);;
|
||||
|
||||
/* System Control 1 Register bit 15 (Soft Reset) set */
|
||||
hwif->OUTW(scr1 | 0x8000, sc_base + 0x00);
|
||||
|
||||
/* System Control 1 Register bit 14 (FIFO Reset) set */
|
||||
hwif->OUTW(scr1 | 0x4000, sc_base + 0x00);
|
||||
|
||||
/* System Control 1 Register: reset clear */
|
||||
hwif->OUTW(scr1 & ~0xc000, sc_base + 0x00);
|
||||
|
||||
/* Store the system control register base for convenience... */
|
||||
hwif->config_data = sc_base;
|
||||
|
||||
hwif->tuneproc = &tc86c001_tune_drive;
|
||||
hwif->speedproc = &tc86c001_tune_chipset;
|
||||
hwif->busproc = &tc86c001_busproc;
|
||||
|
||||
hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
|
||||
|
||||
if (!hwif->dma_base)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Sector Count Control Register bits 0 and 1 set:
|
||||
* software sets Sector Count Register for master and slave device
|
||||
*/
|
||||
hwif->OUTW(0x0003, sc_base + 0x0c);
|
||||
|
||||
/* Sector Count Register limit */
|
||||
hwif->rqsize = 0xffff;
|
||||
|
||||
hwif->atapi_dma = 1;
|
||||
hwif->ultra_mask = 0x1f;
|
||||
hwif->mwdma_mask = 0x07;
|
||||
|
||||
hwif->ide_dma_check = &tc86c001_config_drive_xfer_rate;
|
||||
hwif->dma_start = &tc86c001_dma_start;
|
||||
|
||||
if (!hwif->udma_four) {
|
||||
/*
|
||||
* System Control 1 Register bit 13 (PDIAGN):
|
||||
* 0=80-pin cable, 1=40-pin cable
|
||||
*/
|
||||
scr1 = hwif->INW(sc_base + 0x00);
|
||||
hwif->udma_four = (scr1 & 0x2000) ? 0 : 1;
|
||||
}
|
||||
|
||||
if (!noautodma)
|
||||
hwif->autodma = 1;
|
||||
hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
|
||||
}
|
||||
|
||||
static unsigned int __devinit init_chipset_tc86c001(struct pci_dev *dev,
|
||||
const char *name)
|
||||
{
|
||||
int err = pci_request_region(dev, 5, name);
|
||||
|
||||
if (err)
|
||||
printk(KERN_ERR "%s: system control regs already in use", name);
|
||||
return err;
|
||||
}
|
||||
|
||||
static ide_pci_device_t tc86c001_chipset __devinitdata = {
|
||||
.name = "TC86C001",
|
||||
.init_chipset = init_chipset_tc86c001,
|
||||
.init_hwif = init_hwif_tc86c001,
|
||||
.channels = 1,
|
||||
.autodma = AUTODMA,
|
||||
.bootable = OFF_BOARD
|
||||
};
|
||||
|
||||
static int __devinit tc86c001_init_one(struct pci_dev *dev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
return ide_setup_pci_device(dev, &tc86c001_chipset);
|
||||
}
|
||||
|
||||
static struct pci_device_id tc86c001_pci_tbl[] = {
|
||||
{ PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE,
|
||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
|
||||
{ 0, }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, tc86c001_pci_tbl);
|
||||
|
||||
static struct pci_driver driver = {
|
||||
.name = "TC86C001",
|
||||
.id_table = tc86c001_pci_tbl,
|
||||
.probe = tc86c001_init_one
|
||||
};
|
||||
|
||||
static int __init tc86c001_ide_init(void)
|
||||
{
|
||||
return ide_pci_register_driver(&driver);
|
||||
}
|
||||
module_init(tc86c001_ide_init);
|
||||
|
||||
MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
|
||||
MODULE_DESCRIPTION("PCI driver module for TC86C001 IDE");
|
||||
MODULE_LICENSE("GPL");
|
@ -1460,6 +1460,24 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2609, quirk_intel_pcie_pm);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x260a, quirk_intel_pcie_pm);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x260b, quirk_intel_pcie_pm);
|
||||
|
||||
/*
|
||||
* Toshiba TC86C001 IDE controller reports the standard 8-byte BAR0 size
|
||||
* but the PIO transfers won't work if BAR0 falls at the odd 8 bytes.
|
||||
* Re-allocate the region if needed...
|
||||
*/
|
||||
static void __init quirk_tc86c001_ide(struct pci_dev *dev)
|
||||
{
|
||||
struct resource *r = &dev->resource[0];
|
||||
|
||||
if (r->start & 0x8) {
|
||||
r->start = 0;
|
||||
r->end = 0xf;
|
||||
}
|
||||
}
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TOSHIBA_2,
|
||||
PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE,
|
||||
quirk_tc86c001_ide);
|
||||
|
||||
static void __devinit quirk_netmos(struct pci_dev *dev)
|
||||
{
|
||||
unsigned int num_parallel = (dev->subsystem_device & 0xf0) >> 4;
|
||||
|
@ -18,6 +18,9 @@
|
||||
#include <linux/device.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/completion.h>
|
||||
#ifdef CONFIG_BLK_DEV_IDEACPI
|
||||
#include <acpi/acpi.h>
|
||||
#endif
|
||||
#include <asm/byteorder.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/io.h>
|
||||
@ -541,6 +544,11 @@ typedef enum {
|
||||
struct ide_driver_s;
|
||||
struct ide_settings_s;
|
||||
|
||||
#ifdef CONFIG_BLK_DEV_IDEACPI
|
||||
struct ide_acpi_drive_link;
|
||||
struct ide_acpi_hwif_link;
|
||||
#endif
|
||||
|
||||
typedef struct ide_drive_s {
|
||||
char name[4]; /* drive name, such as "hda" */
|
||||
char driver_req[10]; /* requests specific driver */
|
||||
@ -637,6 +645,9 @@ typedef struct ide_drive_s {
|
||||
|
||||
int lun; /* logical unit */
|
||||
int crc_count; /* crc counter to reduce drive speed */
|
||||
#ifdef CONFIG_BLK_DEV_IDEACPI
|
||||
struct ide_acpi_drive_link *acpidata;
|
||||
#endif
|
||||
struct list_head list;
|
||||
struct device gendev;
|
||||
struct completion gendev_rel_comp; /* to deal with device release() */
|
||||
@ -804,6 +815,10 @@ typedef struct hwif_s {
|
||||
void *hwif_data; /* extra hwif data */
|
||||
|
||||
unsigned dma;
|
||||
|
||||
#ifdef CONFIG_BLK_DEV_IDEACPI
|
||||
struct ide_acpi_hwif_link *acpidata;
|
||||
#endif
|
||||
} ____cacheline_internodealigned_in_smp ide_hwif_t;
|
||||
|
||||
/*
|
||||
@ -1298,6 +1313,18 @@ static inline void ide_dma_verbose(ide_drive_t *drive) { ; }
|
||||
static inline void ide_release_dma(ide_hwif_t *drive) {;}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BLK_DEV_IDEACPI
|
||||
extern int ide_acpi_exec_tfs(ide_drive_t *drive);
|
||||
extern void ide_acpi_get_timing(ide_hwif_t *hwif);
|
||||
extern void ide_acpi_push_timing(ide_hwif_t *hwif);
|
||||
extern void ide_acpi_init(ide_hwif_t *hwif);
|
||||
#else
|
||||
static inline int ide_acpi_exec_tfs(ide_drive_t *drive) { return 0; }
|
||||
static inline void ide_acpi_get_timing(ide_hwif_t *hwif) { ; }
|
||||
static inline void ide_acpi_push_timing(ide_hwif_t *hwif) { ; }
|
||||
static inline void ide_acpi_init(ide_hwif_t *hwif) { ; }
|
||||
#endif
|
||||
|
||||
extern int ide_hwif_request_regions(ide_hwif_t *hwif);
|
||||
extern void ide_hwif_release_regions(ide_hwif_t* hwif);
|
||||
extern void ide_unregister (unsigned int index);
|
||||
|
@ -1454,6 +1454,7 @@
|
||||
|
||||
#define PCI_VENDOR_ID_TOSHIBA_2 0x102f
|
||||
#define PCI_DEVICE_ID_TOSHIBA_TC35815CF 0x0030
|
||||
#define PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE 0x0105
|
||||
#define PCI_DEVICE_ID_TOSHIBA_TC86C001_MISC 0x0108
|
||||
#define PCI_DEVICE_ID_TOSHIBA_SPIDER_NET 0x01b3
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user