libata: bind the Linux device tree to the ACPI device tree
authorMatthew Garrett <mjg@redhat.com>
Mon, 25 Jun 2012 08:13:03 +0000 (16:13 +0800)
committerJeff Garzik <jgarzik@redhat.com>
Fri, 29 Jun 2012 15:38:10 +0000 (11:38 -0400)
Associate the ACPI device tree and libata devices.
This patch uses the generic ACPI glue framework to do so.

Signed-off-by: Matthew Garrett <mjg@redhat.com>
Signed-off-by: Holger Macht <holger@homac.de>
Signed-off-by: Lin Ming <ming.m.lin@intel.com>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
drivers/acpi/glue.c
drivers/ata/libata-acpi.c
drivers/ata/libata-core.c
drivers/ata/libata.h

index 1564e0927c21de130cd134be6371161298709b5e..18d6812a699ef674f52202b251a7c3ed4df3e97c 100644 (file)
@@ -39,6 +39,7 @@ int register_acpi_bus_type(struct acpi_bus_type *type)
        }
        return -ENODEV;
 }
+EXPORT_SYMBOL(register_acpi_bus_type);
 
 int unregister_acpi_bus_type(struct acpi_bus_type *type)
 {
@@ -54,6 +55,7 @@ int unregister_acpi_bus_type(struct acpi_bus_type *type)
        }
        return -ENODEV;
 }
+EXPORT_SYMBOL(unregister_acpi_bus_type);
 
 static struct acpi_bus_type *acpi_get_bus_type(struct bus_type *type)
 {
@@ -69,7 +71,6 @@ static struct acpi_bus_type *acpi_get_bus_type(struct bus_type *type)
        up_read(&bus_type_sem);
        return ret;
 }
-EXPORT_SYMBOL_GPL(register_acpi_bus_type);
 
 static int acpi_find_bridge_device(struct device *dev, acpi_handle * handle)
 {
@@ -86,7 +87,6 @@ static int acpi_find_bridge_device(struct device *dev, acpi_handle * handle)
        up_read(&bus_type_sem);
        return ret;
 }
-EXPORT_SYMBOL_GPL(unregister_acpi_bus_type);
 
 /* Get device's handler per its address under its parent */
 struct acpi_find_child {
index bb7c5f1085ccdfa997671520afc87c4f887eed39..b3025a7d71e3b402b1012a0920f4e49dbd7af3ea 100644 (file)
@@ -47,6 +47,39 @@ static void ata_acpi_clear_gtf(struct ata_device *dev)
        dev->gtf_cache = NULL;
 }
 
+static acpi_handle ap_acpi_handle(struct ata_port *ap)
+{
+       if (ap->flags & ATA_FLAG_ACPI_SATA)
+               return NULL;
+
+       /*
+        * If acpi bind operation has already happened, we can get the handle
+        * for the port by checking the corresponding scsi_host device's
+        * firmware node, otherwise we will need to find out the handle from
+        * its parent's acpi node.
+        */
+       if (ap->scsi_host)
+               return DEVICE_ACPI_HANDLE(&ap->scsi_host->shost_gendev);
+       else
+               return acpi_get_child(DEVICE_ACPI_HANDLE(ap->host->dev),
+                               ap->port_no);
+}
+
+static acpi_handle dev_acpi_handle(struct ata_device *dev)
+{
+       acpi_integer adr;
+       struct ata_port *ap = dev->link->ap;
+
+       if (ap->flags & ATA_FLAG_ACPI_SATA) {
+               if (!sata_pmp_attached(ap))
+                       adr = SATA_ADR(ap->port_no, NO_PORT_MULT);
+               else
+                       adr = SATA_ADR(ap->port_no, dev->link->pmp);
+               return acpi_get_child(DEVICE_ACPI_HANDLE(ap->host->dev), adr);
+       } else
+               return acpi_get_child(ap_acpi_handle(ap), dev->devno);
+}
+
 /**
  * ata_acpi_associate_sata_port - associate SATA port with ACPI objects
  * @ap: target SATA port
@@ -1018,3 +1051,107 @@ void ata_acpi_on_disable(struct ata_device *dev)
 {
        ata_acpi_clear_gtf(dev);
 }
+
+static int compat_pci_ata(struct ata_port *ap)
+{
+       struct device *dev = ap->tdev.parent;
+       struct pci_dev *pdev;
+
+       if (!is_pci_dev(dev))
+               return 0;
+
+       pdev = to_pci_dev(dev);
+
+       if ((pdev->class >> 8) != PCI_CLASS_STORAGE_SATA &&
+           (pdev->class >> 8) != PCI_CLASS_STORAGE_IDE)
+               return 0;
+
+       return 1;
+}
+
+static int ata_acpi_bind_host(struct ata_port *ap, acpi_handle *handle)
+{
+       if (ap->flags & ATA_FLAG_ACPI_SATA)
+               return -ENODEV;
+
+       *handle = acpi_get_child(DEVICE_ACPI_HANDLE(ap->tdev.parent),
+                       ap->port_no);
+
+       if (!*handle)
+               return -ENODEV;
+
+       return 0;
+}
+
+static int ata_acpi_bind_device(struct ata_port *ap, struct scsi_device *sdev,
+                               acpi_handle *handle)
+{
+       struct ata_device *ata_dev;
+
+       if (ap->flags & ATA_FLAG_ACPI_SATA)
+               ata_dev = &ap->link.device[sdev->channel];
+       else
+               ata_dev = &ap->link.device[sdev->id];
+
+       *handle = dev_acpi_handle(ata_dev);
+
+       if (!*handle)
+               return -ENODEV;
+
+       return 0;
+}
+
+static int is_ata_port(const struct device *dev)
+{
+       return dev->type == &ata_port_type;
+}
+
+static struct ata_port *dev_to_ata_port(struct device *dev)
+{
+       while (!is_ata_port(dev)) {
+               if (!dev->parent)
+                       return NULL;
+               dev = dev->parent;
+       }
+       return to_ata_port(dev);
+}
+
+static int ata_acpi_find_device(struct device *dev, acpi_handle *handle)
+{
+       struct ata_port *ap = dev_to_ata_port(dev);
+
+       if (!ap)
+               return -ENODEV;
+
+       if (!compat_pci_ata(ap))
+               return -ENODEV;
+
+       if (scsi_is_host_device(dev))
+               return ata_acpi_bind_host(ap, handle);
+       else if (scsi_is_sdev_device(dev)) {
+               struct scsi_device *sdev = to_scsi_device(dev);
+
+               return ata_acpi_bind_device(ap, sdev, handle);
+       } else
+               return -ENODEV;
+}
+
+static int ata_acpi_find_dummy(struct device *dev, acpi_handle *handle)
+{
+       return -ENODEV;
+}
+
+static struct acpi_bus_type ata_acpi_bus = {
+       .find_bridge = ata_acpi_find_dummy,
+       .find_device = ata_acpi_find_device,
+};
+
+int ata_acpi_register(void)
+{
+       return scsi_register_acpi_bus_type(&ata_acpi_bus);
+}
+
+void ata_acpi_unregister(void)
+{
+       scsi_unregister_acpi_bus_type(&ata_acpi_bus);
+}
index cece3a4d11eaeb70bf2323a53f027d28439bd543..bd33b4a7ac135e2e42ecbb56067582face51317b 100644 (file)
@@ -5288,8 +5288,6 @@ static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
        return rc;
 }
 
-#define to_ata_port(d) container_of(d, struct ata_port, tdev)
-
 static int ata_port_suspend_common(struct device *dev, pm_message_t mesg)
 {
        struct ata_port *ap = to_ata_port(dev);
@@ -6513,6 +6511,8 @@ static int __init ata_init(void)
 
        ata_parse_force_param();
 
+       ata_acpi_register();
+
        rc = ata_sff_init();
        if (rc) {
                kfree(ata_force_tbl);
@@ -6539,6 +6539,7 @@ static void __exit ata_exit(void)
        ata_release_transport(ata_scsi_transport_template);
        libata_transport_exit();
        ata_sff_exit();
+       ata_acpi_unregister();
        kfree(ata_force_tbl);
 }
 
index 9d0fd0b7185224239030e51d42dbe83f27ebbafb..7f48b602b01baaf7f1ff10a0b8829f9b5c871da4 100644 (file)
@@ -107,6 +107,8 @@ extern const char *sata_spd_string(unsigned int spd);
 extern int ata_port_probe(struct ata_port *ap);
 extern void __ata_port_probe(struct ata_port *ap);
 
+#define to_ata_port(d) container_of(d, struct ata_port, tdev)
+
 /* libata-acpi.c */
 #ifdef CONFIG_ATA_ACPI
 extern unsigned int ata_acpi_gtf_filter;
@@ -119,6 +121,8 @@ extern void ata_acpi_on_resume(struct ata_port *ap);
 extern int ata_acpi_on_devcfg(struct ata_device *dev);
 extern void ata_acpi_on_disable(struct ata_device *dev);
 extern void ata_acpi_set_state(struct ata_port *ap, pm_message_t state);
+extern int ata_acpi_register(void);
+extern void ata_acpi_unregister(void);
 #else
 static inline void ata_acpi_associate_sata_port(struct ata_port *ap) { }
 static inline void ata_acpi_associate(struct ata_host *host) { }
@@ -129,6 +133,8 @@ static inline int ata_acpi_on_devcfg(struct ata_device *dev) { return 0; }
 static inline void ata_acpi_on_disable(struct ata_device *dev) { }
 static inline void ata_acpi_set_state(struct ata_port *ap,
                                      pm_message_t state) { }
+static inline int ata_acpi_register(void) { return 0; }
+static void ata_acpi_unregister(void) { }
 #endif
 
 /* libata-scsi.c */