Generalize acpi_pci_save_handle and preliminary ATA ACPI support.
Takanori Watanabe
takawata at ns.init-main.com
Tue Jan 16 17:29:07 UTC 2007
Oops, I forgot to attach files.
>I wrote preliminary support of ACPI support for PCI ATA device.
>Currently it does nothing but recognize acpi handle.
>To use some support function in PCI, I generalized acpi_pci_save_handle
>and export it as acpi device method.
>
>To support ATA channel it seems that it require some modification to
>ATA driver.
>
>ACPI has some ATA support. for more information, Section 9.9 of
>ACPI 3.0 specification.
>
>Regards.
-------------- next part --------------
Index: acpi.c
===================================================================
RCS file: /disk1/ncvs/src/sys/dev/acpica/acpi.c,v
retrieving revision 1.229
diff -u -r1.229 acpi.c
--- acpi.c 21 Sep 2006 18:56:03 -0000 1.229
+++ acpi.c 16 Jan 2007 11:26:15 -0000
@@ -127,6 +127,12 @@
void *context, void **retval);
static ACPI_STATUS acpi_device_scan_children(device_t bus, device_t dev,
int max_depth, acpi_scan_cb_t user_fn, void *arg);
+
+static void acpi_update_device(ACPI_HANDLE handle, device_t newdev);
+static ACPI_STATUS acpi_device_save_handle_cb(ACPI_HANDLE h, UINT32 level,
+ void *context, void **retval);
+static int acpi_device_save_handle(device_t acpi, device_t dev);
+
static int acpi_set_powerstate_method(device_t bus, device_t child,
int state);
static int acpi_isa_pnp_probe(device_t bus, device_t child,
@@ -188,6 +194,7 @@
DEVMETHOD(acpi_evaluate_object, acpi_device_eval_obj),
DEVMETHOD(acpi_pwr_for_sleep, acpi_device_pwr_for_sleep),
DEVMETHOD(acpi_scan_children, acpi_device_scan_children),
+ DEVMETHOD(acpi_save_handle, acpi_device_save_handle),
/* PCI emulation */
DEVMETHOD(pci_set_powerstate, acpi_set_powerstate_method),
@@ -1384,6 +1391,85 @@
acpi_device_scan_cb, &ctx, NULL));
}
+/********************************************
+ *
+ * acpi_device_save_handle() and its helper
+ *
+ ********************************************/
+
+/*
+ * detach direct children of acpi device and attach device to acpi handle.
+ */
+static void acpi_update_device(ACPI_HANDLE handle, device_t newdev)
+{
+ ACPI_STATUS status;
+ device_t olddev;
+
+ olddev = acpi_get_device(handle);
+ if (olddev != NULL) {
+ KASSERT(!device_is_alive(olddev), ("%s: deleting alive child %s",
+ __func__, device_get_nameunit(olddev)));
+ KASSERT(device_get_parent(olddev) == acpidev(),
+ ("%s: child (%s)'s parent is not acpi0", __func__,
+ acpi_name(handle)));
+ device_delete_child(device_get_parent(olddev), olddev);
+ }
+
+ /*
+ * Update ACPI-CA to use the enumlated device_t for this handle.
+ */
+ status = AcpiDetachData(handle, acpi_fake_objhandler);
+ if (ACPI_FAILURE(status))
+ printf("WARNING: Unable to detach object data from %s - %s\n",
+ acpi_name(handle), AcpiFormatException(status));
+ status = AcpiAttachData(handle, acpi_fake_objhandler, newdev);
+ if (ACPI_FAILURE(status))
+ printf("WARNING: Unable to attach object data to %s - %s\n",
+ acpi_name(handle), AcpiFormatException(status));
+
+}
+
+
+/*
+ * per handle process of acpi_device_save_handle
+ */
+static ACPI_STATUS
+acpi_device_save_handle_cb(ACPI_HANDLE h, UINT32 level, void *context, void **status)
+{
+ device_t *devlist;
+ int devcount, i;
+ UINT32 address;
+ ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+ if (ACPI_FAILURE(acpi_GetInteger(h, "_ADR", &address)))
+ return_ACPI_STATUS (AE_OK);
+
+ if (device_get_children((device_t)context, &devlist, &devcount) != 0)
+ return_ACPI_STATUS (AE_OK);
+
+ for (i = 0; i < devcount; i++) {
+ if(acpi_get_adr(devlist[i]) == address){
+ acpi_set_handle(devlist[i], h);
+ acpi_update_device(h, devlist[i]);
+ }
+ }
+ free(devlist, M_TEMP);
+
+ return_ACPI_STATUS(AE_OK);
+}
+
+/*
+ * register acpi handle to device other than direct children of
+ * acpi device.
+ */
+static int
+acpi_device_save_handle(device_t acpi, device_t dev)
+{
+ AcpiWalkNamespace(ACPI_TYPE_DEVICE, acpi_get_handle(dev), 1, acpi_device_save_handle_cb, dev, NULL);
+
+ return 0;
+}
+
+
/*
* Even though ACPI devices are not PCI, we use the PCI approach for setting
* device power states since it's close enough to ACPI.
Index: acpi_if.m
===================================================================
RCS file: /disk1/ncvs/src/sys/dev/acpica/acpi_if.m,v
retrieving revision 1.8
diff -u -r1.8 acpi_if.m
--- acpi_if.m 11 Sep 2005 18:39:01 -0000 1.8
+++ acpi_if.m 16 Jan 2007 12:36:01 -0000
@@ -222,3 +222,19 @@
device_t dev;
struct acpi_bst *bst;
};
+
+#
+# Save device handles to ivars for children.
+# All children have to be attached to parent and
+# children should be able to access following ivars:
+# 1. read ACPI_IVAR_ADR to get _ADR value.
+# 2. write ACPI_IVAR_HANDLE to set ACPI handle.
+#
+# device_t acpi: ACPI device
+# device_t dev: parent device
+#
+
+METHOD int save_handle{
+ device_t acpi;
+ device_t dev;
+};
Index: acpi_pci.c
===================================================================
RCS file: /disk1/ncvs/src/sys/dev/acpica/acpi_pci.c,v
retrieving revision 1.30
diff -u -r1.30 acpi_pci.c
--- acpi_pci.c 11 May 2006 22:13:20 -0000 1.30
+++ acpi_pci.c 16 Jan 2007 12:11:14 -0000
@@ -73,11 +73,8 @@
uintptr_t *result);
static int acpi_pci_write_ivar(device_t dev, device_t child, int which,
uintptr_t value);
-static ACPI_STATUS acpi_pci_save_handle(ACPI_HANDLE handle, UINT32 level,
- void *context, void **status);
static int acpi_pci_set_powerstate_method(device_t dev, device_t child,
int state);
-static void acpi_pci_update_device(ACPI_HANDLE handle, device_t pci_child);
static device_method_t acpi_pci_methods[] = {
/* Device interface */
@@ -116,6 +113,10 @@
case ACPI_IVAR_FLAGS:
*result = (uintptr_t)dinfo->ap_flags;
return (0);
+ case ACPI_IVAR_ADR:
+ *result = (uintptr_t) (dinfo->ap_dinfo.cfg.slot<<16
+ |dinfo->ap_dinfo.cfg.func);
+ return (0);
}
return (pci_read_ivar(dev, child, which, result));
}
@@ -196,69 +197,6 @@
return (error);
}
-static void
-acpi_pci_update_device(ACPI_HANDLE handle, device_t pci_child)
-{
- ACPI_STATUS status;
- device_t child;
-
- /*
- * Lookup and remove the unused device that acpi0 creates when it walks
- * the namespace creating devices.
- */
- child = acpi_get_device(handle);
- if (child != NULL) {
- KASSERT(!device_is_alive(child), ("%s: deleting alive child %s",
- __func__, device_get_nameunit(child)));
- KASSERT(device_get_parent(child) ==
- devclass_get_device(devclass_find("acpi"), 0),
- ("%s: child (%s)'s parent is not acpi0", __func__,
- acpi_name(handle)));
- device_delete_child(device_get_parent(child), child);
- }
-
- /*
- * Update ACPI-CA to use the PCI enumerated device_t for this handle.
- */
- status = AcpiDetachData(handle, acpi_fake_objhandler);
- if (ACPI_FAILURE(status))
- printf("WARNING: Unable to detach object data from %s - %s\n",
- acpi_name(handle), AcpiFormatException(status));
- status = AcpiAttachData(handle, acpi_fake_objhandler, pci_child);
- if (ACPI_FAILURE(status))
- printf("WARNING: Unable to attach object data to %s - %s\n",
- acpi_name(handle), AcpiFormatException(status));
-}
-
-static ACPI_STATUS
-acpi_pci_save_handle(ACPI_HANDLE handle, UINT32 level, void *context,
- void **status)
-{
- struct acpi_pci_devinfo *dinfo;
- device_t *devlist;
- int devcount, i, func, slot;
- UINT32 address;
-
- ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
-
- if (ACPI_FAILURE(acpi_GetInteger(handle, "_ADR", &address)))
- return_ACPI_STATUS (AE_OK);
- slot = ACPI_ADR_PCI_SLOT(address);
- func = ACPI_ADR_PCI_FUNC(address);
- if (device_get_children((device_t)context, &devlist, &devcount) != 0)
- return_ACPI_STATUS (AE_OK);
- for (i = 0; i < devcount; i++) {
- dinfo = device_get_ivars(devlist[i]);
- if (dinfo->ap_dinfo.cfg.func == func &&
- dinfo->ap_dinfo.cfg.slot == slot) {
- dinfo->ap_handle = handle;
- acpi_pci_update_device(handle, devlist[i]);
- break;
- }
- }
- free(devlist, M_TEMP);
- return_ACPI_STATUS (AE_OK);
-}
static int
acpi_pci_probe(device_t dev)
@@ -298,8 +236,7 @@
* these devices.
*/
pci_add_children(dev, busno, sizeof(struct acpi_pci_devinfo));
- AcpiWalkNamespace(ACPI_TYPE_DEVICE, acpi_get_handle(dev), 1,
- acpi_pci_save_handle, dev, NULL);
+ ACPI_SAVE_HANDLE(acpidev(), dev);
return (bus_generic_attach(dev));
}
Index: acpivar.h
===================================================================
RCS file: /disk1/ncvs/src/sys/dev/acpica/acpivar.h,v
retrieving revision 1.102
diff -u -r1.102 acpivar.h
--- acpivar.h 29 Jul 2006 21:46:15 -0000 1.102
+++ acpivar.h 16 Jan 2007 12:33:22 -0000
@@ -204,6 +204,7 @@
#define ACPI_IVAR_MAGIC 0x101
#define ACPI_IVAR_PRIVATE 0x102
#define ACPI_IVAR_FLAGS 0x103
+#define ACPI_IVAR_ADR 0x104
/*
* Accessor functions for our ivars. Default value for BUS_READ_IVAR is
@@ -230,6 +231,7 @@
__ACPI_BUS_ACCESSOR(acpi, magic, ACPI, MAGIC, int)
__ACPI_BUS_ACCESSOR(acpi, private, ACPI, PRIVATE, void *)
__ACPI_BUS_ACCESSOR(acpi, flags, ACPI, FLAGS, int)
+__ACPI_BUS_ACCESSOR(acpi, adr, ACPI, ADR, UINT32)
void acpi_fake_objhandler(ACPI_HANDLE h, UINT32 fn, void *data);
static __inline device_t
@@ -336,6 +338,11 @@
void (*set_end_dependent)(device_t dev, void *context);
};
+
+
+#define acpidev() devclass_get_device(devclass_find("acpi"),0)
+
+
extern struct acpi_parse_resource_set acpi_res_parse_set;
void acpi_config_intr(device_t dev, ACPI_RESOURCE *res);
-------------- next part --------------
/*-
* Copyright (c) 2006 Takanori Watanabe
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/sys/dev/ata/ata-pci.c,v 1.117 2006/05/12 05:04:40 jhb Exp $");
#include "opt_ata.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/ata.h>
#include <sys/bus.h>
#include <sys/conf.h>
#include <sys/malloc.h>
#include <sys/sema.h>
#include <sys/taskqueue.h>
#include <vm/uma.h>
#include <machine/stdarg.h>
#include <machine/resource.h>
#include <machine/bus.h>
#include <sys/rman.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
#include <dev/ata/ata-all.h>
#include <dev/ata/ata-pci.h>
#include <ata_if.h>
#define ATA_ACPI_PROBE_OK -8
#include <contrib/dev/acpica/acpi.h>
#include <dev/acpica/acpivar.h>
#include "acpi_if.h"
static int ata_pci_acpi_probe(device_t);
static int ata_pci_acpi_attach(device_t);
static int ata_pci_acpi_read_ivar(device_t, device_t, int , uintptr_t *);
static int ata_pci_acpi_write_ivar(device_t, device_t, int , uintptr_t );
struct ata_pci_controller_acpi {
struct ata_pci_controller core; /*Must be here.*/
ACPI_HANDLE acpi_handle[8];
};
struct ata_pci_channel_acpi {
struct ata_channel core; /*Must be here.*/
ACPI_HANDLE acpi_handle[8];
};
int ata_pci_acpi_probe(device_t dev)
{
if(acpi_get_handle(dev) == NULL){
return ENXIO;
}
if(ata_pci_probe(dev)<= 0){
return ATA_ACPI_PROBE_OK;
}
return ENXIO;
}
int ata_pci_acpi_attach(device_t dev)
{
int result;
result = ata_pci_attach(dev);
if(result != 0){
return result;
}
ACPI_SAVE_HANDLE(acpidev(), dev);
return 0;
}
int ata_pci_acpi_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
{
struct ata_pci_controller_acpi *sc = device_get_softc(dev);
struct ata_channel *ch = device_get_softc(child);
switch (which){
case ACPI_IVAR_HANDLE:
sc->acpi_handle[ch->unit] = (ACPI_HANDLE) value;
return 0;
}
return ENXIO;
}
int ata_pci_acpi_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
{
struct ata_pci_controller_acpi *sc = device_get_softc(dev);
struct ata_channel *ch = device_get_softc(child);
/*Multiple channel device got wrong result,
when it is called before calling parent attach*/
switch (which){
case ACPI_IVAR_HANDLE:
*result = (uintptr_t) sc->acpi_handle[ch->unit];
return 0;
case ACPI_IVAR_ADR:
*result = (uintptr_t) ch->unit;
return 0;
}
/*GENERIC CODE DON'T HAVE THIS METHOD*/
return ENXIO;
}
static int
ata_pci_acpi_location_str(device_t cbdev, device_t child, char *buf,
size_t buflen)
{
struct ata_channel *ch = device_get_softc(child);
struct ata_pci_controller_acpi *sc = device_get_softc(cbdev);
snprintf(buf, buflen, "channel=%d", ch->unit);
/*acpi_name should be exported.*/
if(sc->acpi_handle[ch->unit]){
strlcat(buf, " handle=", buflen);
strlcat(buf, acpi_name(sc->acpi_handle[ch->unit]), buflen);
}
return 0;
}
static device_method_t ata_pci_methods[] = {
/* device interface */
DEVMETHOD(device_probe, ata_pci_acpi_probe),
DEVMETHOD(device_attach, ata_pci_acpi_attach),
DEVMETHOD(device_detach, ata_pci_detach),
DEVMETHOD(device_shutdown, bus_generic_shutdown),
DEVMETHOD(device_suspend, bus_generic_suspend),
DEVMETHOD(device_resume, bus_generic_resume),
/* bus methods */
DEVMETHOD(bus_alloc_resource, ata_pci_alloc_resource),
DEVMETHOD(bus_release_resource, ata_pci_release_resource),
DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
DEVMETHOD(bus_setup_intr, ata_pci_setup_intr),
DEVMETHOD(bus_teardown_intr, ata_pci_teardown_intr),
DEVMETHOD(bus_read_ivar, ata_pci_acpi_read_ivar),
DEVMETHOD(bus_write_ivar, ata_pci_acpi_write_ivar),
DEVMETHOD(bus_child_location_str, ata_pci_acpi_location_str),
{ 0, 0 }
};
static driver_t ata_pci_acpi_driver = {
"atapci",
ata_pci_methods,
sizeof(struct ata_pci_controller_acpi),
};
static devclass_t atapciacpi_devclass;
DRIVER_MODULE(atapciacpi, pci, ata_pci_acpi_driver, atapciacpi_devclass, 0, 0);
MODULE_VERSION(atapciacpi, 1);
MODULE_DEPEND(atapciacpi, atapci, 1, 1, 1);
/*Temporally: this should be removed after acpi_name can be accessed without
loading acpi module */
MODULE_DEPEND(atapciacpi, acpi, 1, 1, 1);
More information about the freebsd-acpi
mailing list