OSDN Git Service

ata: start separating SATA specific code from libata-core.c
authorBartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
Thu, 26 Mar 2020 15:58:11 +0000 (16:58 +0100)
committerJens Axboe <axboe@kernel.dk>
Thu, 26 Mar 2020 16:28:19 +0000 (10:28 -0600)
Start separating SATA specific code from libata-core.c:

* move following functions to libata-sata.c:
  - ata_tf_to_fis()
  - ata_tf_from_fis()
  - sata_link_scr_lpm()
  - ata_slave_link_init()
  - sata_lpm_ignore_phy_events()

* group above functions together in <linux/libata.h>

* include libata-sata.c in the build when CONFIG_SATA_HOST=y

Code size savings on m68k arch using (modified) atari_defconfig:

   text    data     bss     dec     hex filename
before:
  37582     572      40   38194    9532 drivers/ata/libata-core.o
after:
  36762     572      40   37374    91fe drivers/ata/libata-core.o

Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
drivers/ata/Makefile
drivers/ata/libata-core.c
drivers/ata/libata-sata.c [new file with mode: 0644]
include/linux/libata.h

index cdaf965..b8aebfb 100644 (file)
@@ -123,6 +123,7 @@ obj-$(CONFIG_PATA_LEGACY)   += pata_legacy.o
 
 libata-y       := libata-core.o libata-scsi.o libata-eh.o \
        libata-transport.o libata-trace.o
+libata-$(CONFIG_SATA_HOST)     += libata-sata.o
 libata-$(CONFIG_ATA_SFF)       += libata-sff.o
 libata-$(CONFIG_SATA_PMP)      += libata-pmp.o
 libata-$(CONFIG_ATA_ACPI)      += libata-acpi.o
index dcdb7fb..b4a952d 100644 (file)
@@ -531,81 +531,6 @@ int atapi_cmd_type(u8 opcode)
 }
 EXPORT_SYMBOL_GPL(atapi_cmd_type);
 
-/**
- *     ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure
- *     @tf: Taskfile to convert
- *     @pmp: Port multiplier port
- *     @is_cmd: This FIS is for command
- *     @fis: Buffer into which data will output
- *
- *     Converts a standard ATA taskfile to a Serial ATA
- *     FIS structure (Register - Host to Device).
- *
- *     LOCKING:
- *     Inherited from caller.
- */
-void ata_tf_to_fis(const struct ata_taskfile *tf, u8 pmp, int is_cmd, u8 *fis)
-{
-       fis[0] = 0x27;                  /* Register - Host to Device FIS */
-       fis[1] = pmp & 0xf;             /* Port multiplier number*/
-       if (is_cmd)
-               fis[1] |= (1 << 7);     /* bit 7 indicates Command FIS */
-
-       fis[2] = tf->command;
-       fis[3] = tf->feature;
-
-       fis[4] = tf->lbal;
-       fis[5] = tf->lbam;
-       fis[6] = tf->lbah;
-       fis[7] = tf->device;
-
-       fis[8] = tf->hob_lbal;
-       fis[9] = tf->hob_lbam;
-       fis[10] = tf->hob_lbah;
-       fis[11] = tf->hob_feature;
-
-       fis[12] = tf->nsect;
-       fis[13] = tf->hob_nsect;
-       fis[14] = 0;
-       fis[15] = tf->ctl;
-
-       fis[16] = tf->auxiliary & 0xff;
-       fis[17] = (tf->auxiliary >> 8) & 0xff;
-       fis[18] = (tf->auxiliary >> 16) & 0xff;
-       fis[19] = (tf->auxiliary >> 24) & 0xff;
-}
-EXPORT_SYMBOL_GPL(ata_tf_to_fis);
-
-/**
- *     ata_tf_from_fis - Convert SATA FIS to ATA taskfile
- *     @fis: Buffer from which data will be input
- *     @tf: Taskfile to output
- *
- *     Converts a serial ATA FIS structure to a standard ATA taskfile.
- *
- *     LOCKING:
- *     Inherited from caller.
- */
-
-void ata_tf_from_fis(const u8 *fis, struct ata_taskfile *tf)
-{
-       tf->command     = fis[2];       /* status */
-       tf->feature     = fis[3];       /* error */
-
-       tf->lbal        = fis[4];
-       tf->lbam        = fis[5];
-       tf->lbah        = fis[6];
-       tf->device      = fis[7];
-
-       tf->hob_lbal    = fis[8];
-       tf->hob_lbam    = fis[9];
-       tf->hob_lbah    = fis[10];
-
-       tf->nsect       = fis[12];
-       tf->hob_nsect   = fis[13];
-}
-EXPORT_SYMBOL_GPL(ata_tf_from_fis);
-
 static const u8 ata_rw_cmds[] = {
        /* pio multi */
        ATA_CMD_READ_MULTI,
@@ -3780,81 +3705,6 @@ int sata_link_resume(struct ata_link *link, const unsigned long *params,
 EXPORT_SYMBOL_GPL(sata_link_resume);
 
 /**
- *     sata_link_scr_lpm - manipulate SControl IPM and SPM fields
- *     @link: ATA link to manipulate SControl for
- *     @policy: LPM policy to configure
- *     @spm_wakeup: initiate LPM transition to active state
- *
- *     Manipulate the IPM field of the SControl register of @link
- *     according to @policy.  If @policy is ATA_LPM_MAX_POWER and
- *     @spm_wakeup is %true, the SPM field is manipulated to wake up
- *     the link.  This function also clears PHYRDY_CHG before
- *     returning.
- *
- *     LOCKING:
- *     EH context.
- *
- *     RETURNS:
- *     0 on success, -errno otherwise.
- */
-int sata_link_scr_lpm(struct ata_link *link, enum ata_lpm_policy policy,
-                     bool spm_wakeup)
-{
-       struct ata_eh_context *ehc = &link->eh_context;
-       bool woken_up = false;
-       u32 scontrol;
-       int rc;
-
-       rc = sata_scr_read(link, SCR_CONTROL, &scontrol);
-       if (rc)
-               return rc;
-
-       switch (policy) {
-       case ATA_LPM_MAX_POWER:
-               /* disable all LPM transitions */
-               scontrol |= (0x7 << 8);
-               /* initiate transition to active state */
-               if (spm_wakeup) {
-                       scontrol |= (0x4 << 12);
-                       woken_up = true;
-               }
-               break;
-       case ATA_LPM_MED_POWER:
-               /* allow LPM to PARTIAL */
-               scontrol &= ~(0x1 << 8);
-               scontrol |= (0x6 << 8);
-               break;
-       case ATA_LPM_MED_POWER_WITH_DIPM:
-       case ATA_LPM_MIN_POWER_WITH_PARTIAL:
-       case ATA_LPM_MIN_POWER:
-               if (ata_link_nr_enabled(link) > 0)
-                       /* no restrictions on LPM transitions */
-                       scontrol &= ~(0x7 << 8);
-               else {
-                       /* empty port, power off */
-                       scontrol &= ~0xf;
-                       scontrol |= (0x1 << 2);
-               }
-               break;
-       default:
-               WARN_ON(1);
-       }
-
-       rc = sata_scr_write(link, SCR_CONTROL, scontrol);
-       if (rc)
-               return rc;
-
-       /* give the link time to transit out of LPM state */
-       if (woken_up)
-               msleep(10);
-
-       /* clear PHYRDY_CHG from SError */
-       ehc->i.serror &= ~SERR_PHYRDY_CHG;
-       return sata_scr_write(link, SCR_ERROR, SERR_PHYRDY_CHG);
-}
-EXPORT_SYMBOL_GPL(sata_link_scr_lpm);
-
-/**
  *     ata_std_prereset - prepare for reset
  *     @link: ATA link to be reset
  *     @deadline: deadline jiffies for the operation
@@ -6118,69 +5968,6 @@ struct ata_host *ata_host_alloc_pinfo(struct device *dev,
 }
 EXPORT_SYMBOL_GPL(ata_host_alloc_pinfo);
 
-/**
- *     ata_slave_link_init - initialize slave link
- *     @ap: port to initialize slave link for
- *
- *     Create and initialize slave link for @ap.  This enables slave
- *     link handling on the port.
- *
- *     In libata, a port contains links and a link contains devices.
- *     There is single host link but if a PMP is attached to it,
- *     there can be multiple fan-out links.  On SATA, there's usually
- *     a single device connected to a link but PATA and SATA
- *     controllers emulating TF based interface can have two - master
- *     and slave.
- *
- *     However, there are a few controllers which don't fit into this
- *     abstraction too well - SATA controllers which emulate TF
- *     interface with both master and slave devices but also have
- *     separate SCR register sets for each device.  These controllers
- *     need separate links for physical link handling
- *     (e.g. onlineness, link speed) but should be treated like a
- *     traditional M/S controller for everything else (e.g. command
- *     issue, softreset).
- *
- *     slave_link is libata's way of handling this class of
- *     controllers without impacting core layer too much.  For
- *     anything other than physical link handling, the default host
- *     link is used for both master and slave.  For physical link
- *     handling, separate @ap->slave_link is used.  All dirty details
- *     are implemented inside libata core layer.  From LLD's POV, the
- *     only difference is that prereset, hardreset and postreset are
- *     called once more for the slave link, so the reset sequence
- *     looks like the following.
- *
- *     prereset(M) -> prereset(S) -> hardreset(M) -> hardreset(S) ->
- *     softreset(M) -> postreset(M) -> postreset(S)
- *
- *     Note that softreset is called only for the master.  Softreset
- *     resets both M/S by definition, so SRST on master should handle
- *     both (the standard method will work just fine).
- *
- *     LOCKING:
- *     Should be called before host is registered.
- *
- *     RETURNS:
- *     0 on success, -errno on failure.
- */
-int ata_slave_link_init(struct ata_port *ap)
-{
-       struct ata_link *link;
-
-       WARN_ON(ap->slave_link);
-       WARN_ON(ap->flags & ATA_FLAG_PMP);
-
-       link = kzalloc(sizeof(*link), GFP_KERNEL);
-       if (!link)
-               return -ENOMEM;
-
-       ata_link_init(ap, link, 1);
-       ap->slave_link = link;
-       return 0;
-}
-EXPORT_SYMBOL_GPL(ata_slave_link_init);
-
 static void ata_host_stop(struct device *gendev, void *res)
 {
        struct ata_host *host = dev_get_drvdata(gendev);
@@ -7106,38 +6893,6 @@ u32 ata_wait_register(struct ata_port *ap, void __iomem *reg, u32 mask, u32 val,
 }
 EXPORT_SYMBOL_GPL(ata_wait_register);
 
-/**
- *     sata_lpm_ignore_phy_events - test if PHY event should be ignored
- *     @link: Link receiving the event
- *
- *     Test whether the received PHY event has to be ignored or not.
- *
- *     LOCKING:
- *     None:
- *
- *     RETURNS:
- *     True if the event has to be ignored.
- */
-bool sata_lpm_ignore_phy_events(struct ata_link *link)
-{
-       unsigned long lpm_timeout = link->last_lpm_change +
-                                   msecs_to_jiffies(ATA_TMOUT_SPURIOUS_PHY);
-
-       /* if LPM is enabled, PHYRDY doesn't mean anything */
-       if (link->lpm_policy > ATA_LPM_MAX_POWER)
-               return true;
-
-       /* ignore the first PHY event after the LPM policy changed
-        * as it is might be spurious
-        */
-       if ((link->flags & ATA_LFLAG_CHANGED) &&
-           time_before(jiffies, lpm_timeout))
-               return true;
-
-       return false;
-}
-EXPORT_SYMBOL_GPL(sata_lpm_ignore_phy_events);
-
 /*
  * Dummy port_ops
  */
diff --git a/drivers/ata/libata-sata.c b/drivers/ata/libata-sata.c
new file mode 100644 (file)
index 0000000..04f1eca
--- /dev/null
@@ -0,0 +1,258 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *  SATA specific part of ATA helper library
+ *
+ *  Copyright 2003-2004 Red Hat, Inc.  All rights reserved.
+ *  Copyright 2003-2004 Jeff Garzik
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/libata.h>
+
+#include "libata.h"
+
+/**
+ *     ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure
+ *     @tf: Taskfile to convert
+ *     @pmp: Port multiplier port
+ *     @is_cmd: This FIS is for command
+ *     @fis: Buffer into which data will output
+ *
+ *     Converts a standard ATA taskfile to a Serial ATA
+ *     FIS structure (Register - Host to Device).
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
+void ata_tf_to_fis(const struct ata_taskfile *tf, u8 pmp, int is_cmd, u8 *fis)
+{
+       fis[0] = 0x27;                  /* Register - Host to Device FIS */
+       fis[1] = pmp & 0xf;             /* Port multiplier number*/
+       if (is_cmd)
+               fis[1] |= (1 << 7);     /* bit 7 indicates Command FIS */
+
+       fis[2] = tf->command;
+       fis[3] = tf->feature;
+
+       fis[4] = tf->lbal;
+       fis[5] = tf->lbam;
+       fis[6] = tf->lbah;
+       fis[7] = tf->device;
+
+       fis[8] = tf->hob_lbal;
+       fis[9] = tf->hob_lbam;
+       fis[10] = tf->hob_lbah;
+       fis[11] = tf->hob_feature;
+
+       fis[12] = tf->nsect;
+       fis[13] = tf->hob_nsect;
+       fis[14] = 0;
+       fis[15] = tf->ctl;
+
+       fis[16] = tf->auxiliary & 0xff;
+       fis[17] = (tf->auxiliary >> 8) & 0xff;
+       fis[18] = (tf->auxiliary >> 16) & 0xff;
+       fis[19] = (tf->auxiliary >> 24) & 0xff;
+}
+EXPORT_SYMBOL_GPL(ata_tf_to_fis);
+
+/**
+ *     ata_tf_from_fis - Convert SATA FIS to ATA taskfile
+ *     @fis: Buffer from which data will be input
+ *     @tf: Taskfile to output
+ *
+ *     Converts a serial ATA FIS structure to a standard ATA taskfile.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
+
+void ata_tf_from_fis(const u8 *fis, struct ata_taskfile *tf)
+{
+       tf->command     = fis[2];       /* status */
+       tf->feature     = fis[3];       /* error */
+
+       tf->lbal        = fis[4];
+       tf->lbam        = fis[5];
+       tf->lbah        = fis[6];
+       tf->device      = fis[7];
+
+       tf->hob_lbal    = fis[8];
+       tf->hob_lbam    = fis[9];
+       tf->hob_lbah    = fis[10];
+
+       tf->nsect       = fis[12];
+       tf->hob_nsect   = fis[13];
+}
+EXPORT_SYMBOL_GPL(ata_tf_from_fis);
+
+/**
+ *     sata_link_scr_lpm - manipulate SControl IPM and SPM fields
+ *     @link: ATA link to manipulate SControl for
+ *     @policy: LPM policy to configure
+ *     @spm_wakeup: initiate LPM transition to active state
+ *
+ *     Manipulate the IPM field of the SControl register of @link
+ *     according to @policy.  If @policy is ATA_LPM_MAX_POWER and
+ *     @spm_wakeup is %true, the SPM field is manipulated to wake up
+ *     the link.  This function also clears PHYRDY_CHG before
+ *     returning.
+ *
+ *     LOCKING:
+ *     EH context.
+ *
+ *     RETURNS:
+ *     0 on success, -errno otherwise.
+ */
+int sata_link_scr_lpm(struct ata_link *link, enum ata_lpm_policy policy,
+                     bool spm_wakeup)
+{
+       struct ata_eh_context *ehc = &link->eh_context;
+       bool woken_up = false;
+       u32 scontrol;
+       int rc;
+
+       rc = sata_scr_read(link, SCR_CONTROL, &scontrol);
+       if (rc)
+               return rc;
+
+       switch (policy) {
+       case ATA_LPM_MAX_POWER:
+               /* disable all LPM transitions */
+               scontrol |= (0x7 << 8);
+               /* initiate transition to active state */
+               if (spm_wakeup) {
+                       scontrol |= (0x4 << 12);
+                       woken_up = true;
+               }
+               break;
+       case ATA_LPM_MED_POWER:
+               /* allow LPM to PARTIAL */
+               scontrol &= ~(0x1 << 8);
+               scontrol |= (0x6 << 8);
+               break;
+       case ATA_LPM_MED_POWER_WITH_DIPM:
+       case ATA_LPM_MIN_POWER_WITH_PARTIAL:
+       case ATA_LPM_MIN_POWER:
+               if (ata_link_nr_enabled(link) > 0)
+                       /* no restrictions on LPM transitions */
+                       scontrol &= ~(0x7 << 8);
+               else {
+                       /* empty port, power off */
+                       scontrol &= ~0xf;
+                       scontrol |= (0x1 << 2);
+               }
+               break;
+       default:
+               WARN_ON(1);
+       }
+
+       rc = sata_scr_write(link, SCR_CONTROL, scontrol);
+       if (rc)
+               return rc;
+
+       /* give the link time to transit out of LPM state */
+       if (woken_up)
+               msleep(10);
+
+       /* clear PHYRDY_CHG from SError */
+       ehc->i.serror &= ~SERR_PHYRDY_CHG;
+       return sata_scr_write(link, SCR_ERROR, SERR_PHYRDY_CHG);
+}
+EXPORT_SYMBOL_GPL(sata_link_scr_lpm);
+
+/**
+ *     ata_slave_link_init - initialize slave link
+ *     @ap: port to initialize slave link for
+ *
+ *     Create and initialize slave link for @ap.  This enables slave
+ *     link handling on the port.
+ *
+ *     In libata, a port contains links and a link contains devices.
+ *     There is single host link but if a PMP is attached to it,
+ *     there can be multiple fan-out links.  On SATA, there's usually
+ *     a single device connected to a link but PATA and SATA
+ *     controllers emulating TF based interface can have two - master
+ *     and slave.
+ *
+ *     However, there are a few controllers which don't fit into this
+ *     abstraction too well - SATA controllers which emulate TF
+ *     interface with both master and slave devices but also have
+ *     separate SCR register sets for each device.  These controllers
+ *     need separate links for physical link handling
+ *     (e.g. onlineness, link speed) but should be treated like a
+ *     traditional M/S controller for everything else (e.g. command
+ *     issue, softreset).
+ *
+ *     slave_link is libata's way of handling this class of
+ *     controllers without impacting core layer too much.  For
+ *     anything other than physical link handling, the default host
+ *     link is used for both master and slave.  For physical link
+ *     handling, separate @ap->slave_link is used.  All dirty details
+ *     are implemented inside libata core layer.  From LLD's POV, the
+ *     only difference is that prereset, hardreset and postreset are
+ *     called once more for the slave link, so the reset sequence
+ *     looks like the following.
+ *
+ *     prereset(M) -> prereset(S) -> hardreset(M) -> hardreset(S) ->
+ *     softreset(M) -> postreset(M) -> postreset(S)
+ *
+ *     Note that softreset is called only for the master.  Softreset
+ *     resets both M/S by definition, so SRST on master should handle
+ *     both (the standard method will work just fine).
+ *
+ *     LOCKING:
+ *     Should be called before host is registered.
+ *
+ *     RETURNS:
+ *     0 on success, -errno on failure.
+ */
+int ata_slave_link_init(struct ata_port *ap)
+{
+       struct ata_link *link;
+
+       WARN_ON(ap->slave_link);
+       WARN_ON(ap->flags & ATA_FLAG_PMP);
+
+       link = kzalloc(sizeof(*link), GFP_KERNEL);
+       if (!link)
+               return -ENOMEM;
+
+       ata_link_init(ap, link, 1);
+       ap->slave_link = link;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ata_slave_link_init);
+
+/**
+ *     sata_lpm_ignore_phy_events - test if PHY event should be ignored
+ *     @link: Link receiving the event
+ *
+ *     Test whether the received PHY event has to be ignored or not.
+ *
+ *     LOCKING:
+ *     None:
+ *
+ *     RETURNS:
+ *     True if the event has to be ignored.
+ */
+bool sata_lpm_ignore_phy_events(struct ata_link *link)
+{
+       unsigned long lpm_timeout = link->last_lpm_change +
+                                   msecs_to_jiffies(ATA_TMOUT_SPURIOUS_PHY);
+
+       /* if LPM is enabled, PHYRDY doesn't mean anything */
+       if (link->lpm_policy > ATA_LPM_MAX_POWER)
+               return true;
+
+       /* ignore the first PHY event after the LPM policy changed
+        * as it is might be spurious
+        */
+       if ((link->flags & ATA_LFLAG_CHANGED) &&
+           time_before(jiffies, lpm_timeout))
+               return true;
+
+       return false;
+}
+EXPORT_SYMBOL_GPL(sata_lpm_ignore_phy_events);
index 661d760..b419d74 100644 (file)
@@ -1082,8 +1082,6 @@ extern int sata_link_debounce(struct ata_link *link,
                        const unsigned long *params, unsigned long deadline);
 extern int sata_link_resume(struct ata_link *link, const unsigned long *params,
                            unsigned long deadline);
-extern int sata_link_scr_lpm(struct ata_link *link, enum ata_lpm_policy policy,
-                            bool spm_wakeup);
 extern int sata_link_hardreset(struct ata_link *link,
                        const unsigned long *timing, unsigned long deadline,
                        bool *online, int (*check_ready)(struct ata_link *));
@@ -1094,7 +1092,6 @@ extern void ata_std_postreset(struct ata_link *link, unsigned int *classes);
 extern struct ata_host *ata_host_alloc(struct device *dev, int max_ports);
 extern struct ata_host *ata_host_alloc_pinfo(struct device *dev,
                        const struct ata_port_info * const * ppi, int n_ports);
-extern int ata_slave_link_init(struct ata_port *ap);
 extern void ata_host_get(struct ata_host *host);
 extern void ata_host_put(struct ata_host *host);
 extern int ata_host_start(struct ata_host *host);
@@ -1152,9 +1149,6 @@ extern void ata_msleep(struct ata_port *ap, unsigned int msecs);
 extern u32 ata_wait_register(struct ata_port *ap, void __iomem *reg, u32 mask,
                        u32 val, unsigned long interval, unsigned long timeout);
 extern int atapi_cmd_type(u8 opcode);
-extern void ata_tf_to_fis(const struct ata_taskfile *tf,
-                         u8 pmp, int is_cmd, u8 *fis);
-extern void ata_tf_from_fis(const u8 *fis, struct ata_taskfile *tf);
 extern unsigned long ata_pack_xfermask(unsigned long pio_mask,
                        unsigned long mwdma_mask, unsigned long udma_mask);
 extern void ata_unpack_xfermask(unsigned long xfer_mask,
@@ -1195,6 +1189,16 @@ extern struct ata_device *ata_dev_pair(struct ata_device *adev);
 extern int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev);
 extern void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap);
 extern void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap, struct list_head *eh_q);
+
+/*
+ * SATA specific code - drivers/ata/libata-sata.c
+ */
+extern int sata_link_scr_lpm(struct ata_link *link, enum ata_lpm_policy policy,
+                            bool spm_wakeup);
+extern int ata_slave_link_init(struct ata_port *ap);
+extern void ata_tf_to_fis(const struct ata_taskfile *tf,
+                         u8 pmp, int is_cmd, u8 *fis);
+extern void ata_tf_from_fis(const u8 *fis, struct ata_taskfile *tf);
 extern bool sata_lpm_ignore_phy_events(struct ata_link *link);
 
 extern int ata_cable_40wire(struct ata_port *ap);