Changes in 4.9.238 af_key: pfkey_dump needs parameter validation KVM: fix memory leak in kvm_io_bus_unregister_dev() kprobes: fix kill kprobe which has been marked as gone RDMA/ucma: ucma_context reference leak in error path mtd: Fix comparison in map_word_andequal() hdlc_ppp: add range checks in ppp_cp_parse_cr() ip: fix tos reflection in ack and reset packets tipc: use skb_unshare() instead in tipc_buf_append() bnxt_en: Protect bnxt_set_eee() and bnxt_set_pauseparam() with mutex. net: phy: Avoid NPD upon phy_detach() when driver is unbound net/hsr: Check skb_put_padto() return value net: add __must_check to skb_put_padto() serial: 8250: Avoid error message on reprobe scsi: aacraid: fix illegal IO beyond last LBA m68k: q40: Fix info-leak in rtc_ioctl gma/gma500: fix a memory disclosure bug due to uninitialized bytes ASoC: kirkwood: fix IRQ error handling ALSA: usb-audio: Add delay quirk for H570e USB headsets PM / devfreq: tegra30: Fix integer overflow on CPU's freq max out clk/ti/adpll: allocate room for terminating null mtd: cfi_cmdset_0002: don't free cfi->cfiq in error path of cfi_amdstd_setup() mfd: mfd-core: Protect against NULL call-back function pointer tracing: Adding NULL checks for trace_array descriptor pointer bcache: fix a lost wake-up problem caused by mca_cannibalize_lock RDMA/i40iw: Fix potential use after free xfs: fix attr leaf header freemap.size underflow RDMA/iw_cgxb4: Fix an error handling path in 'c4iw_connect()' debugfs: Fix !DEBUG_FS debugfs_create_automount CIFS: Properly process SMB3 lease breaks kernel/sys.c: avoid copying possible padding bytes in copy_to_user neigh_stat_seq_next() should increase position index rt_cpu_seq_next should increase position index seqlock: Require WRITE_ONCE surrounding raw_seqcount_barrier media: ti-vpe: cal: Restrict DMA to avoid memory corruption ACPI: EC: Reference count query handlers under lock dmaengine: zynqmp_dma: fix burst length configuration tracing: Set kernel_stack's caller size properly ar5523: Add USB ID of SMCWUSBT-G2 wireless adapter Bluetooth: Fix refcount use-after-free issue mm: pagewalk: fix termination condition in walk_pte_range() Bluetooth: prefetch channel before killing sock KVM: fix overflow of zero page refcount with ksm running ALSA: hda: Clear RIRB status before reading WP skbuff: fix a data race in skb_queue_len() audit: CONFIG_CHANGE don't log internal bookkeeping as an event selinux: sel_avc_get_stat_idx should increase position index scsi: lpfc: Fix RQ buffer leakage when no IOCBs available scsi: lpfc: Fix coverity errors in fmdi attribute handling drm/omap: fix possible object reference leak RDMA/rxe: Fix configuration of atomic queue pair attributes KVM: x86: fix incorrect comparison in trace event x86/pkeys: Add check for pkey "overflow" bpf: Remove recursion prevention from rcu free callback dmaengine: tegra-apb: Prevent race conditions on channel's freeing media: go7007: Fix URB type for interrupt handling Bluetooth: guard against controllers sending zero'd events timekeeping: Prevent 32bit truncation in scale64_check_overflow() drm/amdgpu: increase atombios cmd timeout Bluetooth: L2CAP: handle l2cap config request during open state media: tda10071: fix unsigned sign extension overflow xfs: don't ever return a stale pointer from __xfs_dir3_free_read tpm: ibmvtpm: Wait for buffer to be set before proceeding tracing: Use address-of operator on section symbols serial: 8250_port: Don't service RX FIFO if throttled serial: 8250_omap: Fix sleeping function called from invalid context during probe serial: 8250: 8250_omap: Terminate DMA before pushing data on RX timeout cpufreq: powernv: Fix frame-size-overflow in powernv_cpufreq_work_fn tools: gpio-hammer: Avoid potential overflow in main SUNRPC: Fix a potential buffer overflow in 'svc_print_xprts()' svcrdma: Fix leak of transport addresses ubifs: Fix out-of-bounds memory access caused by abnormal value of node_len ALSA: usb-audio: Fix case when USB MIDI interface has more than one extra endpoint descriptor mm/filemap.c: clear page error before actual read mm/mmap.c: initialize align_offset explicitly for vm_unmapped_area KVM: Remove CREATE_IRQCHIP/SET_PIT2 race bdev: Reduce time holding bd_mutex in sync in blkdev_close() drivers: char: tlclk.c: Avoid data race between init and interrupt handler dt-bindings: sound: wm8994: Correct required supplies based on actual implementaion atm: fix a memory leak of vcc->user_back phy: samsung: s5pv210-usb2: Add delay after reset Bluetooth: Handle Inquiry Cancel error after Inquiry Complete USB: EHCI: ehci-mv: fix error handling in mv_ehci_probe() tty: serial: samsung: Correct clock selection logic ALSA: hda: Fix potential race in unsol event handler fuse: don't check refcount after stealing page USB: EHCI: ehci-mv: fix less than zero comparison of an unsigned int e1000: Do not perform reset in reset_task if we are already down printk: handle blank console arguments passed in. btrfs: don't force read-only after error in drop snapshot vfio/pci: fix memory leaks of eventfd ctx perf util: Fix memory leak of prefix_if_not_in perf kcore_copy: Fix module map when there are no modules loaded mtd: rawnand: omap_elm: Fix runtime PM imbalance on error ceph: fix potential race in ceph_check_caps mtd: parser: cmdline: Support MTD names containing one or more colons x86/speculation/mds: Mark mds_user_clear_cpu_buffers() __always_inline vfio/pci: Clear error and request eventfd ctx after releasing cifs: Fix double add page to memcg when cifs_readpages selftests/x86/syscall_nt: Clear weird flags after each test vfio/pci: fix racy on error and request eventfd ctx s390/init: add missing __init annotations i2c: core: Call i2c_acpi_install_space_handler() before i2c_acpi_register_devices() objtool: Fix noreturn detection for ignored functions ieee802154/adf7242: check status of adf7242_read_reg clocksource/drivers/h8300_timer8: Fix wrong return value in h8300_8timer_init() mwifiex: Increase AES key storage size to 256 bits batman-adv: bla: fix type misuse for backbone_gw hash indexing atm: eni: fix the missed pci_disable_device() for eni_init_one() batman-adv: mcast/TT: fix wrongly dropped or rerouted packets mac802154: tx: fix use-after-free batman-adv: Add missing include for in_interrupt() batman-adv: mcast: fix duplicate mcast packets in BLA backbone from mesh ALSA: asihpi: fix iounmap in error handler MIPS: Add the missing 'CPU_1074K' into __get_cpu_type() kprobes: Fix to check probe enabled before disarm_kprobe_ftrace() lib/string.c: implement stpcpy ata: define AC_ERR_OK ata: make qc_prep return ata_completion_errors ata: sata_mv, avoid trigerrable BUG_ON Linux 4.9.238 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: I799877db3bc49e473bbc023ab948cd241755beff
515 lines
13 KiB
C
515 lines
13 KiB
C
|
|
/*
|
|
* acard-ahci.c - ACard AHCI SATA support
|
|
*
|
|
* Maintained by: Tejun Heo <tj@kernel.org>
|
|
* Please ALWAYS copy linux-ide@vger.kernel.org
|
|
* on emails.
|
|
*
|
|
* Copyright 2010 Red Hat, Inc.
|
|
*
|
|
*
|
|
* 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 02139, USA.
|
|
*
|
|
*
|
|
* libata documentation is available via 'make {ps|pdf}docs',
|
|
* as Documentation/DocBook/libata.*
|
|
*
|
|
* AHCI hardware documentation:
|
|
* http://www.intel.com/technology/serialata/pdf/rev1_0.pdf
|
|
* http://www.intel.com/technology/serialata/pdf/rev1_1.pdf
|
|
*
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/module.h>
|
|
#include <linux/pci.h>
|
|
#include <linux/blkdev.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/dma-mapping.h>
|
|
#include <linux/device.h>
|
|
#include <linux/dmi.h>
|
|
#include <linux/gfp.h>
|
|
#include <scsi/scsi_host.h>
|
|
#include <scsi/scsi_cmnd.h>
|
|
#include <linux/libata.h>
|
|
#include "ahci.h"
|
|
|
|
#define DRV_NAME "acard-ahci"
|
|
#define DRV_VERSION "1.0"
|
|
|
|
/*
|
|
Received FIS structure limited to 80h.
|
|
*/
|
|
|
|
#define ACARD_AHCI_RX_FIS_SZ 128
|
|
|
|
enum {
|
|
AHCI_PCI_BAR = 5,
|
|
};
|
|
|
|
enum board_ids {
|
|
board_acard_ahci,
|
|
};
|
|
|
|
struct acard_sg {
|
|
__le32 addr;
|
|
__le32 addr_hi;
|
|
__le32 reserved;
|
|
__le32 size; /* bit 31 (EOT) max==0x10000 (64k) */
|
|
};
|
|
|
|
static enum ata_completion_errors acard_ahci_qc_prep(struct ata_queued_cmd *qc);
|
|
static bool acard_ahci_qc_fill_rtf(struct ata_queued_cmd *qc);
|
|
static int acard_ahci_port_start(struct ata_port *ap);
|
|
static int acard_ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
|
|
|
|
#ifdef CONFIG_PM_SLEEP
|
|
static int acard_ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
|
|
static int acard_ahci_pci_device_resume(struct pci_dev *pdev);
|
|
#endif
|
|
|
|
static struct scsi_host_template acard_ahci_sht = {
|
|
AHCI_SHT("acard-ahci"),
|
|
};
|
|
|
|
static struct ata_port_operations acard_ops = {
|
|
.inherits = &ahci_ops,
|
|
.qc_prep = acard_ahci_qc_prep,
|
|
.qc_fill_rtf = acard_ahci_qc_fill_rtf,
|
|
.port_start = acard_ahci_port_start,
|
|
};
|
|
|
|
#define AHCI_HFLAGS(flags) .private_data = (void *)(flags)
|
|
|
|
static const struct ata_port_info acard_ahci_port_info[] = {
|
|
[board_acard_ahci] =
|
|
{
|
|
AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ),
|
|
.flags = AHCI_FLAG_COMMON,
|
|
.pio_mask = ATA_PIO4,
|
|
.udma_mask = ATA_UDMA6,
|
|
.port_ops = &acard_ops,
|
|
},
|
|
};
|
|
|
|
static const struct pci_device_id acard_ahci_pci_tbl[] = {
|
|
/* ACard */
|
|
{ PCI_VDEVICE(ARTOP, 0x000d), board_acard_ahci }, /* ATP8620 */
|
|
|
|
{ } /* terminate list */
|
|
};
|
|
|
|
static struct pci_driver acard_ahci_pci_driver = {
|
|
.name = DRV_NAME,
|
|
.id_table = acard_ahci_pci_tbl,
|
|
.probe = acard_ahci_init_one,
|
|
.remove = ata_pci_remove_one,
|
|
#ifdef CONFIG_PM_SLEEP
|
|
.suspend = acard_ahci_pci_device_suspend,
|
|
.resume = acard_ahci_pci_device_resume,
|
|
#endif
|
|
};
|
|
|
|
#ifdef CONFIG_PM_SLEEP
|
|
static int acard_ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
|
|
{
|
|
struct ata_host *host = pci_get_drvdata(pdev);
|
|
struct ahci_host_priv *hpriv = host->private_data;
|
|
void __iomem *mmio = hpriv->mmio;
|
|
u32 ctl;
|
|
|
|
if (mesg.event & PM_EVENT_SUSPEND &&
|
|
hpriv->flags & AHCI_HFLAG_NO_SUSPEND) {
|
|
dev_err(&pdev->dev,
|
|
"BIOS update required for suspend/resume\n");
|
|
return -EIO;
|
|
}
|
|
|
|
if (mesg.event & PM_EVENT_SLEEP) {
|
|
/* AHCI spec rev1.1 section 8.3.3:
|
|
* Software must disable interrupts prior to requesting a
|
|
* transition of the HBA to D3 state.
|
|
*/
|
|
ctl = readl(mmio + HOST_CTL);
|
|
ctl &= ~HOST_IRQ_EN;
|
|
writel(ctl, mmio + HOST_CTL);
|
|
readl(mmio + HOST_CTL); /* flush */
|
|
}
|
|
|
|
return ata_pci_device_suspend(pdev, mesg);
|
|
}
|
|
|
|
static int acard_ahci_pci_device_resume(struct pci_dev *pdev)
|
|
{
|
|
struct ata_host *host = pci_get_drvdata(pdev);
|
|
int rc;
|
|
|
|
rc = ata_pci_device_do_resume(pdev);
|
|
if (rc)
|
|
return rc;
|
|
|
|
if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
|
|
rc = ahci_reset_controller(host);
|
|
if (rc)
|
|
return rc;
|
|
|
|
ahci_init_controller(host);
|
|
}
|
|
|
|
ata_host_resume(host);
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static int acard_ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac)
|
|
{
|
|
int rc;
|
|
|
|
if (using_dac &&
|
|
!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64))) {
|
|
rc = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
|
|
if (rc) {
|
|
rc = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
|
|
if (rc) {
|
|
dev_err(&pdev->dev,
|
|
"64-bit DMA enable failed\n");
|
|
return rc;
|
|
}
|
|
}
|
|
} else {
|
|
rc = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
|
|
if (rc) {
|
|
dev_err(&pdev->dev, "32-bit DMA enable failed\n");
|
|
return rc;
|
|
}
|
|
rc = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
|
|
if (rc) {
|
|
dev_err(&pdev->dev,
|
|
"32-bit consistent DMA enable failed\n");
|
|
return rc;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void acard_ahci_pci_print_info(struct ata_host *host)
|
|
{
|
|
struct pci_dev *pdev = to_pci_dev(host->dev);
|
|
u16 cc;
|
|
const char *scc_s;
|
|
|
|
pci_read_config_word(pdev, 0x0a, &cc);
|
|
if (cc == PCI_CLASS_STORAGE_IDE)
|
|
scc_s = "IDE";
|
|
else if (cc == PCI_CLASS_STORAGE_SATA)
|
|
scc_s = "SATA";
|
|
else if (cc == PCI_CLASS_STORAGE_RAID)
|
|
scc_s = "RAID";
|
|
else
|
|
scc_s = "unknown";
|
|
|
|
ahci_print_info(host, scc_s);
|
|
}
|
|
|
|
static unsigned int acard_ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl)
|
|
{
|
|
struct scatterlist *sg;
|
|
struct acard_sg *acard_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ;
|
|
unsigned int si, last_si = 0;
|
|
|
|
VPRINTK("ENTER\n");
|
|
|
|
/*
|
|
* Next, the S/G list.
|
|
*/
|
|
for_each_sg(qc->sg, sg, qc->n_elem, si) {
|
|
dma_addr_t addr = sg_dma_address(sg);
|
|
u32 sg_len = sg_dma_len(sg);
|
|
|
|
/*
|
|
* ACard note:
|
|
* We must set an end-of-table (EOT) bit,
|
|
* and the segment cannot exceed 64k (0x10000)
|
|
*/
|
|
acard_sg[si].addr = cpu_to_le32(addr & 0xffffffff);
|
|
acard_sg[si].addr_hi = cpu_to_le32((addr >> 16) >> 16);
|
|
acard_sg[si].size = cpu_to_le32(sg_len);
|
|
last_si = si;
|
|
}
|
|
|
|
acard_sg[last_si].size |= cpu_to_le32(1 << 31); /* set EOT */
|
|
|
|
return si;
|
|
}
|
|
|
|
static enum ata_completion_errors acard_ahci_qc_prep(struct ata_queued_cmd *qc)
|
|
{
|
|
struct ata_port *ap = qc->ap;
|
|
struct ahci_port_priv *pp = ap->private_data;
|
|
int is_atapi = ata_is_atapi(qc->tf.protocol);
|
|
void *cmd_tbl;
|
|
u32 opts;
|
|
const u32 cmd_fis_len = 5; /* five dwords */
|
|
unsigned int n_elem;
|
|
|
|
/*
|
|
* Fill in command table information. First, the header,
|
|
* a SATA Register - Host to Device command FIS.
|
|
*/
|
|
cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
|
|
|
|
ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, cmd_tbl);
|
|
if (is_atapi) {
|
|
memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
|
|
memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
|
|
}
|
|
|
|
n_elem = 0;
|
|
if (qc->flags & ATA_QCFLAG_DMAMAP)
|
|
n_elem = acard_ahci_fill_sg(qc, cmd_tbl);
|
|
|
|
/*
|
|
* Fill in command slot information.
|
|
*
|
|
* ACard note: prd table length not filled in
|
|
*/
|
|
opts = cmd_fis_len | (qc->dev->link->pmp << 12);
|
|
if (qc->tf.flags & ATA_TFLAG_WRITE)
|
|
opts |= AHCI_CMD_WRITE;
|
|
if (is_atapi)
|
|
opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH;
|
|
|
|
ahci_fill_cmd_slot(pp, qc->tag, opts);
|
|
|
|
return AC_ERR_OK;
|
|
}
|
|
|
|
static bool acard_ahci_qc_fill_rtf(struct ata_queued_cmd *qc)
|
|
{
|
|
struct ahci_port_priv *pp = qc->ap->private_data;
|
|
u8 *rx_fis = pp->rx_fis;
|
|
|
|
if (pp->fbs_enabled)
|
|
rx_fis += qc->dev->link->pmp * ACARD_AHCI_RX_FIS_SZ;
|
|
|
|
/*
|
|
* After a successful execution of an ATA PIO data-in command,
|
|
* the device doesn't send D2H Reg FIS to update the TF and
|
|
* the host should take TF and E_Status from the preceding PIO
|
|
* Setup FIS.
|
|
*/
|
|
if (qc->tf.protocol == ATA_PROT_PIO && qc->dma_dir == DMA_FROM_DEVICE &&
|
|
!(qc->flags & ATA_QCFLAG_FAILED)) {
|
|
ata_tf_from_fis(rx_fis + RX_FIS_PIO_SETUP, &qc->result_tf);
|
|
qc->result_tf.command = (rx_fis + RX_FIS_PIO_SETUP)[15];
|
|
} else
|
|
ata_tf_from_fis(rx_fis + RX_FIS_D2H_REG, &qc->result_tf);
|
|
|
|
return true;
|
|
}
|
|
|
|
static int acard_ahci_port_start(struct ata_port *ap)
|
|
{
|
|
struct ahci_host_priv *hpriv = ap->host->private_data;
|
|
struct device *dev = ap->host->dev;
|
|
struct ahci_port_priv *pp;
|
|
void *mem;
|
|
dma_addr_t mem_dma;
|
|
size_t dma_sz, rx_fis_sz;
|
|
|
|
pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
|
|
if (!pp)
|
|
return -ENOMEM;
|
|
|
|
/* check FBS capability */
|
|
if ((hpriv->cap & HOST_CAP_FBS) && sata_pmp_supported(ap)) {
|
|
void __iomem *port_mmio = ahci_port_base(ap);
|
|
u32 cmd = readl(port_mmio + PORT_CMD);
|
|
if (cmd & PORT_CMD_FBSCP)
|
|
pp->fbs_supported = true;
|
|
else if (hpriv->flags & AHCI_HFLAG_YES_FBS) {
|
|
dev_info(dev, "port %d can do FBS, forcing FBSCP\n",
|
|
ap->port_no);
|
|
pp->fbs_supported = true;
|
|
} else
|
|
dev_warn(dev, "port %d is not capable of FBS\n",
|
|
ap->port_no);
|
|
}
|
|
|
|
if (pp->fbs_supported) {
|
|
dma_sz = AHCI_PORT_PRIV_FBS_DMA_SZ;
|
|
rx_fis_sz = ACARD_AHCI_RX_FIS_SZ * 16;
|
|
} else {
|
|
dma_sz = AHCI_PORT_PRIV_DMA_SZ;
|
|
rx_fis_sz = ACARD_AHCI_RX_FIS_SZ;
|
|
}
|
|
|
|
mem = dmam_alloc_coherent(dev, dma_sz, &mem_dma, GFP_KERNEL);
|
|
if (!mem)
|
|
return -ENOMEM;
|
|
memset(mem, 0, dma_sz);
|
|
|
|
/*
|
|
* First item in chunk of DMA memory: 32-slot command table,
|
|
* 32 bytes each in size
|
|
*/
|
|
pp->cmd_slot = mem;
|
|
pp->cmd_slot_dma = mem_dma;
|
|
|
|
mem += AHCI_CMD_SLOT_SZ;
|
|
mem_dma += AHCI_CMD_SLOT_SZ;
|
|
|
|
/*
|
|
* Second item: Received-FIS area
|
|
*/
|
|
pp->rx_fis = mem;
|
|
pp->rx_fis_dma = mem_dma;
|
|
|
|
mem += rx_fis_sz;
|
|
mem_dma += rx_fis_sz;
|
|
|
|
/*
|
|
* Third item: data area for storing a single command
|
|
* and its scatter-gather table
|
|
*/
|
|
pp->cmd_tbl = mem;
|
|
pp->cmd_tbl_dma = mem_dma;
|
|
|
|
/*
|
|
* Save off initial list of interrupts to be enabled.
|
|
* This could be changed later
|
|
*/
|
|
pp->intr_mask = DEF_PORT_IRQ;
|
|
|
|
ap->private_data = pp;
|
|
|
|
/* engage engines, captain */
|
|
return ahci_port_resume(ap);
|
|
}
|
|
|
|
static int acard_ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|
{
|
|
unsigned int board_id = ent->driver_data;
|
|
struct ata_port_info pi = acard_ahci_port_info[board_id];
|
|
const struct ata_port_info *ppi[] = { &pi, NULL };
|
|
struct device *dev = &pdev->dev;
|
|
struct ahci_host_priv *hpriv;
|
|
struct ata_host *host;
|
|
int n_ports, i, rc;
|
|
|
|
VPRINTK("ENTER\n");
|
|
|
|
WARN_ON((int)ATA_MAX_QUEUE > AHCI_MAX_CMDS);
|
|
|
|
ata_print_version_once(&pdev->dev, DRV_VERSION);
|
|
|
|
/* acquire resources */
|
|
rc = pcim_enable_device(pdev);
|
|
if (rc)
|
|
return rc;
|
|
|
|
/* AHCI controllers often implement SFF compatible interface.
|
|
* Grab all PCI BARs just in case.
|
|
*/
|
|
rc = pcim_iomap_regions_request_all(pdev, 1 << AHCI_PCI_BAR, DRV_NAME);
|
|
if (rc == -EBUSY)
|
|
pcim_pin_device(pdev);
|
|
if (rc)
|
|
return rc;
|
|
|
|
hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
|
|
if (!hpriv)
|
|
return -ENOMEM;
|
|
|
|
hpriv->irq = pdev->irq;
|
|
hpriv->flags |= (unsigned long)pi.private_data;
|
|
|
|
if (!(hpriv->flags & AHCI_HFLAG_NO_MSI))
|
|
pci_enable_msi(pdev);
|
|
|
|
hpriv->mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
|
|
|
|
/* save initial config */
|
|
ahci_save_initial_config(&pdev->dev, hpriv);
|
|
|
|
/* prepare host */
|
|
if (hpriv->cap & HOST_CAP_NCQ)
|
|
pi.flags |= ATA_FLAG_NCQ;
|
|
|
|
if (hpriv->cap & HOST_CAP_PMP)
|
|
pi.flags |= ATA_FLAG_PMP;
|
|
|
|
ahci_set_em_messages(hpriv, &pi);
|
|
|
|
/* CAP.NP sometimes indicate the index of the last enabled
|
|
* port, at other times, that of the last possible port, so
|
|
* determining the maximum port number requires looking at
|
|
* both CAP.NP and port_map.
|
|
*/
|
|
n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
|
|
|
|
host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
|
|
if (!host)
|
|
return -ENOMEM;
|
|
host->private_data = hpriv;
|
|
|
|
if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
|
|
host->flags |= ATA_HOST_PARALLEL_SCAN;
|
|
else
|
|
printk(KERN_INFO "ahci: SSS flag set, parallel bus scan disabled\n");
|
|
|
|
for (i = 0; i < host->n_ports; i++) {
|
|
struct ata_port *ap = host->ports[i];
|
|
|
|
ata_port_pbar_desc(ap, AHCI_PCI_BAR, -1, "abar");
|
|
ata_port_pbar_desc(ap, AHCI_PCI_BAR,
|
|
0x100 + ap->port_no * 0x80, "port");
|
|
|
|
/* set initial link pm policy */
|
|
/*
|
|
ap->pm_policy = NOT_AVAILABLE;
|
|
*/
|
|
/* disabled/not-implemented port */
|
|
if (!(hpriv->port_map & (1 << i)))
|
|
ap->ops = &ata_dummy_port_ops;
|
|
}
|
|
|
|
/* initialize adapter */
|
|
rc = acard_ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64);
|
|
if (rc)
|
|
return rc;
|
|
|
|
rc = ahci_reset_controller(host);
|
|
if (rc)
|
|
return rc;
|
|
|
|
ahci_init_controller(host);
|
|
acard_ahci_pci_print_info(host);
|
|
|
|
pci_set_master(pdev);
|
|
return ahci_host_activate(host, &acard_ahci_sht);
|
|
}
|
|
|
|
module_pci_driver(acard_ahci_pci_driver);
|
|
|
|
MODULE_AUTHOR("Jeff Garzik");
|
|
MODULE_DESCRIPTION("ACard AHCI SATA low-level driver");
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_DEVICE_TABLE(pci, acard_ahci_pci_tbl);
|
|
MODULE_VERSION(DRV_VERSION);
|