Commit bde4f8fa authored by Linus Torvalds's avatar Linus Torvalds

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
parents 84841384 c40e7cb8
...@@ -49,6 +49,10 @@ ...@@ -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[] = { ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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;
if (event == 0 || event == 1) { int wait = 0;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(ap->lock, flags);
ata_ehi_clear_desc(ehi); if (!ap)
ata_ehi_push_desc(ehi, "ACPI event"); ap = dev->link->ap;
ata_ehi_hotplugged(ehi); ehi = &ap->link.eh_info;
ata_port_freeze(ap);
spin_unlock_irqrestore(ap->lock, flags); spin_lock_irqsave(ap->lock, flags);
switch (event) {
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) ...@@ -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) ...@@ -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); ...@@ -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;
......
...@@ -297,6 +297,31 @@ int pcim_iomap_regions(struct pci_dev *pdev, u16 mask, const char *name) ...@@ -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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment