xref: /kernel/linux/linux-5.10/drivers/ide/ide-acpi.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Provides ACPI support for IDE drives.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2005 Intel Corp.
68c2ecf20Sopenharmony_ci * Copyright (C) 2005 Randy Dunlap
78c2ecf20Sopenharmony_ci * Copyright (C) 2006 SUSE Linux Products GmbH
88c2ecf20Sopenharmony_ci * Copyright (C) 2006 Hannes Reinecke
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/acpi.h>
128c2ecf20Sopenharmony_ci#include <linux/ata.h>
138c2ecf20Sopenharmony_ci#include <linux/delay.h>
148c2ecf20Sopenharmony_ci#include <linux/device.h>
158c2ecf20Sopenharmony_ci#include <linux/errno.h>
168c2ecf20Sopenharmony_ci#include <linux/kernel.h>
178c2ecf20Sopenharmony_ci#include <linux/slab.h>
188c2ecf20Sopenharmony_ci#include <linux/ide.h>
198c2ecf20Sopenharmony_ci#include <linux/pci.h>
208c2ecf20Sopenharmony_ci#include <linux/dmi.h>
218c2ecf20Sopenharmony_ci#include <linux/module.h>
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#define REGS_PER_GTF		7
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistruct GTM_buffer {
268c2ecf20Sopenharmony_ci	u32	PIO_speed0;
278c2ecf20Sopenharmony_ci	u32	DMA_speed0;
288c2ecf20Sopenharmony_ci	u32	PIO_speed1;
298c2ecf20Sopenharmony_ci	u32	DMA_speed1;
308c2ecf20Sopenharmony_ci	u32	GTM_flags;
318c2ecf20Sopenharmony_ci};
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistruct ide_acpi_drive_link {
348c2ecf20Sopenharmony_ci	acpi_handle	 obj_handle;
358c2ecf20Sopenharmony_ci	u8		 idbuff[512];
368c2ecf20Sopenharmony_ci};
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistruct ide_acpi_hwif_link {
398c2ecf20Sopenharmony_ci	ide_hwif_t			*hwif;
408c2ecf20Sopenharmony_ci	acpi_handle			 obj_handle;
418c2ecf20Sopenharmony_ci	struct GTM_buffer		 gtm;
428c2ecf20Sopenharmony_ci	struct ide_acpi_drive_link	 master;
438c2ecf20Sopenharmony_ci	struct ide_acpi_drive_link	 slave;
448c2ecf20Sopenharmony_ci};
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci#undef DEBUGGING
478c2ecf20Sopenharmony_ci/* note: adds function name and KERN_DEBUG */
488c2ecf20Sopenharmony_ci#ifdef DEBUGGING
498c2ecf20Sopenharmony_ci#define DEBPRINT(fmt, args...)	\
508c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "%s: " fmt, __func__, ## args)
518c2ecf20Sopenharmony_ci#else
528c2ecf20Sopenharmony_ci#define DEBPRINT(fmt, args...)	do {} while (0)
538c2ecf20Sopenharmony_ci#endif	/* DEBUGGING */
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_cistatic bool ide_noacpi;
568c2ecf20Sopenharmony_cimodule_param_named(noacpi, ide_noacpi, bool, 0);
578c2ecf20Sopenharmony_ciMODULE_PARM_DESC(noacpi, "disable IDE ACPI support");
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistatic bool ide_acpigtf;
608c2ecf20Sopenharmony_cimodule_param_named(acpigtf, ide_acpigtf, bool, 0);
618c2ecf20Sopenharmony_ciMODULE_PARM_DESC(acpigtf, "enable IDE ACPI _GTF support");
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cistatic bool ide_acpionboot;
648c2ecf20Sopenharmony_cimodule_param_named(acpionboot, ide_acpionboot, bool, 0);
658c2ecf20Sopenharmony_ciMODULE_PARM_DESC(acpionboot, "call IDE ACPI methods on boot");
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistatic bool ide_noacpi_psx;
688c2ecf20Sopenharmony_cistatic int no_acpi_psx(const struct dmi_system_id *id)
698c2ecf20Sopenharmony_ci{
708c2ecf20Sopenharmony_ci	ide_noacpi_psx = true;
718c2ecf20Sopenharmony_ci	printk(KERN_NOTICE"%s detected - disable ACPI _PSx.\n", id->ident);
728c2ecf20Sopenharmony_ci	return 0;
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cistatic const struct dmi_system_id ide_acpi_dmi_table[] = {
768c2ecf20Sopenharmony_ci	/* Bug 9673. */
778c2ecf20Sopenharmony_ci	/* We should check if this is because ACPI NVS isn't save/restored. */
788c2ecf20Sopenharmony_ci	{
798c2ecf20Sopenharmony_ci		.callback = no_acpi_psx,
808c2ecf20Sopenharmony_ci		.ident    = "HP nx9005",
818c2ecf20Sopenharmony_ci		.matches  = {
828c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies Ltd."),
838c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BIOS_VERSION, "KAM1.60")
848c2ecf20Sopenharmony_ci		},
858c2ecf20Sopenharmony_ci	},
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	{ }	/* terminate list */
888c2ecf20Sopenharmony_ci};
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ciint ide_acpi_init(void)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	dmi_check_system(ide_acpi_dmi_table);
938c2ecf20Sopenharmony_ci	return 0;
948c2ecf20Sopenharmony_ci}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cibool ide_port_acpi(ide_hwif_t *hwif)
978c2ecf20Sopenharmony_ci{
988c2ecf20Sopenharmony_ci	return ide_noacpi == 0 && hwif->acpidata;
998c2ecf20Sopenharmony_ci}
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_cistatic acpi_handle acpi_get_child(acpi_handle handle, u64 addr)
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci	struct acpi_device *adev;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	if (!handle || acpi_bus_get_device(handle, &adev))
1068c2ecf20Sopenharmony_ci		return NULL;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	adev = acpi_find_child_device(adev, addr, false);
1098c2ecf20Sopenharmony_ci	return adev ? adev->handle : NULL;
1108c2ecf20Sopenharmony_ci}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci/**
1138c2ecf20Sopenharmony_ci * ide_get_dev_handle - finds acpi_handle and PCI device.function
1148c2ecf20Sopenharmony_ci * @dev: device to locate
1158c2ecf20Sopenharmony_ci * @handle: returned acpi_handle for @dev
1168c2ecf20Sopenharmony_ci * @pcidevfn: return PCI device.func for @dev
1178c2ecf20Sopenharmony_ci *
1188c2ecf20Sopenharmony_ci * Returns the ACPI object handle to the corresponding PCI device.
1198c2ecf20Sopenharmony_ci *
1208c2ecf20Sopenharmony_ci * Returns 0 on success, <0 on error.
1218c2ecf20Sopenharmony_ci */
1228c2ecf20Sopenharmony_cistatic int ide_get_dev_handle(struct device *dev, acpi_handle *handle,
1238c2ecf20Sopenharmony_ci			       u64 *pcidevfn)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
1268c2ecf20Sopenharmony_ci	unsigned int bus, devnum, func;
1278c2ecf20Sopenharmony_ci	u64 addr;
1288c2ecf20Sopenharmony_ci	acpi_handle dev_handle;
1298c2ecf20Sopenharmony_ci	acpi_status status;
1308c2ecf20Sopenharmony_ci	struct acpi_device_info	*dinfo = NULL;
1318c2ecf20Sopenharmony_ci	int ret = -ENODEV;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	bus = pdev->bus->number;
1348c2ecf20Sopenharmony_ci	devnum = PCI_SLOT(pdev->devfn);
1358c2ecf20Sopenharmony_ci	func = PCI_FUNC(pdev->devfn);
1368c2ecf20Sopenharmony_ci	/* ACPI _ADR encoding for PCI bus: */
1378c2ecf20Sopenharmony_ci	addr = (u64)(devnum << 16 | func);
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	DEBPRINT("ENTER: pci %02x:%02x.%01x\n", bus, devnum, func);
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	dev_handle = ACPI_HANDLE(dev);
1428c2ecf20Sopenharmony_ci	if (!dev_handle) {
1438c2ecf20Sopenharmony_ci		DEBPRINT("no acpi handle for device\n");
1448c2ecf20Sopenharmony_ci		goto err;
1458c2ecf20Sopenharmony_ci	}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	status = acpi_get_object_info(dev_handle, &dinfo);
1488c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status)) {
1498c2ecf20Sopenharmony_ci		DEBPRINT("get_object_info for device failed\n");
1508c2ecf20Sopenharmony_ci		goto err;
1518c2ecf20Sopenharmony_ci	}
1528c2ecf20Sopenharmony_ci	if (dinfo && (dinfo->valid & ACPI_VALID_ADR) &&
1538c2ecf20Sopenharmony_ci	    dinfo->address == addr) {
1548c2ecf20Sopenharmony_ci		*pcidevfn = addr;
1558c2ecf20Sopenharmony_ci		*handle = dev_handle;
1568c2ecf20Sopenharmony_ci	} else {
1578c2ecf20Sopenharmony_ci		DEBPRINT("get_object_info for device has wrong "
1588c2ecf20Sopenharmony_ci			" address: %llu, should be %u\n",
1598c2ecf20Sopenharmony_ci			dinfo ? (unsigned long long)dinfo->address : -1ULL,
1608c2ecf20Sopenharmony_ci			(unsigned int)addr);
1618c2ecf20Sopenharmony_ci		goto err;
1628c2ecf20Sopenharmony_ci	}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	DEBPRINT("for dev=0x%x.%x, addr=0x%llx, *handle=0x%p\n",
1658c2ecf20Sopenharmony_ci		 devnum, func, (unsigned long long)addr, *handle);
1668c2ecf20Sopenharmony_ci	ret = 0;
1678c2ecf20Sopenharmony_cierr:
1688c2ecf20Sopenharmony_ci	kfree(dinfo);
1698c2ecf20Sopenharmony_ci	return ret;
1708c2ecf20Sopenharmony_ci}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci/**
1738c2ecf20Sopenharmony_ci * ide_acpi_hwif_get_handle - Get ACPI object handle for a given hwif
1748c2ecf20Sopenharmony_ci * @hwif: device to locate
1758c2ecf20Sopenharmony_ci *
1768c2ecf20Sopenharmony_ci * Retrieves the object handle for a given hwif.
1778c2ecf20Sopenharmony_ci *
1788c2ecf20Sopenharmony_ci * Returns handle on success, 0 on error.
1798c2ecf20Sopenharmony_ci */
1808c2ecf20Sopenharmony_cistatic acpi_handle ide_acpi_hwif_get_handle(ide_hwif_t *hwif)
1818c2ecf20Sopenharmony_ci{
1828c2ecf20Sopenharmony_ci	struct device		*dev = hwif->gendev.parent;
1838c2ecf20Sopenharmony_ci	acpi_handle		dev_handle;
1848c2ecf20Sopenharmony_ci	u64			pcidevfn;
1858c2ecf20Sopenharmony_ci	acpi_handle		chan_handle;
1868c2ecf20Sopenharmony_ci	int			err;
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	DEBPRINT("ENTER: device %s\n", hwif->name);
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	if (!dev) {
1918c2ecf20Sopenharmony_ci		DEBPRINT("no PCI device for %s\n", hwif->name);
1928c2ecf20Sopenharmony_ci		return NULL;
1938c2ecf20Sopenharmony_ci	}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	err = ide_get_dev_handle(dev, &dev_handle, &pcidevfn);
1968c2ecf20Sopenharmony_ci	if (err < 0) {
1978c2ecf20Sopenharmony_ci		DEBPRINT("ide_get_dev_handle failed (%d)\n", err);
1988c2ecf20Sopenharmony_ci		return NULL;
1998c2ecf20Sopenharmony_ci	}
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	/* get child objects of dev_handle == channel objects,
2028c2ecf20Sopenharmony_ci	 * + _their_ children == drive objects */
2038c2ecf20Sopenharmony_ci	/* channel is hwif->channel */
2048c2ecf20Sopenharmony_ci	chan_handle = acpi_get_child(dev_handle, hwif->channel);
2058c2ecf20Sopenharmony_ci	DEBPRINT("chan adr=%d: handle=0x%p\n",
2068c2ecf20Sopenharmony_ci		 hwif->channel, chan_handle);
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	return chan_handle;
2098c2ecf20Sopenharmony_ci}
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci/**
2128c2ecf20Sopenharmony_ci * do_drive_get_GTF - get the drive bootup default taskfile settings
2138c2ecf20Sopenharmony_ci * @drive: the drive for which the taskfile settings should be retrieved
2148c2ecf20Sopenharmony_ci * @gtf_length: number of bytes of _GTF data returned at @gtf_address
2158c2ecf20Sopenharmony_ci * @gtf_address: buffer containing _GTF taskfile arrays
2168c2ecf20Sopenharmony_ci *
2178c2ecf20Sopenharmony_ci * The _GTF method has no input parameters.
2188c2ecf20Sopenharmony_ci * It returns a variable number of register set values (registers
2198c2ecf20Sopenharmony_ci * hex 1F1..1F7, taskfiles).
2208c2ecf20Sopenharmony_ci * The <variable number> is not known in advance, so have ACPI-CA
2218c2ecf20Sopenharmony_ci * allocate the buffer as needed and return it, then free it later.
2228c2ecf20Sopenharmony_ci *
2238c2ecf20Sopenharmony_ci * The returned @gtf_length and @gtf_address are only valid if the
2248c2ecf20Sopenharmony_ci * function return value is 0.
2258c2ecf20Sopenharmony_ci */
2268c2ecf20Sopenharmony_cistatic int do_drive_get_GTF(ide_drive_t *drive,
2278c2ecf20Sopenharmony_ci		     unsigned int *gtf_length, unsigned long *gtf_address,
2288c2ecf20Sopenharmony_ci		     unsigned long *obj_loc)
2298c2ecf20Sopenharmony_ci{
2308c2ecf20Sopenharmony_ci	acpi_status			status;
2318c2ecf20Sopenharmony_ci	struct acpi_buffer		output;
2328c2ecf20Sopenharmony_ci	union acpi_object 		*out_obj;
2338c2ecf20Sopenharmony_ci	int				err = -ENODEV;
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	*gtf_length = 0;
2368c2ecf20Sopenharmony_ci	*gtf_address = 0UL;
2378c2ecf20Sopenharmony_ci	*obj_loc = 0UL;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	if (!drive->acpidata->obj_handle) {
2408c2ecf20Sopenharmony_ci		DEBPRINT("No ACPI object found for %s\n", drive->name);
2418c2ecf20Sopenharmony_ci		goto out;
2428c2ecf20Sopenharmony_ci	}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	/* Setting up output buffer */
2458c2ecf20Sopenharmony_ci	output.length = ACPI_ALLOCATE_BUFFER;
2468c2ecf20Sopenharmony_ci	output.pointer = NULL;	/* ACPI-CA sets this; save/free it later */
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	/* _GTF has no input parameters */
2498c2ecf20Sopenharmony_ci	err = -EIO;
2508c2ecf20Sopenharmony_ci	status = acpi_evaluate_object(drive->acpidata->obj_handle, "_GTF",
2518c2ecf20Sopenharmony_ci				      NULL, &output);
2528c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status)) {
2538c2ecf20Sopenharmony_ci		printk(KERN_DEBUG
2548c2ecf20Sopenharmony_ci		       "%s: Run _GTF error: status = 0x%x\n",
2558c2ecf20Sopenharmony_ci		       __func__, status);
2568c2ecf20Sopenharmony_ci		goto out;
2578c2ecf20Sopenharmony_ci	}
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	if (!output.length || !output.pointer) {
2608c2ecf20Sopenharmony_ci		DEBPRINT("Run _GTF: "
2618c2ecf20Sopenharmony_ci		       "length or ptr is NULL (0x%llx, 0x%p)\n",
2628c2ecf20Sopenharmony_ci		       (unsigned long long)output.length,
2638c2ecf20Sopenharmony_ci		       output.pointer);
2648c2ecf20Sopenharmony_ci		goto out;
2658c2ecf20Sopenharmony_ci	}
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	out_obj = output.pointer;
2688c2ecf20Sopenharmony_ci	if (out_obj->type != ACPI_TYPE_BUFFER) {
2698c2ecf20Sopenharmony_ci		DEBPRINT("Run _GTF: error: "
2708c2ecf20Sopenharmony_ci		       "expected object type of ACPI_TYPE_BUFFER, "
2718c2ecf20Sopenharmony_ci		       "got 0x%x\n", out_obj->type);
2728c2ecf20Sopenharmony_ci		err = -ENOENT;
2738c2ecf20Sopenharmony_ci		kfree(output.pointer);
2748c2ecf20Sopenharmony_ci		goto out;
2758c2ecf20Sopenharmony_ci	}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	if (!out_obj->buffer.length || !out_obj->buffer.pointer ||
2788c2ecf20Sopenharmony_ci	    out_obj->buffer.length % REGS_PER_GTF) {
2798c2ecf20Sopenharmony_ci		printk(KERN_ERR
2808c2ecf20Sopenharmony_ci		       "%s: unexpected GTF length (%d) or addr (0x%p)\n",
2818c2ecf20Sopenharmony_ci		       __func__, out_obj->buffer.length,
2828c2ecf20Sopenharmony_ci		       out_obj->buffer.pointer);
2838c2ecf20Sopenharmony_ci		err = -ENOENT;
2848c2ecf20Sopenharmony_ci		kfree(output.pointer);
2858c2ecf20Sopenharmony_ci		goto out;
2868c2ecf20Sopenharmony_ci	}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	*gtf_length = out_obj->buffer.length;
2898c2ecf20Sopenharmony_ci	*gtf_address = (unsigned long)out_obj->buffer.pointer;
2908c2ecf20Sopenharmony_ci	*obj_loc = (unsigned long)out_obj;
2918c2ecf20Sopenharmony_ci	DEBPRINT("returning gtf_length=%d, gtf_address=0x%lx, obj_loc=0x%lx\n",
2928c2ecf20Sopenharmony_ci		 *gtf_length, *gtf_address, *obj_loc);
2938c2ecf20Sopenharmony_ci	err = 0;
2948c2ecf20Sopenharmony_ciout:
2958c2ecf20Sopenharmony_ci	return err;
2968c2ecf20Sopenharmony_ci}
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci/**
2998c2ecf20Sopenharmony_ci * do_drive_set_taskfiles - write the drive taskfile settings from _GTF
3008c2ecf20Sopenharmony_ci * @drive: the drive to which the taskfile command should be sent
3018c2ecf20Sopenharmony_ci * @gtf_length: total number of bytes of _GTF taskfiles
3028c2ecf20Sopenharmony_ci * @gtf_address: location of _GTF taskfile arrays
3038c2ecf20Sopenharmony_ci *
3048c2ecf20Sopenharmony_ci * Write {gtf_address, length gtf_length} in groups of
3058c2ecf20Sopenharmony_ci * REGS_PER_GTF bytes.
3068c2ecf20Sopenharmony_ci */
3078c2ecf20Sopenharmony_cistatic int do_drive_set_taskfiles(ide_drive_t *drive,
3088c2ecf20Sopenharmony_ci				  unsigned int gtf_length,
3098c2ecf20Sopenharmony_ci				  unsigned long gtf_address)
3108c2ecf20Sopenharmony_ci{
3118c2ecf20Sopenharmony_ci	int			rc = 0, err;
3128c2ecf20Sopenharmony_ci	int			gtf_count = gtf_length / REGS_PER_GTF;
3138c2ecf20Sopenharmony_ci	int			ix;
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	DEBPRINT("total GTF bytes=%u (0x%x), gtf_count=%d, addr=0x%lx\n",
3168c2ecf20Sopenharmony_ci		 gtf_length, gtf_length, gtf_count, gtf_address);
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	/* send all taskfile registers (0x1f1-0x1f7) *in*that*order* */
3198c2ecf20Sopenharmony_ci	for (ix = 0; ix < gtf_count; ix++) {
3208c2ecf20Sopenharmony_ci		u8 *gtf = (u8 *)(gtf_address + ix * REGS_PER_GTF);
3218c2ecf20Sopenharmony_ci		struct ide_cmd cmd;
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci		DEBPRINT("(0x1f1-1f7): "
3248c2ecf20Sopenharmony_ci			 "hex: %02x %02x %02x %02x %02x %02x %02x\n",
3258c2ecf20Sopenharmony_ci			 gtf[0], gtf[1], gtf[2],
3268c2ecf20Sopenharmony_ci			 gtf[3], gtf[4], gtf[5], gtf[6]);
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci		if (!ide_acpigtf) {
3298c2ecf20Sopenharmony_ci			DEBPRINT("_GTF execution disabled\n");
3308c2ecf20Sopenharmony_ci			continue;
3318c2ecf20Sopenharmony_ci		}
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci		/* convert GTF to taskfile */
3348c2ecf20Sopenharmony_ci		memset(&cmd, 0, sizeof(cmd));
3358c2ecf20Sopenharmony_ci		memcpy(&cmd.tf.feature, gtf, REGS_PER_GTF);
3368c2ecf20Sopenharmony_ci		cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE;
3378c2ecf20Sopenharmony_ci		cmd.valid.in.tf  = IDE_VALID_IN_TF  | IDE_VALID_DEVICE;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci		err = ide_no_data_taskfile(drive, &cmd);
3408c2ecf20Sopenharmony_ci		if (err) {
3418c2ecf20Sopenharmony_ci			printk(KERN_ERR "%s: ide_no_data_taskfile failed: %u\n",
3428c2ecf20Sopenharmony_ci					__func__, err);
3438c2ecf20Sopenharmony_ci			rc = err;
3448c2ecf20Sopenharmony_ci		}
3458c2ecf20Sopenharmony_ci	}
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	return rc;
3488c2ecf20Sopenharmony_ci}
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci/**
3518c2ecf20Sopenharmony_ci * ide_acpi_exec_tfs - get then write drive taskfile settings
3528c2ecf20Sopenharmony_ci * @drive: the drive for which the taskfile settings should be
3538c2ecf20Sopenharmony_ci *         written.
3548c2ecf20Sopenharmony_ci *
3558c2ecf20Sopenharmony_ci * According to the ACPI spec this should be called after _STM
3568c2ecf20Sopenharmony_ci * has been evaluated for the interface. Some ACPI vendors interpret
3578c2ecf20Sopenharmony_ci * that as a hard requirement and modify the taskfile according
3588c2ecf20Sopenharmony_ci * to the Identify Drive information passed down with _STM.
3598c2ecf20Sopenharmony_ci * So one should really make sure to call this only after _STM has
3608c2ecf20Sopenharmony_ci * been executed.
3618c2ecf20Sopenharmony_ci */
3628c2ecf20Sopenharmony_ciint ide_acpi_exec_tfs(ide_drive_t *drive)
3638c2ecf20Sopenharmony_ci{
3648c2ecf20Sopenharmony_ci	int		ret;
3658c2ecf20Sopenharmony_ci	unsigned int	gtf_length;
3668c2ecf20Sopenharmony_ci	unsigned long	gtf_address;
3678c2ecf20Sopenharmony_ci	unsigned long	obj_loc;
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	DEBPRINT("call get_GTF, drive=%s port=%d\n", drive->name, drive->dn);
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	ret = do_drive_get_GTF(drive, &gtf_length, &gtf_address, &obj_loc);
3728c2ecf20Sopenharmony_ci	if (ret < 0) {
3738c2ecf20Sopenharmony_ci		DEBPRINT("get_GTF error (%d)\n", ret);
3748c2ecf20Sopenharmony_ci		return ret;
3758c2ecf20Sopenharmony_ci	}
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	DEBPRINT("call set_taskfiles, drive=%s\n", drive->name);
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	ret = do_drive_set_taskfiles(drive, gtf_length, gtf_address);
3808c2ecf20Sopenharmony_ci	kfree((void *)obj_loc);
3818c2ecf20Sopenharmony_ci	if (ret < 0) {
3828c2ecf20Sopenharmony_ci		DEBPRINT("set_taskfiles error (%d)\n", ret);
3838c2ecf20Sopenharmony_ci	}
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	DEBPRINT("ret=%d\n", ret);
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	return ret;
3888c2ecf20Sopenharmony_ci}
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci/**
3918c2ecf20Sopenharmony_ci * ide_acpi_get_timing - get the channel (controller) timings
3928c2ecf20Sopenharmony_ci * @hwif: target IDE interface (channel)
3938c2ecf20Sopenharmony_ci *
3948c2ecf20Sopenharmony_ci * This function executes the _GTM ACPI method for the target channel.
3958c2ecf20Sopenharmony_ci *
3968c2ecf20Sopenharmony_ci */
3978c2ecf20Sopenharmony_civoid ide_acpi_get_timing(ide_hwif_t *hwif)
3988c2ecf20Sopenharmony_ci{
3998c2ecf20Sopenharmony_ci	acpi_status		status;
4008c2ecf20Sopenharmony_ci	struct acpi_buffer	output;
4018c2ecf20Sopenharmony_ci	union acpi_object 	*out_obj;
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	/* Setting up output buffer for _GTM */
4048c2ecf20Sopenharmony_ci	output.length = ACPI_ALLOCATE_BUFFER;
4058c2ecf20Sopenharmony_ci	output.pointer = NULL;	/* ACPI-CA sets this; save/free it later */
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	/* _GTM has no input parameters */
4088c2ecf20Sopenharmony_ci	status = acpi_evaluate_object(hwif->acpidata->obj_handle, "_GTM",
4098c2ecf20Sopenharmony_ci				      NULL, &output);
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	DEBPRINT("_GTM status: %d, outptr: 0x%p, outlen: 0x%llx\n",
4128c2ecf20Sopenharmony_ci		 status, output.pointer,
4138c2ecf20Sopenharmony_ci		 (unsigned long long)output.length);
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status)) {
4168c2ecf20Sopenharmony_ci		DEBPRINT("Run _GTM error: status = 0x%x\n", status);
4178c2ecf20Sopenharmony_ci		return;
4188c2ecf20Sopenharmony_ci	}
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	if (!output.length || !output.pointer) {
4218c2ecf20Sopenharmony_ci		DEBPRINT("Run _GTM: length or ptr is NULL (0x%llx, 0x%p)\n",
4228c2ecf20Sopenharmony_ci		       (unsigned long long)output.length,
4238c2ecf20Sopenharmony_ci		       output.pointer);
4248c2ecf20Sopenharmony_ci		kfree(output.pointer);
4258c2ecf20Sopenharmony_ci		return;
4268c2ecf20Sopenharmony_ci	}
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	out_obj = output.pointer;
4298c2ecf20Sopenharmony_ci	if (out_obj->type != ACPI_TYPE_BUFFER) {
4308c2ecf20Sopenharmony_ci		DEBPRINT("Run _GTM: error: "
4318c2ecf20Sopenharmony_ci		       "expected object type of ACPI_TYPE_BUFFER, "
4328c2ecf20Sopenharmony_ci		       "got 0x%x\n", out_obj->type);
4338c2ecf20Sopenharmony_ci		kfree(output.pointer);
4348c2ecf20Sopenharmony_ci		return;
4358c2ecf20Sopenharmony_ci	}
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	if (!out_obj->buffer.length || !out_obj->buffer.pointer ||
4388c2ecf20Sopenharmony_ci	    out_obj->buffer.length != sizeof(struct GTM_buffer)) {
4398c2ecf20Sopenharmony_ci		printk(KERN_ERR
4408c2ecf20Sopenharmony_ci			"%s: unexpected _GTM length (0x%x)[should be 0x%zx] or "
4418c2ecf20Sopenharmony_ci			"addr (0x%p)\n",
4428c2ecf20Sopenharmony_ci			__func__, out_obj->buffer.length,
4438c2ecf20Sopenharmony_ci			sizeof(struct GTM_buffer), out_obj->buffer.pointer);
4448c2ecf20Sopenharmony_ci		kfree(output.pointer);
4458c2ecf20Sopenharmony_ci		return;
4468c2ecf20Sopenharmony_ci	}
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	memcpy(&hwif->acpidata->gtm, out_obj->buffer.pointer,
4498c2ecf20Sopenharmony_ci	       sizeof(struct GTM_buffer));
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	DEBPRINT("_GTM info: ptr: 0x%p, len: 0x%x, exp.len: 0x%zx\n",
4528c2ecf20Sopenharmony_ci		 out_obj->buffer.pointer, out_obj->buffer.length,
4538c2ecf20Sopenharmony_ci		 sizeof(struct GTM_buffer));
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	DEBPRINT("_GTM fields: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n",
4568c2ecf20Sopenharmony_ci		 hwif->acpidata->gtm.PIO_speed0,
4578c2ecf20Sopenharmony_ci		 hwif->acpidata->gtm.DMA_speed0,
4588c2ecf20Sopenharmony_ci		 hwif->acpidata->gtm.PIO_speed1,
4598c2ecf20Sopenharmony_ci		 hwif->acpidata->gtm.DMA_speed1,
4608c2ecf20Sopenharmony_ci		 hwif->acpidata->gtm.GTM_flags);
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	kfree(output.pointer);
4638c2ecf20Sopenharmony_ci}
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci/**
4668c2ecf20Sopenharmony_ci * ide_acpi_push_timing - set the channel (controller) timings
4678c2ecf20Sopenharmony_ci * @hwif: target IDE interface (channel)
4688c2ecf20Sopenharmony_ci *
4698c2ecf20Sopenharmony_ci * This function executes the _STM ACPI method for the target channel.
4708c2ecf20Sopenharmony_ci *
4718c2ecf20Sopenharmony_ci * _STM requires Identify Drive data, which has to passed as an argument.
4728c2ecf20Sopenharmony_ci * Unfortunately drive->id is a mangled version which we can't readily
4738c2ecf20Sopenharmony_ci * use; hence we'll get the information afresh.
4748c2ecf20Sopenharmony_ci */
4758c2ecf20Sopenharmony_civoid ide_acpi_push_timing(ide_hwif_t *hwif)
4768c2ecf20Sopenharmony_ci{
4778c2ecf20Sopenharmony_ci	acpi_status		status;
4788c2ecf20Sopenharmony_ci	struct acpi_object_list	input;
4798c2ecf20Sopenharmony_ci	union acpi_object 	in_params[3];
4808c2ecf20Sopenharmony_ci	struct ide_acpi_drive_link	*master = &hwif->acpidata->master;
4818c2ecf20Sopenharmony_ci	struct ide_acpi_drive_link	*slave = &hwif->acpidata->slave;
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	/* Give the GTM buffer + drive Identify data to the channel via the
4848c2ecf20Sopenharmony_ci	 * _STM method: */
4858c2ecf20Sopenharmony_ci	/* setup input parameters buffer for _STM */
4868c2ecf20Sopenharmony_ci	input.count = 3;
4878c2ecf20Sopenharmony_ci	input.pointer = in_params;
4888c2ecf20Sopenharmony_ci	in_params[0].type = ACPI_TYPE_BUFFER;
4898c2ecf20Sopenharmony_ci	in_params[0].buffer.length = sizeof(struct GTM_buffer);
4908c2ecf20Sopenharmony_ci	in_params[0].buffer.pointer = (u8 *)&hwif->acpidata->gtm;
4918c2ecf20Sopenharmony_ci	in_params[1].type = ACPI_TYPE_BUFFER;
4928c2ecf20Sopenharmony_ci	in_params[1].buffer.length = ATA_ID_WORDS * 2;
4938c2ecf20Sopenharmony_ci	in_params[1].buffer.pointer = (u8 *)&master->idbuff;
4948c2ecf20Sopenharmony_ci	in_params[2].type = ACPI_TYPE_BUFFER;
4958c2ecf20Sopenharmony_ci	in_params[2].buffer.length = ATA_ID_WORDS * 2;
4968c2ecf20Sopenharmony_ci	in_params[2].buffer.pointer = (u8 *)&slave->idbuff;
4978c2ecf20Sopenharmony_ci	/* Output buffer: _STM has no output */
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	status = acpi_evaluate_object(hwif->acpidata->obj_handle, "_STM",
5008c2ecf20Sopenharmony_ci				      &input, NULL);
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status)) {
5038c2ecf20Sopenharmony_ci		DEBPRINT("Run _STM error: status = 0x%x\n", status);
5048c2ecf20Sopenharmony_ci	}
5058c2ecf20Sopenharmony_ci	DEBPRINT("_STM status: %d\n", status);
5068c2ecf20Sopenharmony_ci}
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci/**
5098c2ecf20Sopenharmony_ci * ide_acpi_set_state - set the channel power state
5108c2ecf20Sopenharmony_ci * @hwif: target IDE interface
5118c2ecf20Sopenharmony_ci * @on: state, on/off
5128c2ecf20Sopenharmony_ci *
5138c2ecf20Sopenharmony_ci * This function executes the _PS0/_PS3 ACPI method to set the power state.
5148c2ecf20Sopenharmony_ci * ACPI spec requires _PS0 when IDE power on and _PS3 when power off
5158c2ecf20Sopenharmony_ci */
5168c2ecf20Sopenharmony_civoid ide_acpi_set_state(ide_hwif_t *hwif, int on)
5178c2ecf20Sopenharmony_ci{
5188c2ecf20Sopenharmony_ci	ide_drive_t *drive;
5198c2ecf20Sopenharmony_ci	int i;
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	if (ide_noacpi_psx)
5228c2ecf20Sopenharmony_ci		return;
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	DEBPRINT("ENTER:\n");
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	/* channel first and then drives for power on and verse versa for power off */
5278c2ecf20Sopenharmony_ci	if (on)
5288c2ecf20Sopenharmony_ci		acpi_bus_set_power(hwif->acpidata->obj_handle, ACPI_STATE_D0);
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	ide_port_for_each_present_dev(i, drive, hwif) {
5318c2ecf20Sopenharmony_ci		if (drive->acpidata->obj_handle)
5328c2ecf20Sopenharmony_ci			acpi_bus_set_power(drive->acpidata->obj_handle,
5338c2ecf20Sopenharmony_ci				on ? ACPI_STATE_D0 : ACPI_STATE_D3_COLD);
5348c2ecf20Sopenharmony_ci	}
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	if (!on)
5378c2ecf20Sopenharmony_ci		acpi_bus_set_power(hwif->acpidata->obj_handle,
5388c2ecf20Sopenharmony_ci				   ACPI_STATE_D3_COLD);
5398c2ecf20Sopenharmony_ci}
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci/**
5428c2ecf20Sopenharmony_ci * ide_acpi_init_port - initialize the ACPI link for an IDE interface
5438c2ecf20Sopenharmony_ci * @hwif: target IDE interface (channel)
5448c2ecf20Sopenharmony_ci *
5458c2ecf20Sopenharmony_ci * The ACPI spec is not quite clear when the drive identify buffer
5468c2ecf20Sopenharmony_ci * should be obtained. Calling IDENTIFY DEVICE during shutdown
5478c2ecf20Sopenharmony_ci * is not the best of ideas as the drive might already being put to
5488c2ecf20Sopenharmony_ci * sleep. And obviously we can't call it during resume.
5498c2ecf20Sopenharmony_ci * So we get the information during startup; but this means that
5508c2ecf20Sopenharmony_ci * any changes during run-time will be lost after resume.
5518c2ecf20Sopenharmony_ci */
5528c2ecf20Sopenharmony_civoid ide_acpi_init_port(ide_hwif_t *hwif)
5538c2ecf20Sopenharmony_ci{
5548c2ecf20Sopenharmony_ci	hwif->acpidata = kzalloc(sizeof(struct ide_acpi_hwif_link), GFP_KERNEL);
5558c2ecf20Sopenharmony_ci	if (!hwif->acpidata)
5568c2ecf20Sopenharmony_ci		return;
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci	hwif->acpidata->obj_handle = ide_acpi_hwif_get_handle(hwif);
5598c2ecf20Sopenharmony_ci	if (!hwif->acpidata->obj_handle) {
5608c2ecf20Sopenharmony_ci		DEBPRINT("no ACPI object for %s found\n", hwif->name);
5618c2ecf20Sopenharmony_ci		kfree(hwif->acpidata);
5628c2ecf20Sopenharmony_ci		hwif->acpidata = NULL;
5638c2ecf20Sopenharmony_ci	}
5648c2ecf20Sopenharmony_ci}
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_civoid ide_acpi_port_init_devices(ide_hwif_t *hwif)
5678c2ecf20Sopenharmony_ci{
5688c2ecf20Sopenharmony_ci	ide_drive_t *drive;
5698c2ecf20Sopenharmony_ci	int i, err;
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	if (hwif->acpidata == NULL)
5728c2ecf20Sopenharmony_ci		return;
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci	/*
5758c2ecf20Sopenharmony_ci	 * The ACPI spec mandates that we send information
5768c2ecf20Sopenharmony_ci	 * for both drives, regardless whether they are connected
5778c2ecf20Sopenharmony_ci	 * or not.
5788c2ecf20Sopenharmony_ci	 */
5798c2ecf20Sopenharmony_ci	hwif->devices[0]->acpidata = &hwif->acpidata->master;
5808c2ecf20Sopenharmony_ci	hwif->devices[1]->acpidata = &hwif->acpidata->slave;
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	/* get _ADR info for each device */
5838c2ecf20Sopenharmony_ci	ide_port_for_each_present_dev(i, drive, hwif) {
5848c2ecf20Sopenharmony_ci		acpi_handle dev_handle;
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci		DEBPRINT("ENTER: %s at channel#: %d port#: %d\n",
5878c2ecf20Sopenharmony_ci			 drive->name, hwif->channel, drive->dn & 1);
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci		/* TBD: could also check ACPI object VALID bits */
5908c2ecf20Sopenharmony_ci		dev_handle = acpi_get_child(hwif->acpidata->obj_handle,
5918c2ecf20Sopenharmony_ci					    drive->dn & 1);
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci		DEBPRINT("drive %s handle 0x%p\n", drive->name, dev_handle);
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci		drive->acpidata->obj_handle = dev_handle;
5968c2ecf20Sopenharmony_ci	}
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci	/* send IDENTIFY for each device */
5998c2ecf20Sopenharmony_ci	ide_port_for_each_present_dev(i, drive, hwif) {
6008c2ecf20Sopenharmony_ci		err = taskfile_lib_get_identify(drive, drive->acpidata->idbuff);
6018c2ecf20Sopenharmony_ci		if (err)
6028c2ecf20Sopenharmony_ci			DEBPRINT("identify device %s failed (%d)\n",
6038c2ecf20Sopenharmony_ci				 drive->name, err);
6048c2ecf20Sopenharmony_ci	}
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	if (ide_noacpi || ide_acpionboot == 0) {
6078c2ecf20Sopenharmony_ci		DEBPRINT("ACPI methods disabled on boot\n");
6088c2ecf20Sopenharmony_ci		return;
6098c2ecf20Sopenharmony_ci	}
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	/* ACPI _PS0 before _STM */
6128c2ecf20Sopenharmony_ci	ide_acpi_set_state(hwif, 1);
6138c2ecf20Sopenharmony_ci	/*
6148c2ecf20Sopenharmony_ci	 * ACPI requires us to call _STM on startup
6158c2ecf20Sopenharmony_ci	 */
6168c2ecf20Sopenharmony_ci	ide_acpi_get_timing(hwif);
6178c2ecf20Sopenharmony_ci	ide_acpi_push_timing(hwif);
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	ide_port_for_each_present_dev(i, drive, hwif) {
6208c2ecf20Sopenharmony_ci		ide_acpi_exec_tfs(drive);
6218c2ecf20Sopenharmony_ci	}
6228c2ecf20Sopenharmony_ci}
623