Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 246dd412 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/libata-dev:
  libata-sff: Fix oops reported in kerneloops.org for pnp devices with no ctl
  libata: kill unused constants
  sata_mv: PHY_MODE4 cleanups
  [libata] ata_piix: more acer short cable quirks
  [libata] ACPI: Properly handle bay devices in dock stations
parents 2d9b57fb a57c1bad
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -574,6 +574,8 @@ static const struct ich_laptop ich_laptop[] = {
	{ 0x27DF, 0x1043, 0x1267 },	/* ICH7 on Asus W5F */
	{ 0x27DF, 0x103C, 0x30A1 },	/* ICH7 on HP Compaq nc2400 */
	{ 0x24CA, 0x1025, 0x0061 },	/* ICH4 on ACER Aspire 2023WLMi */
	{ 0x24CA, 0x1025, 0x003d },	/* ICH4 on ACER TM290 */
	{ 0x266F, 0x1025, 0x0066 },	/* ICH6 on ACER Aspire 1694WLMi */
	{ 0x2653, 0x1043, 0x82D8 },	/* ICH6M on Asus Eee 701 */
	/* end marker */
	{ 0, }
+114 −51
Original line number Diff line number Diff line
@@ -118,12 +118,62 @@ static void ata_acpi_associate_ide_port(struct ata_port *ap)
		ap->pflags |= ATA_PFLAG_INIT_GTM_VALID;
}

static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device
				    *dev, u32 event)
static void ata_acpi_eject_device(acpi_handle handle)
{
	struct acpi_object_list arg_list;
	union acpi_object arg;

	arg_list.count = 1;
	arg_list.pointer = &arg;
	arg.type = ACPI_TYPE_INTEGER;
	arg.integer.value = 1;

	if (ACPI_FAILURE(acpi_evaluate_object(handle, "_EJ0",
					      &arg_list, NULL)))
		printk(KERN_ERR "Failed to evaluate _EJ0!\n");
}

/* @ap and @dev are the same as ata_acpi_handle_hotplug() */
static void ata_acpi_detach_device(struct ata_port *ap, struct ata_device *dev)
{
	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);
}

/**
 * ata_acpi_handle_hotplug - ACPI event handler backend
 * @ap: ATA port ACPI event occurred
 * @dev: ATA device ACPI event occurred (can be NULL)
 * @event: ACPI event which occurred
 * @is_dock_event: boolean indicating whether the event was a dock one
 *
 * All ACPI bay / device realted events end up in this function.  If
 * the event is port-wide @dev is NULL.  If the event is specific to a
 * device, @dev points to it.
 *
 * Hotplug (as opposed to unplug) notification is always handled as
 * port-wide while unplug only kills the target device on device-wide
 * event.
 *
 * LOCKING:
 * ACPI notify handler context.  May sleep.
 */
static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev,
				    u32 event, int is_dock_event)
{
	char event_string[12];
	char *envp[] = { event_string, NULL };
	struct ata_eh_info *ehi;
	struct ata_eh_info *ehi = &ap->link.eh_info;
	struct kobject *kobj = NULL;
	int wait = 0;
	unsigned long flags;
@@ -131,87 +181,100 @@ static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device
	unsigned long sta;
	acpi_status status;

	if (!ap)
		ap = dev->link->ap;
	ehi = &ap->link.eh_info;

	spin_lock_irqsave(ap->lock, flags);

	if (dev)
	if (dev) {
		if (dev->sdev)
			kobj = &dev->sdev->sdev_gendev.kobj;
		handle = dev->acpi_handle;
	else
	} else {
		kobj = &ap->dev->kobj;
		handle = ap->acpi_handle;
	}

	status = acpi_get_handle(handle, "_EJ0", &tmphandle);
	if (ACPI_FAILURE(status)) {
		/* This device is not ejectable */
		spin_unlock_irqrestore(ap->lock, flags);
	if (ACPI_FAILURE(status))
		/* This device does not support hotplug */
		return;
	}

	status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
	if (ACPI_FAILURE(status)) {
		printk ("Unable to determine bay status\n");
		spin_unlock_irqrestore(ap->lock, flags);
		return;
	}
	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");
		if (!sta) {
                /* Device has been unplugged */
			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;
					}
				}
		status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
		if (ACPI_FAILURE(status)) {
			ata_port_printk(ap, KERN_ERR,
				"acpi: failed to determine bay status (0x%x)\n",
				status);
			break;
		}
			ata_port_schedule_eh(ap);
			wait = 1;
		} else {

		if (sta) {
			ata_ehi_hotplugged(ehi);
			ata_port_freeze(ap);
		} else {
			/* The device has gone - unplug it */
			ata_acpi_detach_device(ap, dev);
			wait = 1;
		}
		break;
	case ACPI_NOTIFY_EJECT_REQUEST:
		ata_ehi_push_desc(ehi, "ACPI event");

		if (!is_dock_event)
			break;

		/* undock event - immediate unplug */
		ata_acpi_detach_device(ap, dev);
		wait = 1;
		break;
	}

	/* make sure kobj doesn't go away while ap->lock is released */
	kobject_get(kobj);

	spin_unlock_irqrestore(ap->lock, flags);

	if (wait)
	if (wait) {
		ata_port_wait_eh(ap);
		ata_acpi_eject_device(handle);
	}

	if (dev) {
		if (dev->sdev)
			kobj = &dev->sdev->sdev_gendev.kobj;
	} else
		kobj = &ap->dev->kobj;

	if (kobj) {
	if (kobj && !is_dock_event) {
		sprintf(event_string, "BAY_EVENT=%d", event);
		kobject_uevent_env(kobj, KOBJ_CHANGE, envp);
	}

	kobject_put(kobj);
}

static void ata_acpi_dev_notify_dock(acpi_handle handle, u32 event, void *data)
{
	struct ata_device *dev = data;

	ata_acpi_handle_hotplug(dev->link->ap, dev, event, 1);
}

static void ata_acpi_ap_notify_dock(acpi_handle handle, u32 event, void *data)
{
	struct ata_port *ap = data;

	ata_acpi_handle_hotplug(ap, NULL, event, 1);
}

static void ata_acpi_dev_notify(acpi_handle handle, u32 event, void *data)
{
	struct ata_device *dev = data;

	ata_acpi_handle_hotplug(NULL, dev, event);
	ata_acpi_handle_hotplug(dev->link->ap, dev, event, 0);
}

static void ata_acpi_ap_notify(acpi_handle handle, u32 event, void *data)
{
	struct ata_port *ap = data;

	ata_acpi_handle_hotplug(ap, NULL, event);
	ata_acpi_handle_hotplug(ap, NULL, event, 0);
}

/**
@@ -252,7 +315,7 @@ void ata_acpi_associate(struct ata_host *host)
						    ata_acpi_ap_notify, ap);
			/* we might be on a docking station */
			register_hotplug_dock_device(ap->acpi_handle,
						     ata_acpi_ap_notify, ap);
					     ata_acpi_ap_notify_dock, ap);
		}

		for (j = 0; j < ata_link_max_devices(&ap->link); j++) {
@@ -264,7 +327,7 @@ void ata_acpi_associate(struct ata_host *host)
						ata_acpi_dev_notify, dev);
				/* we might be on a docking station */
				register_hotplug_dock_device(dev->acpi_handle,
						ata_acpi_dev_notify, dev);
					     ata_acpi_dev_notify_dock, dev);
			}
		}
	}
+100 −15
Original line number Diff line number Diff line
@@ -247,7 +247,7 @@ u8 ata_sff_check_status(struct ata_port *ap)
 *	LOCKING:
 *	Inherited from caller.
 */
u8 ata_sff_altstatus(struct ata_port *ap)
static u8 ata_sff_altstatus(struct ata_port *ap)
{
	if (ap->ops->sff_check_altstatus)
		return ap->ops->sff_check_altstatus(ap);
@@ -255,6 +255,93 @@ u8 ata_sff_altstatus(struct ata_port *ap)
	return ioread8(ap->ioaddr.altstatus_addr);
}

/**
 *	ata_sff_irq_status - Check if the device is busy
 *	@ap: port where the device is
 *
 *	Determine if the port is currently busy. Uses altstatus
 *	if available in order to avoid clearing shared IRQ status
 *	when finding an IRQ source. Non ctl capable devices don't
 *	share interrupt lines fortunately for us.
 *
 *	LOCKING:
 *	Inherited from caller.
 */
static u8 ata_sff_irq_status(struct ata_port *ap)
{
	u8 status;

	if (ap->ops->sff_check_altstatus || ap->ioaddr.altstatus_addr) {
		status = ata_sff_altstatus(ap);
		/* Not us: We are busy */
		if (status & ATA_BUSY)
		    	return status;
	}
	/* Clear INTRQ latch */
	status = ata_sff_check_status(ap);
	return status;
}

/**
 *	ata_sff_sync - Flush writes
 *	@ap: Port to wait for.
 *
 *	CAUTION:
 *	If we have an mmio device with no ctl and no altstatus
 *	method this will fail. No such devices are known to exist.
 *
 *	LOCKING:
 *	Inherited from caller.
 */

static void ata_sff_sync(struct ata_port *ap)
{
	if (ap->ops->sff_check_altstatus)
		ap->ops->sff_check_altstatus(ap);
	else if (ap->ioaddr.altstatus_addr)
		ioread8(ap->ioaddr.altstatus_addr);
}

/**
 *	ata_sff_pause		-	Flush writes and wait 400nS
 *	@ap: Port to pause for.
 *
 *	CAUTION:
 *	If we have an mmio device with no ctl and no altstatus
 *	method this will fail. No such devices are known to exist.
 *
 *	LOCKING:
 *	Inherited from caller.
 */

void ata_sff_pause(struct ata_port *ap)
{
	ata_sff_sync(ap);
	ndelay(400);
}

/**
 *	ata_sff_dma_pause	-	Pause before commencing DMA
 *	@ap: Port to pause for.
 *
 *	Perform I/O fencing and ensure sufficient cycle delays occur
 *	for the HDMA1:0 transition
 */
 
void ata_sff_dma_pause(struct ata_port *ap)
{
	if (ap->ops->sff_check_altstatus || ap->ioaddr.altstatus_addr) {
		/* An altstatus read will cause the needed delay without
		   messing up the IRQ status */
		ata_sff_altstatus(ap);
		return;
	}
	/* There are no DMA controllers without ctl. BUG here to ensure
	   we never violate the HDMA1:0 transition timing and risk
	   corruption. */
	BUG();
}

/**
 *	ata_sff_busy_sleep - sleep until BSY clears, or timeout
 *	@ap: port containing status register to be polled
@@ -742,7 +829,7 @@ static void ata_pio_sectors(struct ata_queued_cmd *qc)
	} else
		ata_pio_sector(qc);

	ata_sff_altstatus(qc->ap); /* flush */
	ata_sff_sync(qc->ap); /* flush */
}

/**
@@ -763,8 +850,9 @@ static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc)
	WARN_ON(qc->dev->cdb_len < 12);

	ap->ops->sff_data_xfer(qc->dev, qc->cdb, qc->dev->cdb_len, 1);
	ata_sff_altstatus(ap); /* flush */

	ata_sff_sync(ap);
	/* FIXME: If the CDB is for DMA do we need to do the transition delay
	   or is bmdma_start guaranteed to do it ? */
	switch (qc->tf.protocol) {
	case ATAPI_PROT_PIO:
		ap->hsm_task_state = HSM_ST;
@@ -905,7 +993,7 @@ static void atapi_pio_bytes(struct ata_queued_cmd *qc)

	if (unlikely(__atapi_pio_bytes(qc, bytes)))
		goto err_out;
	ata_sff_altstatus(ap); /* flush */
	ata_sff_sync(ap); /* flush */

	return;

@@ -1489,14 +1577,10 @@ inline unsigned int ata_sff_host_intr(struct ata_port *ap,
		goto idle_irq;
	}

	/* check altstatus */
	status = ata_sff_altstatus(ap);
	if (status & ATA_BUSY)
		goto idle_irq;

	/* check main status, clearing INTRQ */
	status = ap->ops->sff_check_status(ap);
	if (unlikely(status & ATA_BUSY))
	/* check main status, clearing INTRQ if needed */
	status = ata_sff_irq_status(ap);
	if (status & ATA_BUSY)
		goto idle_irq;

	/* ack bmdma irq events */
@@ -2030,7 +2114,7 @@ void ata_sff_error_handler(struct ata_port *ap)
		ap->ops->bmdma_stop(qc);
	}

	ata_sff_altstatus(ap);
	ata_sff_sync(ap);		/* FIXME: We don't need this */
	ap->ops->sff_check_status(ap);
	ap->ops->sff_irq_clear(ap);

@@ -2203,7 +2287,7 @@ void ata_bmdma_stop(struct ata_queued_cmd *qc)
		 mmio + ATA_DMA_CMD);

	/* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
	ata_sff_altstatus(ap);        /* dummy read */
	ata_sff_dma_pause(ap);
}

/**
@@ -2722,7 +2806,8 @@ EXPORT_SYMBOL_GPL(ata_sff_qc_prep);
EXPORT_SYMBOL_GPL(ata_sff_dumb_qc_prep);
EXPORT_SYMBOL_GPL(ata_sff_dev_select);
EXPORT_SYMBOL_GPL(ata_sff_check_status);
EXPORT_SYMBOL_GPL(ata_sff_altstatus);
EXPORT_SYMBOL_GPL(ata_sff_dma_pause);
EXPORT_SYMBOL_GPL(ata_sff_pause);
EXPORT_SYMBOL_GPL(ata_sff_busy_sleep);
EXPORT_SYMBOL_GPL(ata_sff_wait_ready);
EXPORT_SYMBOL_GPL(ata_sff_tf_load);
+1 −1
Original line number Diff line number Diff line
@@ -270,7 +270,7 @@ static void pata_icside_bmdma_stop(struct ata_queued_cmd *qc)
	disable_dma(state->dma);

	/* see ata_bmdma_stop */
	ata_sff_altstatus(ap);
	ata_sff_dma_pause(ap);
}

static u8 pata_icside_bmdma_status(struct ata_port *ap)
+3 −1
Original line number Diff line number Diff line
@@ -57,7 +57,9 @@ static inline void rb532_pata_finish_io(struct ata_port *ap)
	struct ata_host *ah = ap->host;
	struct rb532_cf_info *info = ah->private_data;

	ata_sff_altstatus(ap);
	/* FIXME: Keep previous delay. If this is merely a fence then
	   ata_sff_sync might be sufficient. */
	ata_sff_dma_pause(ap);
	ndelay(RB500_CF_IO_DELAY);

	set_irq_type(info->irq, IRQ_TYPE_LEVEL_HIGH);
Loading