Merge branch 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/libata-dev
* 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/libata-dev: ahci: Add Marvell 6121 SATA support pata_ali: use atapi_cmd_type() to determine cmd type instead of transfer size ahci: implement skip_host_reset parameter ahci: request all PCI BARs devres: implement pcim_iomap_regions_request_all() libata-acpi: improve dock event handling
This commit is contained in:
@@ -49,6 +49,10 @@
|
|||||||
#define DRV_NAME "ahci"
|
#define DRV_NAME "ahci"
|
||||||
#define DRV_VERSION "3.0"
|
#define DRV_VERSION "3.0"
|
||||||
|
|
||||||
|
static int ahci_skip_host_reset;
|
||||||
|
module_param_named(skip_host_reset, ahci_skip_host_reset, int, 0444);
|
||||||
|
MODULE_PARM_DESC(skip_host_reset, "skip global host reset (0=don't skip, 1=skip)");
|
||||||
|
|
||||||
static int ahci_enable_alpm(struct ata_port *ap,
|
static int ahci_enable_alpm(struct ata_port *ap,
|
||||||
enum link_pm policy);
|
enum link_pm policy);
|
||||||
static void ahci_disable_alpm(struct ata_port *ap);
|
static void ahci_disable_alpm(struct ata_port *ap);
|
||||||
@@ -587,6 +591,7 @@ static const struct pci_device_id ahci_pci_tbl[] = {
|
|||||||
|
|
||||||
/* Marvell */
|
/* Marvell */
|
||||||
{ PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv }, /* 6145 */
|
{ PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv }, /* 6145 */
|
||||||
|
{ PCI_VDEVICE(MARVELL, 0x6121), board_ahci_mv }, /* 6121 */
|
||||||
|
|
||||||
/* Generic, PCI class code for AHCI */
|
/* Generic, PCI class code for AHCI */
|
||||||
{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
|
{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
|
||||||
@@ -661,6 +666,7 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
|
|||||||
void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
|
void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
|
||||||
u32 cap, port_map;
|
u32 cap, port_map;
|
||||||
int i;
|
int i;
|
||||||
|
int mv;
|
||||||
|
|
||||||
/* make sure AHCI mode is enabled before accessing CAP */
|
/* make sure AHCI mode is enabled before accessing CAP */
|
||||||
ahci_enable_ahci(mmio);
|
ahci_enable_ahci(mmio);
|
||||||
@@ -696,12 +702,16 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
|
|||||||
* presence register, as bit 4 (counting from 0)
|
* presence register, as bit 4 (counting from 0)
|
||||||
*/
|
*/
|
||||||
if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
|
if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
|
||||||
|
if (pdev->device == 0x6121)
|
||||||
|
mv = 0x3;
|
||||||
|
else
|
||||||
|
mv = 0xf;
|
||||||
dev_printk(KERN_ERR, &pdev->dev,
|
dev_printk(KERN_ERR, &pdev->dev,
|
||||||
"MV_AHCI HACK: port_map %x -> %x\n",
|
"MV_AHCI HACK: port_map %x -> %x\n",
|
||||||
hpriv->port_map,
|
port_map,
|
||||||
hpriv->port_map & 0xf);
|
port_map & mv);
|
||||||
|
|
||||||
port_map &= 0xf;
|
port_map &= mv;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* cross check port_map and cap.n_ports */
|
/* cross check port_map and cap.n_ports */
|
||||||
@@ -1088,29 +1098,35 @@ static int ahci_reset_controller(struct ata_host *host)
|
|||||||
ahci_enable_ahci(mmio);
|
ahci_enable_ahci(mmio);
|
||||||
|
|
||||||
/* global controller reset */
|
/* global controller reset */
|
||||||
tmp = readl(mmio + HOST_CTL);
|
if (!ahci_skip_host_reset) {
|
||||||
if ((tmp & HOST_RESET) == 0) {
|
tmp = readl(mmio + HOST_CTL);
|
||||||
writel(tmp | HOST_RESET, mmio + HOST_CTL);
|
if ((tmp & HOST_RESET) == 0) {
|
||||||
readl(mmio + HOST_CTL); /* flush */
|
writel(tmp | HOST_RESET, mmio + HOST_CTL);
|
||||||
}
|
readl(mmio + HOST_CTL); /* flush */
|
||||||
|
}
|
||||||
|
|
||||||
/* reset must complete within 1 second, or
|
/* reset must complete within 1 second, or
|
||||||
* the hardware should be considered fried.
|
* the hardware should be considered fried.
|
||||||
*/
|
*/
|
||||||
ssleep(1);
|
ssleep(1);
|
||||||
|
|
||||||
tmp = readl(mmio + HOST_CTL);
|
tmp = readl(mmio + HOST_CTL);
|
||||||
if (tmp & HOST_RESET) {
|
if (tmp & HOST_RESET) {
|
||||||
dev_printk(KERN_ERR, host->dev,
|
dev_printk(KERN_ERR, host->dev,
|
||||||
"controller reset failed (0x%x)\n", tmp);
|
"controller reset failed (0x%x)\n", tmp);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* turn on AHCI mode */
|
/* turn on AHCI mode */
|
||||||
ahci_enable_ahci(mmio);
|
ahci_enable_ahci(mmio);
|
||||||
|
|
||||||
/* some registers might be cleared on reset. restore initial values */
|
/* Some registers might be cleared on reset. Restore
|
||||||
ahci_restore_initial_config(host);
|
* initial values.
|
||||||
|
*/
|
||||||
|
ahci_restore_initial_config(host);
|
||||||
|
} else
|
||||||
|
dev_printk(KERN_INFO, host->dev,
|
||||||
|
"skipping global host reset\n");
|
||||||
|
|
||||||
if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
|
if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
|
||||||
u16 tmp16;
|
u16 tmp16;
|
||||||
@@ -1162,9 +1178,14 @@ static void ahci_init_controller(struct ata_host *host)
|
|||||||
int i;
|
int i;
|
||||||
void __iomem *port_mmio;
|
void __iomem *port_mmio;
|
||||||
u32 tmp;
|
u32 tmp;
|
||||||
|
int mv;
|
||||||
|
|
||||||
if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
|
if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
|
||||||
port_mmio = __ahci_port_base(host, 4);
|
if (pdev->device == 0x6121)
|
||||||
|
mv = 2;
|
||||||
|
else
|
||||||
|
mv = 4;
|
||||||
|
port_mmio = __ahci_port_base(host, mv);
|
||||||
|
|
||||||
writel(0, port_mmio + PORT_IRQ_MASK);
|
writel(0, port_mmio + PORT_IRQ_MASK);
|
||||||
|
|
||||||
@@ -2241,7 +2262,10 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
rc = pcim_iomap_regions(pdev, 1 << AHCI_PCI_BAR, DRV_NAME);
|
/* 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)
|
if (rc == -EBUSY)
|
||||||
pcim_pin_device(pdev);
|
pcim_pin_device(pdev);
|
||||||
if (rc)
|
if (rc)
|
||||||
|
@@ -118,45 +118,77 @@ static void ata_acpi_associate_ide_port(struct ata_port *ap)
|
|||||||
ap->pflags |= ATA_PFLAG_INIT_GTM_VALID;
|
ap->pflags |= ATA_PFLAG_INIT_GTM_VALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ata_acpi_handle_hotplug(struct ata_port *ap, struct kobject *kobj,
|
static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev,
|
||||||
u32 event)
|
u32 event)
|
||||||
{
|
{
|
||||||
char event_string[12];
|
char event_string[12];
|
||||||
char *envp[] = { event_string, NULL };
|
char *envp[] = { event_string, NULL };
|
||||||
struct ata_eh_info *ehi = &ap->link.eh_info;
|
struct ata_eh_info *ehi;
|
||||||
|
struct kobject *kobj = NULL;
|
||||||
|
int wait = 0;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
if (event == 0 || event == 1) {
|
if (!ap)
|
||||||
unsigned long flags;
|
ap = dev->link->ap;
|
||||||
spin_lock_irqsave(ap->lock, flags);
|
ehi = &ap->link.eh_info;
|
||||||
ata_ehi_clear_desc(ehi);
|
|
||||||
ata_ehi_push_desc(ehi, "ACPI event");
|
spin_lock_irqsave(ap->lock, flags);
|
||||||
ata_ehi_hotplugged(ehi);
|
|
||||||
ata_port_freeze(ap);
|
switch (event) {
|
||||||
spin_unlock_irqrestore(ap->lock, flags);
|
case ACPI_NOTIFY_BUS_CHECK:
|
||||||
|
case ACPI_NOTIFY_DEVICE_CHECK:
|
||||||
|
ata_ehi_push_desc(ehi, "ACPI event");
|
||||||
|
ata_ehi_hotplugged(ehi);
|
||||||
|
ata_port_freeze(ap);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ACPI_NOTIFY_EJECT_REQUEST:
|
||||||
|
ata_ehi_push_desc(ehi, "ACPI event");
|
||||||
|
if (dev)
|
||||||
|
dev->flags |= ATA_DFLAG_DETACH;
|
||||||
|
else {
|
||||||
|
struct ata_link *tlink;
|
||||||
|
struct ata_device *tdev;
|
||||||
|
|
||||||
|
ata_port_for_each_link(tlink, ap)
|
||||||
|
ata_link_for_each_dev(tdev, tlink)
|
||||||
|
tdev->flags |= ATA_DFLAG_DETACH;
|
||||||
|
}
|
||||||
|
|
||||||
|
ata_port_schedule_eh(ap);
|
||||||
|
wait = 1;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dev) {
|
||||||
|
if (dev->sdev)
|
||||||
|
kobj = &dev->sdev->sdev_gendev.kobj;
|
||||||
|
} else
|
||||||
|
kobj = &ap->dev->kobj;
|
||||||
|
|
||||||
if (kobj) {
|
if (kobj) {
|
||||||
sprintf(event_string, "BAY_EVENT=%d", event);
|
sprintf(event_string, "BAY_EVENT=%d", event);
|
||||||
kobject_uevent_env(kobj, KOBJ_CHANGE, envp);
|
kobject_uevent_env(kobj, KOBJ_CHANGE, envp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(ap->lock, flags);
|
||||||
|
|
||||||
|
if (wait)
|
||||||
|
ata_port_wait_eh(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ata_acpi_dev_notify(acpi_handle handle, u32 event, void *data)
|
static void ata_acpi_dev_notify(acpi_handle handle, u32 event, void *data)
|
||||||
{
|
{
|
||||||
struct ata_device *dev = data;
|
struct ata_device *dev = data;
|
||||||
struct kobject *kobj = NULL;
|
|
||||||
|
|
||||||
if (dev->sdev)
|
ata_acpi_handle_hotplug(NULL, dev, event);
|
||||||
kobj = &dev->sdev->sdev_gendev.kobj;
|
|
||||||
|
|
||||||
ata_acpi_handle_hotplug(dev->link->ap, kobj, event);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ata_acpi_ap_notify(acpi_handle handle, u32 event, void *data)
|
static void ata_acpi_ap_notify(acpi_handle handle, u32 event, void *data)
|
||||||
{
|
{
|
||||||
struct ata_port *ap = data;
|
struct ata_port *ap = data;
|
||||||
|
|
||||||
ata_acpi_handle_hotplug(ap, &ap->dev->kobj, event);
|
ata_acpi_handle_hotplug(ap, NULL, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -191,20 +223,30 @@ void ata_acpi_associate(struct ata_host *host)
|
|||||||
else
|
else
|
||||||
ata_acpi_associate_ide_port(ap);
|
ata_acpi_associate_ide_port(ap);
|
||||||
|
|
||||||
if (ap->acpi_handle)
|
if (ap->acpi_handle) {
|
||||||
acpi_install_notify_handler (ap->acpi_handle,
|
acpi_install_notify_handler(ap->acpi_handle,
|
||||||
ACPI_SYSTEM_NOTIFY,
|
ACPI_SYSTEM_NOTIFY,
|
||||||
ata_acpi_ap_notify,
|
ata_acpi_ap_notify, ap);
|
||||||
ap);
|
#if defined(CONFIG_ACPI_DOCK) || defined(CONFIG_ACPI_DOCK_MODULE)
|
||||||
|
/* we might be on a docking station */
|
||||||
|
register_hotplug_dock_device(ap->acpi_handle,
|
||||||
|
ata_acpi_ap_notify, ap);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
for (j = 0; j < ata_link_max_devices(&ap->link); j++) {
|
for (j = 0; j < ata_link_max_devices(&ap->link); j++) {
|
||||||
struct ata_device *dev = &ap->link.device[j];
|
struct ata_device *dev = &ap->link.device[j];
|
||||||
|
|
||||||
if (dev->acpi_handle)
|
if (dev->acpi_handle) {
|
||||||
acpi_install_notify_handler (dev->acpi_handle,
|
acpi_install_notify_handler(dev->acpi_handle,
|
||||||
ACPI_SYSTEM_NOTIFY,
|
ACPI_SYSTEM_NOTIFY,
|
||||||
ata_acpi_dev_notify,
|
ata_acpi_dev_notify, dev);
|
||||||
dev);
|
#if defined(CONFIG_ACPI_DOCK) || defined(CONFIG_ACPI_DOCK_MODULE)
|
||||||
|
/* we might be on a docking station */
|
||||||
|
register_hotplug_dock_device(dev->acpi_handle,
|
||||||
|
ata_acpi_dev_notify, dev);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -295,7 +295,7 @@ static void ali_lock_sectors(struct ata_device *adev)
|
|||||||
static int ali_check_atapi_dma(struct ata_queued_cmd *qc)
|
static int ali_check_atapi_dma(struct ata_queued_cmd *qc)
|
||||||
{
|
{
|
||||||
/* If its not a media command, its not worth it */
|
/* If its not a media command, its not worth it */
|
||||||
if (qc->nbytes < 2048)
|
if (atapi_cmd_type(qc->cdb[0]) == ATAPI_MISC)
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@@ -1045,6 +1045,8 @@ void __iomem *pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen);
|
|||||||
void pcim_iounmap(struct pci_dev *pdev, void __iomem *addr);
|
void pcim_iounmap(struct pci_dev *pdev, void __iomem *addr);
|
||||||
void __iomem * const *pcim_iomap_table(struct pci_dev *pdev);
|
void __iomem * const *pcim_iomap_table(struct pci_dev *pdev);
|
||||||
int pcim_iomap_regions(struct pci_dev *pdev, u16 mask, const char *name);
|
int pcim_iomap_regions(struct pci_dev *pdev, u16 mask, const char *name);
|
||||||
|
int pcim_iomap_regions_request_all(struct pci_dev *pdev, u16 mask,
|
||||||
|
const char *name);
|
||||||
void pcim_iounmap_regions(struct pci_dev *pdev, u16 mask);
|
void pcim_iounmap_regions(struct pci_dev *pdev, u16 mask);
|
||||||
|
|
||||||
extern int pci_pci_problems;
|
extern int pci_pci_problems;
|
||||||
|
25
lib/devres.c
25
lib/devres.c
@@ -297,6 +297,31 @@ int pcim_iomap_regions(struct pci_dev *pdev, u16 mask, const char *name)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(pcim_iomap_regions);
|
EXPORT_SYMBOL(pcim_iomap_regions);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pcim_iomap_regions_request_all - Request all BARs and iomap specified ones
|
||||||
|
* @pdev: PCI device to map IO resources for
|
||||||
|
* @mask: Mask of BARs to iomap
|
||||||
|
* @name: Name used when requesting regions
|
||||||
|
*
|
||||||
|
* Request all PCI BARs and iomap regions specified by @mask.
|
||||||
|
*/
|
||||||
|
int pcim_iomap_regions_request_all(struct pci_dev *pdev, u16 mask,
|
||||||
|
const char *name)
|
||||||
|
{
|
||||||
|
int request_mask = ((1 << 6) - 1) & ~mask;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = pci_request_selected_regions(pdev, request_mask, name);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
rc = pcim_iomap_regions(pdev, mask, name);
|
||||||
|
if (rc)
|
||||||
|
pci_release_selected_regions(pdev, request_mask);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(pcim_iomap_regions_request_all);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pcim_iounmap_regions - Unmap and release PCI BARs
|
* pcim_iounmap_regions - Unmap and release PCI BARs
|
||||||
* @pdev: PCI device to map IO resources for
|
* @pdev: PCI device to map IO resources for
|
||||||
|
Reference in New Issue
Block a user