All of lore.kernel.org
 help / color / mirror / Atom feed
From: Rob Herring <robh@kernel.org>
To: linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org, soc@kernel.org,
	Andre Przywara <andre.przywara@arm.com>,
	Robert Richter <rrichter@marvell.com>, Jon Loeliger <jdl@jdl.com>,
	Alexander Graf <graf@amazon.com>,
	Matthias Brugger <mbrugger@suse.com>,
	Mark Langsdorf <mlangsdo@redhat.com>
Cc: Alex Williamson <alex.williamson@redhat.com>,
	Borislav Petkov <bp@alien8.de>, Cornelia Huck <cohuck@redhat.com>,
	Daniel Lezcano <daniel.lezcano@linaro.org>,
	"David S. Miller" <davem@davemloft.net>,
	devicetree@vger.kernel.org, Eric Auger <eric.auger@redhat.com>,
	iommu@lists.linux-foundation.org,
	James Morse <james.morse@arm.com>, Jens Axboe <axboe@kernel.dk>,
	Joerg Roedel <joro@8bytes.org>,
	kvm@vger.kernel.org, linux-clk@vger.kernel.org,
	linux-edac@vger.kernel.org, linux-ide@vger.kernel.org,
	linux-pm@vger.kernel.org,
	Mauro Carvalho Chehab <mchehab@kernel.org>,
	netdev@vger.kernel.org, "Rafael J. Wysocki" <rjw@rjwysocki.net>,
	Robin Murphy <robin.murphy@arm.com>,
	Stephen Boyd <sboyd@kernel.org>, Tony Luck <tony.luck@intel.com>,
	Viresh Kumar <viresh.kumar@linaro.org>,
	Will Deacon <will@kernel.org>
Subject: [RFC PATCH 02/11] ata: Remove Calxeda AHCI driver
Date: Tue, 18 Feb 2020 11:13:12 -0600	[thread overview]
Message-ID: <20200218171321.30990-3-robh@kernel.org> (raw)
In-Reply-To: <20200218171321.30990-1-robh@kernel.org>

Cc: Jens Axboe <axboe@kernel.dk>
Cc: linux-ide@vger.kernel.org
Signed-off-by: Rob Herring <robh@kernel.org>
---
Do not apply yet.

 drivers/ata/Kconfig         |   9 -
 drivers/ata/Makefile        |   1 -
 drivers/ata/sata_highbank.c | 635 ------------------------------------
 3 files changed, 645 deletions(-)
 delete mode 100644 drivers/ata/sata_highbank.c

diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index a6beb2c5a692..687ddd9f4188 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -395,15 +395,6 @@ config SATA_DWC_VDEBUG
 	help
 	  This option enables the taskfile dumping and NCQ debugging.

-config SATA_HIGHBANK
-	tristate "Calxeda Highbank SATA support"
-	depends on ARCH_HIGHBANK || COMPILE_TEST
-	help
-	  This option enables support for the Calxeda Highbank SoC's
-	  onboard SATA.
-
-	  If unsure, say N.
-
 config SATA_MV
 	tristate "Marvell SATA support"
 	depends on PCI || ARCH_DOVE || ARCH_MV78XX0 || \
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index d8cc2e04a6c7..08f26d674ed7 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -12,7 +12,6 @@ obj-$(CONFIG_SATA_GEMINI)	+= sata_gemini.o
 obj-$(CONFIG_SATA_INIC162X)	+= sata_inic162x.o
 obj-$(CONFIG_SATA_SIL24)	+= sata_sil24.o
 obj-$(CONFIG_SATA_DWC)		+= sata_dwc_460ex.o
-obj-$(CONFIG_SATA_HIGHBANK)	+= sata_highbank.o libahci.o
 obj-$(CONFIG_AHCI_BRCM)		+= ahci_brcm.o libahci.o libahci_platform.o
 obj-$(CONFIG_AHCI_CEVA)		+= ahci_ceva.o libahci.o libahci_platform.o
 obj-$(CONFIG_AHCI_DA850)	+= ahci_da850.o libahci.o libahci_platform.o
diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c
deleted file mode 100644
index ad3893c62572..000000000000
--- a/drivers/ata/sata_highbank.c
+++ /dev/null
@@ -1,635 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Calxeda Highbank AHCI SATA platform driver
- * Copyright 2012 Calxeda, Inc.
- *
- * based on the AHCI SATA platform driver by Jeff Garzik and Anton Vorontsov
- */
-#include <linux/kernel.h>
-#include <linux/gfp.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/spinlock.h>
-#include <linux/device.h>
-#include <linux/of_device.h>
-#include <linux/of_address.h>
-#include <linux/platform_device.h>
-#include <linux/libata.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/export.h>
-#include <linux/gpio/consumer.h>
-
-#include "ahci.h"
-
-#define CPHY_MAP(dev, addr) ((((dev) & 0x1f) << 7) | (((addr) >> 9) & 0x7f))
-#define CPHY_ADDR(addr) (((addr) & 0x1ff) << 2)
-#define SERDES_CR_CTL			0x80a0
-#define SERDES_CR_ADDR			0x80a1
-#define SERDES_CR_DATA			0x80a2
-#define CR_BUSY				0x0001
-#define CR_START			0x0001
-#define CR_WR_RDN			0x0002
-#define CPHY_TX_INPUT_STS		0x2001
-#define CPHY_RX_INPUT_STS		0x2002
-#define CPHY_SATA_TX_OVERRIDE		0x8000
-#define CPHY_SATA_RX_OVERRIDE	 	0x4000
-#define CPHY_TX_OVERRIDE		0x2004
-#define CPHY_RX_OVERRIDE		0x2005
-#define SPHY_LANE			0x100
-#define SPHY_HALF_RATE			0x0001
-#define CPHY_SATA_DPLL_MODE		0x0700
-#define CPHY_SATA_DPLL_SHIFT		8
-#define CPHY_SATA_DPLL_RESET		(1 << 11)
-#define CPHY_SATA_TX_ATTEN		0x1c00
-#define CPHY_SATA_TX_ATTEN_SHIFT	10
-#define CPHY_PHY_COUNT			6
-#define CPHY_LANE_COUNT			4
-#define CPHY_PORT_COUNT			(CPHY_PHY_COUNT * CPHY_LANE_COUNT)
-
-static DEFINE_SPINLOCK(cphy_lock);
-/* Each of the 6 phys can have up to 4 sata ports attached to i. Map 0-based
- * sata ports to their phys and then to their lanes within the phys
- */
-struct phy_lane_info {
-	void __iomem *phy_base;
-	u8 lane_mapping;
-	u8 phy_devs;
-	u8 tx_atten;
-};
-static struct phy_lane_info port_data[CPHY_PORT_COUNT];
-
-static DEFINE_SPINLOCK(sgpio_lock);
-#define SCLOCK				0
-#define SLOAD				1
-#define SDATA				2
-#define SGPIO_PINS			3
-#define SGPIO_PORTS			8
-
-struct ecx_plat_data {
-	u32		n_ports;
-	/* number of extra clocks that the SGPIO PIC controller expects */
-	u32		pre_clocks;
-	u32		post_clocks;
-	struct gpio_desc *sgpio_gpiod[SGPIO_PINS];
-	u32		sgpio_pattern;
-	u32		port_to_sgpio[SGPIO_PORTS];
-};
-
-#define SGPIO_SIGNALS			3
-#define ECX_ACTIVITY_BITS		0x300000
-#define ECX_ACTIVITY_SHIFT		0
-#define ECX_LOCATE_BITS			0x80000
-#define ECX_LOCATE_SHIFT		1
-#define ECX_FAULT_BITS			0x400000
-#define ECX_FAULT_SHIFT			2
-static inline int sgpio_bit_shift(struct ecx_plat_data *pdata, u32 port,
-				u32 shift)
-{
-	return 1 << (3 * pdata->port_to_sgpio[port] + shift);
-}
-
-static void ecx_parse_sgpio(struct ecx_plat_data *pdata, u32 port, u32 state)
-{
-	if (state & ECX_ACTIVITY_BITS)
-		pdata->sgpio_pattern |= sgpio_bit_shift(pdata, port,
-						ECX_ACTIVITY_SHIFT);
-	else
-		pdata->sgpio_pattern &= ~sgpio_bit_shift(pdata, port,
-						ECX_ACTIVITY_SHIFT);
-	if (state & ECX_LOCATE_BITS)
-		pdata->sgpio_pattern |= sgpio_bit_shift(pdata, port,
-						ECX_LOCATE_SHIFT);
-	else
-		pdata->sgpio_pattern &= ~sgpio_bit_shift(pdata, port,
-						ECX_LOCATE_SHIFT);
-	if (state & ECX_FAULT_BITS)
-		pdata->sgpio_pattern |= sgpio_bit_shift(pdata, port,
-						ECX_FAULT_SHIFT);
-	else
-		pdata->sgpio_pattern &= ~sgpio_bit_shift(pdata, port,
-						ECX_FAULT_SHIFT);
-}
-
-/*
- * Tell the LED controller that the signal has changed by raising the clock
- * line for 50 uS and then lowering it for 50 uS.
- */
-static void ecx_led_cycle_clock(struct ecx_plat_data *pdata)
-{
-	gpiod_set_value(pdata->sgpio_gpiod[SCLOCK], 1);
-	udelay(50);
-	gpiod_set_value(pdata->sgpio_gpiod[SCLOCK], 0);
-	udelay(50);
-}
-
-static ssize_t ecx_transmit_led_message(struct ata_port *ap, u32 state,
-					ssize_t size)
-{
-	struct ahci_host_priv *hpriv =  ap->host->private_data;
-	struct ecx_plat_data *pdata = hpriv->plat_data;
-	struct ahci_port_priv *pp = ap->private_data;
-	unsigned long flags;
-	int pmp, i;
-	struct ahci_em_priv *emp;
-	u32 sgpio_out;
-
-	/* get the slot number from the message */
-	pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8;
-	if (pmp < EM_MAX_SLOTS)
-		emp = &pp->em_priv[pmp];
-	else
-		return -EINVAL;
-
-	if (!(hpriv->em_msg_type & EM_MSG_TYPE_LED))
-		return size;
-
-	spin_lock_irqsave(&sgpio_lock, flags);
-	ecx_parse_sgpio(pdata, ap->port_no, state);
-	sgpio_out = pdata->sgpio_pattern;
-	for (i = 0; i < pdata->pre_clocks; i++)
-		ecx_led_cycle_clock(pdata);
-
-	gpiod_set_value(pdata->sgpio_gpiod[SLOAD], 1);
-	ecx_led_cycle_clock(pdata);
-	gpiod_set_value(pdata->sgpio_gpiod[SLOAD], 0);
-	/*
-	 * bit-bang out the SGPIO pattern, by consuming a bit and then
-	 * clocking it out.
-	 */
-	for (i = 0; i < (SGPIO_SIGNALS * pdata->n_ports); i++) {
-		gpiod_set_value(pdata->sgpio_gpiod[SDATA], sgpio_out & 1);
-		sgpio_out >>= 1;
-		ecx_led_cycle_clock(pdata);
-	}
-	for (i = 0; i < pdata->post_clocks; i++)
-		ecx_led_cycle_clock(pdata);
-
-	/* save off new led state for port/slot */
-	emp->led_state = state;
-
-	spin_unlock_irqrestore(&sgpio_lock, flags);
-	return size;
-}
-
-static void highbank_set_em_messages(struct device *dev,
-					struct ahci_host_priv *hpriv,
-					struct ata_port_info *pi)
-{
-	struct device_node *np = dev->of_node;
-	struct ecx_plat_data *pdata = hpriv->plat_data;
-	int i;
-
-	for (i = 0; i < SGPIO_PINS; i++) {
-		struct gpio_desc *gpiod;
-
-		gpiod = devm_gpiod_get_index(dev, "calxeda,sgpio", i,
-					     GPIOD_OUT_HIGH);
-		if (IS_ERR(gpiod)) {
-			dev_err(dev, "failed to get GPIO %d\n", i);
-			continue;
-		}
-		gpiod_set_consumer_name(gpiod, "CX SGPIO");
-
-		pdata->sgpio_gpiod[i] = gpiod;
-	}
-	of_property_read_u32_array(np, "calxeda,led-order",
-						pdata->port_to_sgpio,
-						pdata->n_ports);
-	if (of_property_read_u32(np, "calxeda,pre-clocks", &pdata->pre_clocks))
-		pdata->pre_clocks = 0;
-	if (of_property_read_u32(np, "calxeda,post-clocks",
-				&pdata->post_clocks))
-		pdata->post_clocks = 0;
-
-	/* store em_loc */
-	hpriv->em_loc = 0;
-	hpriv->em_buf_sz = 4;
-	hpriv->em_msg_type = EM_MSG_TYPE_LED;
-	pi->flags |= ATA_FLAG_EM | ATA_FLAG_SW_ACTIVITY;
-}
-
-static u32 __combo_phy_reg_read(u8 sata_port, u32 addr)
-{
-	u32 data;
-	u8 dev = port_data[sata_port].phy_devs;
-	spin_lock(&cphy_lock);
-	writel(CPHY_MAP(dev, addr), port_data[sata_port].phy_base + 0x800);
-	data = readl(port_data[sata_port].phy_base + CPHY_ADDR(addr));
-	spin_unlock(&cphy_lock);
-	return data;
-}
-
-static void __combo_phy_reg_write(u8 sata_port, u32 addr, u32 data)
-{
-	u8 dev = port_data[sata_port].phy_devs;
-	spin_lock(&cphy_lock);
-	writel(CPHY_MAP(dev, addr), port_data[sata_port].phy_base + 0x800);
-	writel(data, port_data[sata_port].phy_base + CPHY_ADDR(addr));
-	spin_unlock(&cphy_lock);
-}
-
-static void combo_phy_wait_for_ready(u8 sata_port)
-{
-	while (__combo_phy_reg_read(sata_port, SERDES_CR_CTL) & CR_BUSY)
-		udelay(5);
-}
-
-static u32 combo_phy_read(u8 sata_port, u32 addr)
-{
-	combo_phy_wait_for_ready(sata_port);
-	__combo_phy_reg_write(sata_port, SERDES_CR_ADDR, addr);
-	__combo_phy_reg_write(sata_port, SERDES_CR_CTL, CR_START);
-	combo_phy_wait_for_ready(sata_port);
-	return __combo_phy_reg_read(sata_port, SERDES_CR_DATA);
-}
-
-static void combo_phy_write(u8 sata_port, u32 addr, u32 data)
-{
-	combo_phy_wait_for_ready(sata_port);
-	__combo_phy_reg_write(sata_port, SERDES_CR_ADDR, addr);
-	__combo_phy_reg_write(sata_port, SERDES_CR_DATA, data);
-	__combo_phy_reg_write(sata_port, SERDES_CR_CTL, CR_WR_RDN | CR_START);
-}
-
-static void highbank_cphy_disable_overrides(u8 sata_port)
-{
-	u8 lane = port_data[sata_port].lane_mapping;
-	u32 tmp;
-	if (unlikely(port_data[sata_port].phy_base == NULL))
-		return;
-	tmp = combo_phy_read(sata_port, CPHY_RX_INPUT_STS + lane * SPHY_LANE);
-	tmp &= ~CPHY_SATA_RX_OVERRIDE;
-	combo_phy_write(sata_port, CPHY_RX_OVERRIDE + lane * SPHY_LANE, tmp);
-}
-
-static void cphy_override_tx_attenuation(u8 sata_port, u32 val)
-{
-	u8 lane = port_data[sata_port].lane_mapping;
-	u32 tmp;
-
-	if (val & 0x8)
-		return;
-
-	tmp = combo_phy_read(sata_port, CPHY_TX_INPUT_STS + lane * SPHY_LANE);
-	tmp &= ~CPHY_SATA_TX_OVERRIDE;
-	combo_phy_write(sata_port, CPHY_TX_OVERRIDE + lane * SPHY_LANE, tmp);
-
-	tmp |= CPHY_SATA_TX_OVERRIDE;
-	combo_phy_write(sata_port, CPHY_TX_OVERRIDE + lane * SPHY_LANE, tmp);
-
-	tmp |= (val << CPHY_SATA_TX_ATTEN_SHIFT) & CPHY_SATA_TX_ATTEN;
-	combo_phy_write(sata_port, CPHY_TX_OVERRIDE + lane * SPHY_LANE, tmp);
-}
-
-static void cphy_override_rx_mode(u8 sata_port, u32 val)
-{
-	u8 lane = port_data[sata_port].lane_mapping;
-	u32 tmp;
-	tmp = combo_phy_read(sata_port, CPHY_RX_INPUT_STS + lane * SPHY_LANE);
-	tmp &= ~CPHY_SATA_RX_OVERRIDE;
-	combo_phy_write(sata_port, CPHY_RX_OVERRIDE + lane * SPHY_LANE, tmp);
-
-	tmp |= CPHY_SATA_RX_OVERRIDE;
-	combo_phy_write(sata_port, CPHY_RX_OVERRIDE + lane * SPHY_LANE, tmp);
-
-	tmp &= ~CPHY_SATA_DPLL_MODE;
-	tmp |= val << CPHY_SATA_DPLL_SHIFT;
-	combo_phy_write(sata_port, CPHY_RX_OVERRIDE + lane * SPHY_LANE, tmp);
-
-	tmp |= CPHY_SATA_DPLL_RESET;
-	combo_phy_write(sata_port, CPHY_RX_OVERRIDE + lane * SPHY_LANE, tmp);
-
-	tmp &= ~CPHY_SATA_DPLL_RESET;
-	combo_phy_write(sata_port, CPHY_RX_OVERRIDE + lane * SPHY_LANE, tmp);
-
-	msleep(15);
-}
-
-static void highbank_cphy_override_lane(u8 sata_port)
-{
-	u8 lane = port_data[sata_port].lane_mapping;
-	u32 tmp, k = 0;
-
-	if (unlikely(port_data[sata_port].phy_base == NULL))
-		return;
-	do {
-		tmp = combo_phy_read(sata_port, CPHY_RX_INPUT_STS +
-						lane * SPHY_LANE);
-	} while ((tmp & SPHY_HALF_RATE) && (k++ < 1000));
-	cphy_override_rx_mode(sata_port, 3);
-	cphy_override_tx_attenuation(sata_port, port_data[sata_port].tx_atten);
-}
-
-static int highbank_initialize_phys(struct device *dev, void __iomem *addr)
-{
-	struct device_node *sata_node = dev->of_node;
-	int phy_count = 0, phy, port = 0, i;
-	void __iomem *cphy_base[CPHY_PHY_COUNT] = {};
-	struct device_node *phy_nodes[CPHY_PHY_COUNT] = {};
-	u32 tx_atten[CPHY_PORT_COUNT] = {};
-
-	memset(port_data, 0, sizeof(struct phy_lane_info) * CPHY_PORT_COUNT);
-
-	do {
-		u32 tmp;
-		struct of_phandle_args phy_data;
-		if (of_parse_phandle_with_args(sata_node,
-				"calxeda,port-phys", "#phy-cells",
-				port, &phy_data))
-			break;
-		for (phy = 0; phy < phy_count; phy++) {
-			if (phy_nodes[phy] == phy_data.np)
-				break;
-		}
-		if (phy_nodes[phy] == NULL) {
-			phy_nodes[phy] = phy_data.np;
-			cphy_base[phy] = of_iomap(phy_nodes[phy], 0);
-			if (cphy_base[phy] == NULL) {
-				return 0;
-			}
-			phy_count += 1;
-		}
-		port_data[port].lane_mapping = phy_data.args[0];
-		of_property_read_u32(phy_nodes[phy], "phydev", &tmp);
-		port_data[port].phy_devs = tmp;
-		port_data[port].phy_base = cphy_base[phy];
-		of_node_put(phy_data.np);
-		port += 1;
-	} while (port < CPHY_PORT_COUNT);
-	of_property_read_u32_array(sata_node, "calxeda,tx-atten",
-				tx_atten, port);
-	for (i = 0; i < port; i++)
-		port_data[i].tx_atten = (u8) tx_atten[i];
-	return 0;
-}
-
-/*
- * The Calxeda SATA phy intermittently fails to bring up a link with Gen3
- * Retrying the phy hard reset can work around the issue, but the drive
- * may fail again. In less than 150 out of 15000 test runs, it took more
- * than 10 tries for the link to be established (but never more than 35).
- * Triple the maximum observed retry count to provide plenty of margin for
- * rare events and to guarantee that the link is established.
- *
- * Also, the default 2 second time-out on a failed drive is too long in
- * this situation. The uboot implementation of the same driver function
- * uses a much shorter time-out period and never experiences a time out
- * issue. Reducing the time-out to 500ms improves the responsiveness.
- * The other timing constants were kept the same as the stock AHCI driver.
- * This change was also tested 15000 times on 24 drives and none of them
- * experienced a time out.
- */
-static int ahci_highbank_hardreset(struct ata_link *link, unsigned int *class,
-				unsigned long deadline)
-{
-	static const unsigned long timing[] = { 5, 100, 500};
-	struct ata_port *ap = link->ap;
-	struct ahci_port_priv *pp = ap->private_data;
-	struct ahci_host_priv *hpriv = ap->host->private_data;
-	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
-	struct ata_taskfile tf;
-	bool online;
-	u32 sstatus;
-	int rc;
-	int retry = 100;
-
-	hpriv->stop_engine(ap);
-
-	/* clear D2H reception area to properly wait for D2H FIS */
-	ata_tf_init(link->device, &tf);
-	tf.command = ATA_BUSY;
-	ata_tf_to_fis(&tf, 0, 0, d2h_fis);
-
-	do {
-		highbank_cphy_disable_overrides(link->ap->port_no);
-		rc = sata_link_hardreset(link, timing, deadline, &online, NULL);
-		highbank_cphy_override_lane(link->ap->port_no);
-
-		/* If the status is 1, we are connected, but the link did not
-		 * come up. So retry resetting the link again.
-		 */
-		if (sata_scr_read(link, SCR_STATUS, &sstatus))
-			break;
-		if (!(sstatus & 0x3))
-			break;
-	} while (!online && retry--);
-
-	hpriv->start_engine(ap);
-
-	if (online)
-		*class = ahci_dev_classify(ap);
-
-	return rc;
-}
-
-static struct ata_port_operations ahci_highbank_ops = {
-	.inherits		= &ahci_ops,
-	.hardreset		= ahci_highbank_hardreset,
-	.transmit_led_message   = ecx_transmit_led_message,
-};
-
-static const struct ata_port_info ahci_highbank_port_info = {
-	.flags          = AHCI_FLAG_COMMON,
-	.pio_mask       = ATA_PIO4,
-	.udma_mask      = ATA_UDMA6,
-	.port_ops       = &ahci_highbank_ops,
-};
-
-static struct scsi_host_template ahci_highbank_platform_sht = {
-	AHCI_SHT("sata_highbank"),
-};
-
-static const struct of_device_id ahci_of_match[] = {
-	{ .compatible = "calxeda,hb-ahci" },
-	{},
-};
-MODULE_DEVICE_TABLE(of, ahci_of_match);
-
-static int ahci_highbank_probe(struct platform_device *pdev)
-{
-	struct device *dev = &pdev->dev;
-	struct ahci_host_priv *hpriv;
-	struct ecx_plat_data *pdata;
-	struct ata_host *host;
-	struct resource *mem;
-	int irq;
-	int i;
-	int rc;
-	u32 n_ports;
-	struct ata_port_info pi = ahci_highbank_port_info;
-	const struct ata_port_info *ppi[] = { &pi, NULL };
-
-	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!mem) {
-		dev_err(dev, "no mmio space\n");
-		return -EINVAL;
-	}
-
-	irq = platform_get_irq(pdev, 0);
-	if (irq <= 0) {
-		dev_err(dev, "no irq\n");
-		return -EINVAL;
-	}
-
-	hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
-	if (!hpriv) {
-		dev_err(dev, "can't alloc ahci_host_priv\n");
-		return -ENOMEM;
-	}
-	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
-	if (!pdata) {
-		dev_err(dev, "can't alloc ecx_plat_data\n");
-		return -ENOMEM;
-	}
-
-	hpriv->irq = irq;
-	hpriv->flags |= (unsigned long)pi.private_data;
-
-	hpriv->mmio = devm_ioremap(dev, mem->start, resource_size(mem));
-	if (!hpriv->mmio) {
-		dev_err(dev, "can't map %pR\n", mem);
-		return -ENOMEM;
-	}
-
-	rc = highbank_initialize_phys(dev, hpriv->mmio);
-	if (rc)
-		return rc;
-
-
-	ahci_save_initial_config(dev, hpriv);
-
-	/* prepare host */
-	if (hpriv->cap & HOST_CAP_NCQ)
-		pi.flags |= ATA_FLAG_NCQ;
-
-	if (hpriv->cap & HOST_CAP_PMP)
-		pi.flags |= ATA_FLAG_PMP;
-
-	if (hpriv->cap & HOST_CAP_64)
-		dma_set_coherent_mask(dev, DMA_BIT_MASK(64));
-
-	/* CAP.NP sometimes indicate the index of the last enabled
-	 * port, at other times, that of the last possible port, so
-	 * determining the maximum port number requires looking at
-	 * both CAP.NP and port_map.
-	 */
-	n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
-
-	pdata->n_ports = n_ports;
-	hpriv->plat_data = pdata;
-	highbank_set_em_messages(dev, hpriv, &pi);
-
-	host = ata_host_alloc_pinfo(dev, ppi, n_ports);
-	if (!host) {
-		rc = -ENOMEM;
-		goto err0;
-	}
-
-	host->private_data = hpriv;
-
-	if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
-		host->flags |= ATA_HOST_PARALLEL_SCAN;
-
-	for (i = 0; i < host->n_ports; i++) {
-		struct ata_port *ap = host->ports[i];
-
-		ata_port_desc(ap, "mmio %pR", mem);
-		ata_port_desc(ap, "port 0x%x", 0x100 + ap->port_no * 0x80);
-
-		/* set enclosure management message type */
-		if (ap->flags & ATA_FLAG_EM)
-			ap->em_message_type = hpriv->em_msg_type;
-
-		/* disabled/not-implemented port */
-		if (!(hpriv->port_map & (1 << i)))
-			ap->ops = &ata_dummy_port_ops;
-	}
-
-	rc = ahci_reset_controller(host);
-	if (rc)
-		goto err0;
-
-	ahci_init_controller(host);
-	ahci_print_info(host, "platform");
-
-	rc = ahci_host_activate(host, &ahci_highbank_platform_sht);
-	if (rc)
-		goto err0;
-
-	return 0;
-err0:
-	return rc;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int ahci_highbank_suspend(struct device *dev)
-{
-	struct ata_host *host = dev_get_drvdata(dev);
-	struct ahci_host_priv *hpriv = host->private_data;
-	void __iomem *mmio = hpriv->mmio;
-	u32 ctl;
-	int rc;
-
-	if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) {
-		dev_err(dev, "firmware update required for suspend/resume\n");
-		return -EIO;
-	}
-
-	/*
-	 * AHCI spec rev1.1 section 8.3.3:
-	 * Software must disable interrupts prior to requesting a
-	 * transition of the HBA to D3 state.
-	 */
-	ctl = readl(mmio + HOST_CTL);
-	ctl &= ~HOST_IRQ_EN;
-	writel(ctl, mmio + HOST_CTL);
-	readl(mmio + HOST_CTL); /* flush */
-
-	rc = ata_host_suspend(host, PMSG_SUSPEND);
-	if (rc)
-		return rc;
-
-	return 0;
-}
-
-static int ahci_highbank_resume(struct device *dev)
-{
-	struct ata_host *host = dev_get_drvdata(dev);
-	int rc;
-
-	if (dev->power.power_state.event == PM_EVENT_SUSPEND) {
-		rc = ahci_reset_controller(host);
-		if (rc)
-			return rc;
-
-		ahci_init_controller(host);
-	}
-
-	ata_host_resume(host);
-
-	return 0;
-}
-#endif
-
-static SIMPLE_DEV_PM_OPS(ahci_highbank_pm_ops,
-		  ahci_highbank_suspend, ahci_highbank_resume);
-
-static struct platform_driver ahci_highbank_driver = {
-	.remove = ata_platform_remove_one,
-        .driver = {
-                .name = "highbank-ahci",
-                .of_match_table = ahci_of_match,
-                .pm = &ahci_highbank_pm_ops,
-        },
-	.probe = ahci_highbank_probe,
-};
-
-module_platform_driver(ahci_highbank_driver);
-
-MODULE_DESCRIPTION("Calxeda Highbank AHCI SATA platform driver");
-MODULE_AUTHOR("Mark Langsdorf <mark.langsdorf@calxeda.com>");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("sata:highbank");
--
2.20.1

WARNING: multiple messages have this Message-ID (diff)
From: Rob Herring <robh@kernel.org>
To: linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org, soc@kernel.org,
	Andre Przywara <andre.przywara@arm.com>,
	Robert Richter <rrichter@marvell.com>, Jon Loeliger <jdl@jdl.com>,
	Alexander Graf <graf@amazon.com>,
	Matthias Brugger <mbrugger@suse.com>,
	Mark Langsdorf <mlangsdo@redhat.com>
Cc: kvm@vger.kernel.org, Viresh Kumar <viresh.kumar@linaro.org>,
	linux-ide@vger.kernel.org, Will Deacon <will@kernel.org>,
	linux-clk@vger.kernel.org,
	Daniel Lezcano <daniel.lezcano@linaro.org>,
	devicetree@vger.kernel.org, linux-pm@vger.kernel.org,
	Alex Williamson <alex.williamson@redhat.com>,
	Borislav Petkov <bp@alien8.de>,
	Mauro Carvalho Chehab <mchehab@kernel.org>,
	linux-edac@vger.kernel.org, Jens Axboe <axboe@kernel.dk>,
	Tony Luck <tony.luck@intel.com>, Stephen Boyd <sboyd@kernel.org>,
	netdev@vger.kernel.org, Cornelia Huck <cohuck@redhat.com>,
	"Rafael J. Wysocki" <rjw@rjwysocki.net>,
	iommu@lists.linux-foundation.org,
	James Morse <james.morse@arm.com>,
	Robin Murphy <robin.murphy@arm.com>,
	"David S. Miller" <davem@davemloft.net>
Subject: [RFC PATCH 02/11] ata: Remove Calxeda AHCI driver
Date: Tue, 18 Feb 2020 11:13:12 -0600	[thread overview]
Message-ID: <20200218171321.30990-3-robh@kernel.org> (raw)
In-Reply-To: <20200218171321.30990-1-robh@kernel.org>

Cc: Jens Axboe <axboe@kernel.dk>
Cc: linux-ide@vger.kernel.org
Signed-off-by: Rob Herring <robh@kernel.org>
---
Do not apply yet.

 drivers/ata/Kconfig         |   9 -
 drivers/ata/Makefile        |   1 -
 drivers/ata/sata_highbank.c | 635 ------------------------------------
 3 files changed, 645 deletions(-)
 delete mode 100644 drivers/ata/sata_highbank.c

diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index a6beb2c5a692..687ddd9f4188 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -395,15 +395,6 @@ config SATA_DWC_VDEBUG
 	help
 	  This option enables the taskfile dumping and NCQ debugging.

-config SATA_HIGHBANK
-	tristate "Calxeda Highbank SATA support"
-	depends on ARCH_HIGHBANK || COMPILE_TEST
-	help
-	  This option enables support for the Calxeda Highbank SoC's
-	  onboard SATA.
-
-	  If unsure, say N.
-
 config SATA_MV
 	tristate "Marvell SATA support"
 	depends on PCI || ARCH_DOVE || ARCH_MV78XX0 || \
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index d8cc2e04a6c7..08f26d674ed7 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -12,7 +12,6 @@ obj-$(CONFIG_SATA_GEMINI)	+= sata_gemini.o
 obj-$(CONFIG_SATA_INIC162X)	+= sata_inic162x.o
 obj-$(CONFIG_SATA_SIL24)	+= sata_sil24.o
 obj-$(CONFIG_SATA_DWC)		+= sata_dwc_460ex.o
-obj-$(CONFIG_SATA_HIGHBANK)	+= sata_highbank.o libahci.o
 obj-$(CONFIG_AHCI_BRCM)		+= ahci_brcm.o libahci.o libahci_platform.o
 obj-$(CONFIG_AHCI_CEVA)		+= ahci_ceva.o libahci.o libahci_platform.o
 obj-$(CONFIG_AHCI_DA850)	+= ahci_da850.o libahci.o libahci_platform.o
diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c
deleted file mode 100644
index ad3893c62572..000000000000
--- a/drivers/ata/sata_highbank.c
+++ /dev/null
@@ -1,635 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Calxeda Highbank AHCI SATA platform driver
- * Copyright 2012 Calxeda, Inc.
- *
- * based on the AHCI SATA platform driver by Jeff Garzik and Anton Vorontsov
- */
-#include <linux/kernel.h>
-#include <linux/gfp.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/spinlock.h>
-#include <linux/device.h>
-#include <linux/of_device.h>
-#include <linux/of_address.h>
-#include <linux/platform_device.h>
-#include <linux/libata.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/export.h>
-#include <linux/gpio/consumer.h>
-
-#include "ahci.h"
-
-#define CPHY_MAP(dev, addr) ((((dev) & 0x1f) << 7) | (((addr) >> 9) & 0x7f))
-#define CPHY_ADDR(addr) (((addr) & 0x1ff) << 2)
-#define SERDES_CR_CTL			0x80a0
-#define SERDES_CR_ADDR			0x80a1
-#define SERDES_CR_DATA			0x80a2
-#define CR_BUSY				0x0001
-#define CR_START			0x0001
-#define CR_WR_RDN			0x0002
-#define CPHY_TX_INPUT_STS		0x2001
-#define CPHY_RX_INPUT_STS		0x2002
-#define CPHY_SATA_TX_OVERRIDE		0x8000
-#define CPHY_SATA_RX_OVERRIDE	 	0x4000
-#define CPHY_TX_OVERRIDE		0x2004
-#define CPHY_RX_OVERRIDE		0x2005
-#define SPHY_LANE			0x100
-#define SPHY_HALF_RATE			0x0001
-#define CPHY_SATA_DPLL_MODE		0x0700
-#define CPHY_SATA_DPLL_SHIFT		8
-#define CPHY_SATA_DPLL_RESET		(1 << 11)
-#define CPHY_SATA_TX_ATTEN		0x1c00
-#define CPHY_SATA_TX_ATTEN_SHIFT	10
-#define CPHY_PHY_COUNT			6
-#define CPHY_LANE_COUNT			4
-#define CPHY_PORT_COUNT			(CPHY_PHY_COUNT * CPHY_LANE_COUNT)
-
-static DEFINE_SPINLOCK(cphy_lock);
-/* Each of the 6 phys can have up to 4 sata ports attached to i. Map 0-based
- * sata ports to their phys and then to their lanes within the phys
- */
-struct phy_lane_info {
-	void __iomem *phy_base;
-	u8 lane_mapping;
-	u8 phy_devs;
-	u8 tx_atten;
-};
-static struct phy_lane_info port_data[CPHY_PORT_COUNT];
-
-static DEFINE_SPINLOCK(sgpio_lock);
-#define SCLOCK				0
-#define SLOAD				1
-#define SDATA				2
-#define SGPIO_PINS			3
-#define SGPIO_PORTS			8
-
-struct ecx_plat_data {
-	u32		n_ports;
-	/* number of extra clocks that the SGPIO PIC controller expects */
-	u32		pre_clocks;
-	u32		post_clocks;
-	struct gpio_desc *sgpio_gpiod[SGPIO_PINS];
-	u32		sgpio_pattern;
-	u32		port_to_sgpio[SGPIO_PORTS];
-};
-
-#define SGPIO_SIGNALS			3
-#define ECX_ACTIVITY_BITS		0x300000
-#define ECX_ACTIVITY_SHIFT		0
-#define ECX_LOCATE_BITS			0x80000
-#define ECX_LOCATE_SHIFT		1
-#define ECX_FAULT_BITS			0x400000
-#define ECX_FAULT_SHIFT			2
-static inline int sgpio_bit_shift(struct ecx_plat_data *pdata, u32 port,
-				u32 shift)
-{
-	return 1 << (3 * pdata->port_to_sgpio[port] + shift);
-}
-
-static void ecx_parse_sgpio(struct ecx_plat_data *pdata, u32 port, u32 state)
-{
-	if (state & ECX_ACTIVITY_BITS)
-		pdata->sgpio_pattern |= sgpio_bit_shift(pdata, port,
-						ECX_ACTIVITY_SHIFT);
-	else
-		pdata->sgpio_pattern &= ~sgpio_bit_shift(pdata, port,
-						ECX_ACTIVITY_SHIFT);
-	if (state & ECX_LOCATE_BITS)
-		pdata->sgpio_pattern |= sgpio_bit_shift(pdata, port,
-						ECX_LOCATE_SHIFT);
-	else
-		pdata->sgpio_pattern &= ~sgpio_bit_shift(pdata, port,
-						ECX_LOCATE_SHIFT);
-	if (state & ECX_FAULT_BITS)
-		pdata->sgpio_pattern |= sgpio_bit_shift(pdata, port,
-						ECX_FAULT_SHIFT);
-	else
-		pdata->sgpio_pattern &= ~sgpio_bit_shift(pdata, port,
-						ECX_FAULT_SHIFT);
-}
-
-/*
- * Tell the LED controller that the signal has changed by raising the clock
- * line for 50 uS and then lowering it for 50 uS.
- */
-static void ecx_led_cycle_clock(struct ecx_plat_data *pdata)
-{
-	gpiod_set_value(pdata->sgpio_gpiod[SCLOCK], 1);
-	udelay(50);
-	gpiod_set_value(pdata->sgpio_gpiod[SCLOCK], 0);
-	udelay(50);
-}
-
-static ssize_t ecx_transmit_led_message(struct ata_port *ap, u32 state,
-					ssize_t size)
-{
-	struct ahci_host_priv *hpriv =  ap->host->private_data;
-	struct ecx_plat_data *pdata = hpriv->plat_data;
-	struct ahci_port_priv *pp = ap->private_data;
-	unsigned long flags;
-	int pmp, i;
-	struct ahci_em_priv *emp;
-	u32 sgpio_out;
-
-	/* get the slot number from the message */
-	pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8;
-	if (pmp < EM_MAX_SLOTS)
-		emp = &pp->em_priv[pmp];
-	else
-		return -EINVAL;
-
-	if (!(hpriv->em_msg_type & EM_MSG_TYPE_LED))
-		return size;
-
-	spin_lock_irqsave(&sgpio_lock, flags);
-	ecx_parse_sgpio(pdata, ap->port_no, state);
-	sgpio_out = pdata->sgpio_pattern;
-	for (i = 0; i < pdata->pre_clocks; i++)
-		ecx_led_cycle_clock(pdata);
-
-	gpiod_set_value(pdata->sgpio_gpiod[SLOAD], 1);
-	ecx_led_cycle_clock(pdata);
-	gpiod_set_value(pdata->sgpio_gpiod[SLOAD], 0);
-	/*
-	 * bit-bang out the SGPIO pattern, by consuming a bit and then
-	 * clocking it out.
-	 */
-	for (i = 0; i < (SGPIO_SIGNALS * pdata->n_ports); i++) {
-		gpiod_set_value(pdata->sgpio_gpiod[SDATA], sgpio_out & 1);
-		sgpio_out >>= 1;
-		ecx_led_cycle_clock(pdata);
-	}
-	for (i = 0; i < pdata->post_clocks; i++)
-		ecx_led_cycle_clock(pdata);
-
-	/* save off new led state for port/slot */
-	emp->led_state = state;
-
-	spin_unlock_irqrestore(&sgpio_lock, flags);
-	return size;
-}
-
-static void highbank_set_em_messages(struct device *dev,
-					struct ahci_host_priv *hpriv,
-					struct ata_port_info *pi)
-{
-	struct device_node *np = dev->of_node;
-	struct ecx_plat_data *pdata = hpriv->plat_data;
-	int i;
-
-	for (i = 0; i < SGPIO_PINS; i++) {
-		struct gpio_desc *gpiod;
-
-		gpiod = devm_gpiod_get_index(dev, "calxeda,sgpio", i,
-					     GPIOD_OUT_HIGH);
-		if (IS_ERR(gpiod)) {
-			dev_err(dev, "failed to get GPIO %d\n", i);
-			continue;
-		}
-		gpiod_set_consumer_name(gpiod, "CX SGPIO");
-
-		pdata->sgpio_gpiod[i] = gpiod;
-	}
-	of_property_read_u32_array(np, "calxeda,led-order",
-						pdata->port_to_sgpio,
-						pdata->n_ports);
-	if (of_property_read_u32(np, "calxeda,pre-clocks", &pdata->pre_clocks))
-		pdata->pre_clocks = 0;
-	if (of_property_read_u32(np, "calxeda,post-clocks",
-				&pdata->post_clocks))
-		pdata->post_clocks = 0;
-
-	/* store em_loc */
-	hpriv->em_loc = 0;
-	hpriv->em_buf_sz = 4;
-	hpriv->em_msg_type = EM_MSG_TYPE_LED;
-	pi->flags |= ATA_FLAG_EM | ATA_FLAG_SW_ACTIVITY;
-}
-
-static u32 __combo_phy_reg_read(u8 sata_port, u32 addr)
-{
-	u32 data;
-	u8 dev = port_data[sata_port].phy_devs;
-	spin_lock(&cphy_lock);
-	writel(CPHY_MAP(dev, addr), port_data[sata_port].phy_base + 0x800);
-	data = readl(port_data[sata_port].phy_base + CPHY_ADDR(addr));
-	spin_unlock(&cphy_lock);
-	return data;
-}
-
-static void __combo_phy_reg_write(u8 sata_port, u32 addr, u32 data)
-{
-	u8 dev = port_data[sata_port].phy_devs;
-	spin_lock(&cphy_lock);
-	writel(CPHY_MAP(dev, addr), port_data[sata_port].phy_base + 0x800);
-	writel(data, port_data[sata_port].phy_base + CPHY_ADDR(addr));
-	spin_unlock(&cphy_lock);
-}
-
-static void combo_phy_wait_for_ready(u8 sata_port)
-{
-	while (__combo_phy_reg_read(sata_port, SERDES_CR_CTL) & CR_BUSY)
-		udelay(5);
-}
-
-static u32 combo_phy_read(u8 sata_port, u32 addr)
-{
-	combo_phy_wait_for_ready(sata_port);
-	__combo_phy_reg_write(sata_port, SERDES_CR_ADDR, addr);
-	__combo_phy_reg_write(sata_port, SERDES_CR_CTL, CR_START);
-	combo_phy_wait_for_ready(sata_port);
-	return __combo_phy_reg_read(sata_port, SERDES_CR_DATA);
-}
-
-static void combo_phy_write(u8 sata_port, u32 addr, u32 data)
-{
-	combo_phy_wait_for_ready(sata_port);
-	__combo_phy_reg_write(sata_port, SERDES_CR_ADDR, addr);
-	__combo_phy_reg_write(sata_port, SERDES_CR_DATA, data);
-	__combo_phy_reg_write(sata_port, SERDES_CR_CTL, CR_WR_RDN | CR_START);
-}
-
-static void highbank_cphy_disable_overrides(u8 sata_port)
-{
-	u8 lane = port_data[sata_port].lane_mapping;
-	u32 tmp;
-	if (unlikely(port_data[sata_port].phy_base == NULL))
-		return;
-	tmp = combo_phy_read(sata_port, CPHY_RX_INPUT_STS + lane * SPHY_LANE);
-	tmp &= ~CPHY_SATA_RX_OVERRIDE;
-	combo_phy_write(sata_port, CPHY_RX_OVERRIDE + lane * SPHY_LANE, tmp);
-}
-
-static void cphy_override_tx_attenuation(u8 sata_port, u32 val)
-{
-	u8 lane = port_data[sata_port].lane_mapping;
-	u32 tmp;
-
-	if (val & 0x8)
-		return;
-
-	tmp = combo_phy_read(sata_port, CPHY_TX_INPUT_STS + lane * SPHY_LANE);
-	tmp &= ~CPHY_SATA_TX_OVERRIDE;
-	combo_phy_write(sata_port, CPHY_TX_OVERRIDE + lane * SPHY_LANE, tmp);
-
-	tmp |= CPHY_SATA_TX_OVERRIDE;
-	combo_phy_write(sata_port, CPHY_TX_OVERRIDE + lane * SPHY_LANE, tmp);
-
-	tmp |= (val << CPHY_SATA_TX_ATTEN_SHIFT) & CPHY_SATA_TX_ATTEN;
-	combo_phy_write(sata_port, CPHY_TX_OVERRIDE + lane * SPHY_LANE, tmp);
-}
-
-static void cphy_override_rx_mode(u8 sata_port, u32 val)
-{
-	u8 lane = port_data[sata_port].lane_mapping;
-	u32 tmp;
-	tmp = combo_phy_read(sata_port, CPHY_RX_INPUT_STS + lane * SPHY_LANE);
-	tmp &= ~CPHY_SATA_RX_OVERRIDE;
-	combo_phy_write(sata_port, CPHY_RX_OVERRIDE + lane * SPHY_LANE, tmp);
-
-	tmp |= CPHY_SATA_RX_OVERRIDE;
-	combo_phy_write(sata_port, CPHY_RX_OVERRIDE + lane * SPHY_LANE, tmp);
-
-	tmp &= ~CPHY_SATA_DPLL_MODE;
-	tmp |= val << CPHY_SATA_DPLL_SHIFT;
-	combo_phy_write(sata_port, CPHY_RX_OVERRIDE + lane * SPHY_LANE, tmp);
-
-	tmp |= CPHY_SATA_DPLL_RESET;
-	combo_phy_write(sata_port, CPHY_RX_OVERRIDE + lane * SPHY_LANE, tmp);
-
-	tmp &= ~CPHY_SATA_DPLL_RESET;
-	combo_phy_write(sata_port, CPHY_RX_OVERRIDE + lane * SPHY_LANE, tmp);
-
-	msleep(15);
-}
-
-static void highbank_cphy_override_lane(u8 sata_port)
-{
-	u8 lane = port_data[sata_port].lane_mapping;
-	u32 tmp, k = 0;
-
-	if (unlikely(port_data[sata_port].phy_base == NULL))
-		return;
-	do {
-		tmp = combo_phy_read(sata_port, CPHY_RX_INPUT_STS +
-						lane * SPHY_LANE);
-	} while ((tmp & SPHY_HALF_RATE) && (k++ < 1000));
-	cphy_override_rx_mode(sata_port, 3);
-	cphy_override_tx_attenuation(sata_port, port_data[sata_port].tx_atten);
-}
-
-static int highbank_initialize_phys(struct device *dev, void __iomem *addr)
-{
-	struct device_node *sata_node = dev->of_node;
-	int phy_count = 0, phy, port = 0, i;
-	void __iomem *cphy_base[CPHY_PHY_COUNT] = {};
-	struct device_node *phy_nodes[CPHY_PHY_COUNT] = {};
-	u32 tx_atten[CPHY_PORT_COUNT] = {};
-
-	memset(port_data, 0, sizeof(struct phy_lane_info) * CPHY_PORT_COUNT);
-
-	do {
-		u32 tmp;
-		struct of_phandle_args phy_data;
-		if (of_parse_phandle_with_args(sata_node,
-				"calxeda,port-phys", "#phy-cells",
-				port, &phy_data))
-			break;
-		for (phy = 0; phy < phy_count; phy++) {
-			if (phy_nodes[phy] == phy_data.np)
-				break;
-		}
-		if (phy_nodes[phy] == NULL) {
-			phy_nodes[phy] = phy_data.np;
-			cphy_base[phy] = of_iomap(phy_nodes[phy], 0);
-			if (cphy_base[phy] == NULL) {
-				return 0;
-			}
-			phy_count += 1;
-		}
-		port_data[port].lane_mapping = phy_data.args[0];
-		of_property_read_u32(phy_nodes[phy], "phydev", &tmp);
-		port_data[port].phy_devs = tmp;
-		port_data[port].phy_base = cphy_base[phy];
-		of_node_put(phy_data.np);
-		port += 1;
-	} while (port < CPHY_PORT_COUNT);
-	of_property_read_u32_array(sata_node, "calxeda,tx-atten",
-				tx_atten, port);
-	for (i = 0; i < port; i++)
-		port_data[i].tx_atten = (u8) tx_atten[i];
-	return 0;
-}
-
-/*
- * The Calxeda SATA phy intermittently fails to bring up a link with Gen3
- * Retrying the phy hard reset can work around the issue, but the drive
- * may fail again. In less than 150 out of 15000 test runs, it took more
- * than 10 tries for the link to be established (but never more than 35).
- * Triple the maximum observed retry count to provide plenty of margin for
- * rare events and to guarantee that the link is established.
- *
- * Also, the default 2 second time-out on a failed drive is too long in
- * this situation. The uboot implementation of the same driver function
- * uses a much shorter time-out period and never experiences a time out
- * issue. Reducing the time-out to 500ms improves the responsiveness.
- * The other timing constants were kept the same as the stock AHCI driver.
- * This change was also tested 15000 times on 24 drives and none of them
- * experienced a time out.
- */
-static int ahci_highbank_hardreset(struct ata_link *link, unsigned int *class,
-				unsigned long deadline)
-{
-	static const unsigned long timing[] = { 5, 100, 500};
-	struct ata_port *ap = link->ap;
-	struct ahci_port_priv *pp = ap->private_data;
-	struct ahci_host_priv *hpriv = ap->host->private_data;
-	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
-	struct ata_taskfile tf;
-	bool online;
-	u32 sstatus;
-	int rc;
-	int retry = 100;
-
-	hpriv->stop_engine(ap);
-
-	/* clear D2H reception area to properly wait for D2H FIS */
-	ata_tf_init(link->device, &tf);
-	tf.command = ATA_BUSY;
-	ata_tf_to_fis(&tf, 0, 0, d2h_fis);
-
-	do {
-		highbank_cphy_disable_overrides(link->ap->port_no);
-		rc = sata_link_hardreset(link, timing, deadline, &online, NULL);
-		highbank_cphy_override_lane(link->ap->port_no);
-
-		/* If the status is 1, we are connected, but the link did not
-		 * come up. So retry resetting the link again.
-		 */
-		if (sata_scr_read(link, SCR_STATUS, &sstatus))
-			break;
-		if (!(sstatus & 0x3))
-			break;
-	} while (!online && retry--);
-
-	hpriv->start_engine(ap);
-
-	if (online)
-		*class = ahci_dev_classify(ap);
-
-	return rc;
-}
-
-static struct ata_port_operations ahci_highbank_ops = {
-	.inherits		= &ahci_ops,
-	.hardreset		= ahci_highbank_hardreset,
-	.transmit_led_message   = ecx_transmit_led_message,
-};
-
-static const struct ata_port_info ahci_highbank_port_info = {
-	.flags          = AHCI_FLAG_COMMON,
-	.pio_mask       = ATA_PIO4,
-	.udma_mask      = ATA_UDMA6,
-	.port_ops       = &ahci_highbank_ops,
-};
-
-static struct scsi_host_template ahci_highbank_platform_sht = {
-	AHCI_SHT("sata_highbank"),
-};
-
-static const struct of_device_id ahci_of_match[] = {
-	{ .compatible = "calxeda,hb-ahci" },
-	{},
-};
-MODULE_DEVICE_TABLE(of, ahci_of_match);
-
-static int ahci_highbank_probe(struct platform_device *pdev)
-{
-	struct device *dev = &pdev->dev;
-	struct ahci_host_priv *hpriv;
-	struct ecx_plat_data *pdata;
-	struct ata_host *host;
-	struct resource *mem;
-	int irq;
-	int i;
-	int rc;
-	u32 n_ports;
-	struct ata_port_info pi = ahci_highbank_port_info;
-	const struct ata_port_info *ppi[] = { &pi, NULL };
-
-	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!mem) {
-		dev_err(dev, "no mmio space\n");
-		return -EINVAL;
-	}
-
-	irq = platform_get_irq(pdev, 0);
-	if (irq <= 0) {
-		dev_err(dev, "no irq\n");
-		return -EINVAL;
-	}
-
-	hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
-	if (!hpriv) {
-		dev_err(dev, "can't alloc ahci_host_priv\n");
-		return -ENOMEM;
-	}
-	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
-	if (!pdata) {
-		dev_err(dev, "can't alloc ecx_plat_data\n");
-		return -ENOMEM;
-	}
-
-	hpriv->irq = irq;
-	hpriv->flags |= (unsigned long)pi.private_data;
-
-	hpriv->mmio = devm_ioremap(dev, mem->start, resource_size(mem));
-	if (!hpriv->mmio) {
-		dev_err(dev, "can't map %pR\n", mem);
-		return -ENOMEM;
-	}
-
-	rc = highbank_initialize_phys(dev, hpriv->mmio);
-	if (rc)
-		return rc;
-
-
-	ahci_save_initial_config(dev, hpriv);
-
-	/* prepare host */
-	if (hpriv->cap & HOST_CAP_NCQ)
-		pi.flags |= ATA_FLAG_NCQ;
-
-	if (hpriv->cap & HOST_CAP_PMP)
-		pi.flags |= ATA_FLAG_PMP;
-
-	if (hpriv->cap & HOST_CAP_64)
-		dma_set_coherent_mask(dev, DMA_BIT_MASK(64));
-
-	/* CAP.NP sometimes indicate the index of the last enabled
-	 * port, at other times, that of the last possible port, so
-	 * determining the maximum port number requires looking at
-	 * both CAP.NP and port_map.
-	 */
-	n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
-
-	pdata->n_ports = n_ports;
-	hpriv->plat_data = pdata;
-	highbank_set_em_messages(dev, hpriv, &pi);
-
-	host = ata_host_alloc_pinfo(dev, ppi, n_ports);
-	if (!host) {
-		rc = -ENOMEM;
-		goto err0;
-	}
-
-	host->private_data = hpriv;
-
-	if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
-		host->flags |= ATA_HOST_PARALLEL_SCAN;
-
-	for (i = 0; i < host->n_ports; i++) {
-		struct ata_port *ap = host->ports[i];
-
-		ata_port_desc(ap, "mmio %pR", mem);
-		ata_port_desc(ap, "port 0x%x", 0x100 + ap->port_no * 0x80);
-
-		/* set enclosure management message type */
-		if (ap->flags & ATA_FLAG_EM)
-			ap->em_message_type = hpriv->em_msg_type;
-
-		/* disabled/not-implemented port */
-		if (!(hpriv->port_map & (1 << i)))
-			ap->ops = &ata_dummy_port_ops;
-	}
-
-	rc = ahci_reset_controller(host);
-	if (rc)
-		goto err0;
-
-	ahci_init_controller(host);
-	ahci_print_info(host, "platform");
-
-	rc = ahci_host_activate(host, &ahci_highbank_platform_sht);
-	if (rc)
-		goto err0;
-
-	return 0;
-err0:
-	return rc;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int ahci_highbank_suspend(struct device *dev)
-{
-	struct ata_host *host = dev_get_drvdata(dev);
-	struct ahci_host_priv *hpriv = host->private_data;
-	void __iomem *mmio = hpriv->mmio;
-	u32 ctl;
-	int rc;
-
-	if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) {
-		dev_err(dev, "firmware update required for suspend/resume\n");
-		return -EIO;
-	}
-
-	/*
-	 * AHCI spec rev1.1 section 8.3.3:
-	 * Software must disable interrupts prior to requesting a
-	 * transition of the HBA to D3 state.
-	 */
-	ctl = readl(mmio + HOST_CTL);
-	ctl &= ~HOST_IRQ_EN;
-	writel(ctl, mmio + HOST_CTL);
-	readl(mmio + HOST_CTL); /* flush */
-
-	rc = ata_host_suspend(host, PMSG_SUSPEND);
-	if (rc)
-		return rc;
-
-	return 0;
-}
-
-static int ahci_highbank_resume(struct device *dev)
-{
-	struct ata_host *host = dev_get_drvdata(dev);
-	int rc;
-
-	if (dev->power.power_state.event == PM_EVENT_SUSPEND) {
-		rc = ahci_reset_controller(host);
-		if (rc)
-			return rc;
-
-		ahci_init_controller(host);
-	}
-
-	ata_host_resume(host);
-
-	return 0;
-}
-#endif
-
-static SIMPLE_DEV_PM_OPS(ahci_highbank_pm_ops,
-		  ahci_highbank_suspend, ahci_highbank_resume);
-
-static struct platform_driver ahci_highbank_driver = {
-	.remove = ata_platform_remove_one,
-        .driver = {
-                .name = "highbank-ahci",
-                .of_match_table = ahci_of_match,
-                .pm = &ahci_highbank_pm_ops,
-        },
-	.probe = ahci_highbank_probe,
-};
-
-module_platform_driver(ahci_highbank_driver);
-
-MODULE_DESCRIPTION("Calxeda Highbank AHCI SATA platform driver");
-MODULE_AUTHOR("Mark Langsdorf <mark.langsdorf@calxeda.com>");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("sata:highbank");
--
2.20.1
_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

WARNING: multiple messages have this Message-ID (diff)
From: Rob Herring <robh@kernel.org>
To: linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org, soc@kernel.org,
	Andre Przywara <andre.przywara@arm.com>,
	Robert Richter <rrichter@marvell.com>, Jon Loeliger <jdl@jdl.com>,
	Alexander Graf <graf@amazon.com>,
	Matthias Brugger <mbrugger@suse.com>,
	Mark Langsdorf <mlangsdo@redhat.com>
Cc: kvm@vger.kernel.org, Viresh Kumar <viresh.kumar@linaro.org>,
	linux-ide@vger.kernel.org, Will Deacon <will@kernel.org>,
	linux-clk@vger.kernel.org, Joerg Roedel <joro@8bytes.org>,
	Daniel Lezcano <daniel.lezcano@linaro.org>,
	devicetree@vger.kernel.org, linux-pm@vger.kernel.org,
	Eric Auger <eric.auger@redhat.com>,
	Alex Williamson <alex.williamson@redhat.com>,
	Borislav Petkov <bp@alien8.de>,
	Mauro Carvalho Chehab <mchehab@kernel.org>,
	linux-edac@vger.kernel.org, Jens Axboe <axboe@kernel.dk>,
	Tony Luck <tony.luck@intel.com>, Stephen Boyd <sboyd@kernel.org>,
	netdev@vger.kernel.org, Cornelia Huck <cohuck@redhat.com>,
	"Rafael J. Wysocki" <rjw@rjwysocki.net>,
	iommu@lists.linux-foundation.org,
	James Morse <james.morse@arm.com>,
	Robin Murphy <robin.murphy@arm.com>,
	"David S. Miller" <davem@davemloft.net>
Subject: [RFC PATCH 02/11] ata: Remove Calxeda AHCI driver
Date: Tue, 18 Feb 2020 11:13:12 -0600	[thread overview]
Message-ID: <20200218171321.30990-3-robh@kernel.org> (raw)
In-Reply-To: <20200218171321.30990-1-robh@kernel.org>

Cc: Jens Axboe <axboe@kernel.dk>
Cc: linux-ide@vger.kernel.org
Signed-off-by: Rob Herring <robh@kernel.org>
---
Do not apply yet.

 drivers/ata/Kconfig         |   9 -
 drivers/ata/Makefile        |   1 -
 drivers/ata/sata_highbank.c | 635 ------------------------------------
 3 files changed, 645 deletions(-)
 delete mode 100644 drivers/ata/sata_highbank.c

diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index a6beb2c5a692..687ddd9f4188 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -395,15 +395,6 @@ config SATA_DWC_VDEBUG
 	help
 	  This option enables the taskfile dumping and NCQ debugging.

-config SATA_HIGHBANK
-	tristate "Calxeda Highbank SATA support"
-	depends on ARCH_HIGHBANK || COMPILE_TEST
-	help
-	  This option enables support for the Calxeda Highbank SoC's
-	  onboard SATA.
-
-	  If unsure, say N.
-
 config SATA_MV
 	tristate "Marvell SATA support"
 	depends on PCI || ARCH_DOVE || ARCH_MV78XX0 || \
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index d8cc2e04a6c7..08f26d674ed7 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -12,7 +12,6 @@ obj-$(CONFIG_SATA_GEMINI)	+= sata_gemini.o
 obj-$(CONFIG_SATA_INIC162X)	+= sata_inic162x.o
 obj-$(CONFIG_SATA_SIL24)	+= sata_sil24.o
 obj-$(CONFIG_SATA_DWC)		+= sata_dwc_460ex.o
-obj-$(CONFIG_SATA_HIGHBANK)	+= sata_highbank.o libahci.o
 obj-$(CONFIG_AHCI_BRCM)		+= ahci_brcm.o libahci.o libahci_platform.o
 obj-$(CONFIG_AHCI_CEVA)		+= ahci_ceva.o libahci.o libahci_platform.o
 obj-$(CONFIG_AHCI_DA850)	+= ahci_da850.o libahci.o libahci_platform.o
diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c
deleted file mode 100644
index ad3893c62572..000000000000
--- a/drivers/ata/sata_highbank.c
+++ /dev/null
@@ -1,635 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Calxeda Highbank AHCI SATA platform driver
- * Copyright 2012 Calxeda, Inc.
- *
- * based on the AHCI SATA platform driver by Jeff Garzik and Anton Vorontsov
- */
-#include <linux/kernel.h>
-#include <linux/gfp.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/spinlock.h>
-#include <linux/device.h>
-#include <linux/of_device.h>
-#include <linux/of_address.h>
-#include <linux/platform_device.h>
-#include <linux/libata.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/export.h>
-#include <linux/gpio/consumer.h>
-
-#include "ahci.h"
-
-#define CPHY_MAP(dev, addr) ((((dev) & 0x1f) << 7) | (((addr) >> 9) & 0x7f))
-#define CPHY_ADDR(addr) (((addr) & 0x1ff) << 2)
-#define SERDES_CR_CTL			0x80a0
-#define SERDES_CR_ADDR			0x80a1
-#define SERDES_CR_DATA			0x80a2
-#define CR_BUSY				0x0001
-#define CR_START			0x0001
-#define CR_WR_RDN			0x0002
-#define CPHY_TX_INPUT_STS		0x2001
-#define CPHY_RX_INPUT_STS		0x2002
-#define CPHY_SATA_TX_OVERRIDE		0x8000
-#define CPHY_SATA_RX_OVERRIDE	 	0x4000
-#define CPHY_TX_OVERRIDE		0x2004
-#define CPHY_RX_OVERRIDE		0x2005
-#define SPHY_LANE			0x100
-#define SPHY_HALF_RATE			0x0001
-#define CPHY_SATA_DPLL_MODE		0x0700
-#define CPHY_SATA_DPLL_SHIFT		8
-#define CPHY_SATA_DPLL_RESET		(1 << 11)
-#define CPHY_SATA_TX_ATTEN		0x1c00
-#define CPHY_SATA_TX_ATTEN_SHIFT	10
-#define CPHY_PHY_COUNT			6
-#define CPHY_LANE_COUNT			4
-#define CPHY_PORT_COUNT			(CPHY_PHY_COUNT * CPHY_LANE_COUNT)
-
-static DEFINE_SPINLOCK(cphy_lock);
-/* Each of the 6 phys can have up to 4 sata ports attached to i. Map 0-based
- * sata ports to their phys and then to their lanes within the phys
- */
-struct phy_lane_info {
-	void __iomem *phy_base;
-	u8 lane_mapping;
-	u8 phy_devs;
-	u8 tx_atten;
-};
-static struct phy_lane_info port_data[CPHY_PORT_COUNT];
-
-static DEFINE_SPINLOCK(sgpio_lock);
-#define SCLOCK				0
-#define SLOAD				1
-#define SDATA				2
-#define SGPIO_PINS			3
-#define SGPIO_PORTS			8
-
-struct ecx_plat_data {
-	u32		n_ports;
-	/* number of extra clocks that the SGPIO PIC controller expects */
-	u32		pre_clocks;
-	u32		post_clocks;
-	struct gpio_desc *sgpio_gpiod[SGPIO_PINS];
-	u32		sgpio_pattern;
-	u32		port_to_sgpio[SGPIO_PORTS];
-};
-
-#define SGPIO_SIGNALS			3
-#define ECX_ACTIVITY_BITS		0x300000
-#define ECX_ACTIVITY_SHIFT		0
-#define ECX_LOCATE_BITS			0x80000
-#define ECX_LOCATE_SHIFT		1
-#define ECX_FAULT_BITS			0x400000
-#define ECX_FAULT_SHIFT			2
-static inline int sgpio_bit_shift(struct ecx_plat_data *pdata, u32 port,
-				u32 shift)
-{
-	return 1 << (3 * pdata->port_to_sgpio[port] + shift);
-}
-
-static void ecx_parse_sgpio(struct ecx_plat_data *pdata, u32 port, u32 state)
-{
-	if (state & ECX_ACTIVITY_BITS)
-		pdata->sgpio_pattern |= sgpio_bit_shift(pdata, port,
-						ECX_ACTIVITY_SHIFT);
-	else
-		pdata->sgpio_pattern &= ~sgpio_bit_shift(pdata, port,
-						ECX_ACTIVITY_SHIFT);
-	if (state & ECX_LOCATE_BITS)
-		pdata->sgpio_pattern |= sgpio_bit_shift(pdata, port,
-						ECX_LOCATE_SHIFT);
-	else
-		pdata->sgpio_pattern &= ~sgpio_bit_shift(pdata, port,
-						ECX_LOCATE_SHIFT);
-	if (state & ECX_FAULT_BITS)
-		pdata->sgpio_pattern |= sgpio_bit_shift(pdata, port,
-						ECX_FAULT_SHIFT);
-	else
-		pdata->sgpio_pattern &= ~sgpio_bit_shift(pdata, port,
-						ECX_FAULT_SHIFT);
-}
-
-/*
- * Tell the LED controller that the signal has changed by raising the clock
- * line for 50 uS and then lowering it for 50 uS.
- */
-static void ecx_led_cycle_clock(struct ecx_plat_data *pdata)
-{
-	gpiod_set_value(pdata->sgpio_gpiod[SCLOCK], 1);
-	udelay(50);
-	gpiod_set_value(pdata->sgpio_gpiod[SCLOCK], 0);
-	udelay(50);
-}
-
-static ssize_t ecx_transmit_led_message(struct ata_port *ap, u32 state,
-					ssize_t size)
-{
-	struct ahci_host_priv *hpriv =  ap->host->private_data;
-	struct ecx_plat_data *pdata = hpriv->plat_data;
-	struct ahci_port_priv *pp = ap->private_data;
-	unsigned long flags;
-	int pmp, i;
-	struct ahci_em_priv *emp;
-	u32 sgpio_out;
-
-	/* get the slot number from the message */
-	pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8;
-	if (pmp < EM_MAX_SLOTS)
-		emp = &pp->em_priv[pmp];
-	else
-		return -EINVAL;
-
-	if (!(hpriv->em_msg_type & EM_MSG_TYPE_LED))
-		return size;
-
-	spin_lock_irqsave(&sgpio_lock, flags);
-	ecx_parse_sgpio(pdata, ap->port_no, state);
-	sgpio_out = pdata->sgpio_pattern;
-	for (i = 0; i < pdata->pre_clocks; i++)
-		ecx_led_cycle_clock(pdata);
-
-	gpiod_set_value(pdata->sgpio_gpiod[SLOAD], 1);
-	ecx_led_cycle_clock(pdata);
-	gpiod_set_value(pdata->sgpio_gpiod[SLOAD], 0);
-	/*
-	 * bit-bang out the SGPIO pattern, by consuming a bit and then
-	 * clocking it out.
-	 */
-	for (i = 0; i < (SGPIO_SIGNALS * pdata->n_ports); i++) {
-		gpiod_set_value(pdata->sgpio_gpiod[SDATA], sgpio_out & 1);
-		sgpio_out >>= 1;
-		ecx_led_cycle_clock(pdata);
-	}
-	for (i = 0; i < pdata->post_clocks; i++)
-		ecx_led_cycle_clock(pdata);
-
-	/* save off new led state for port/slot */
-	emp->led_state = state;
-
-	spin_unlock_irqrestore(&sgpio_lock, flags);
-	return size;
-}
-
-static void highbank_set_em_messages(struct device *dev,
-					struct ahci_host_priv *hpriv,
-					struct ata_port_info *pi)
-{
-	struct device_node *np = dev->of_node;
-	struct ecx_plat_data *pdata = hpriv->plat_data;
-	int i;
-
-	for (i = 0; i < SGPIO_PINS; i++) {
-		struct gpio_desc *gpiod;
-
-		gpiod = devm_gpiod_get_index(dev, "calxeda,sgpio", i,
-					     GPIOD_OUT_HIGH);
-		if (IS_ERR(gpiod)) {
-			dev_err(dev, "failed to get GPIO %d\n", i);
-			continue;
-		}
-		gpiod_set_consumer_name(gpiod, "CX SGPIO");
-
-		pdata->sgpio_gpiod[i] = gpiod;
-	}
-	of_property_read_u32_array(np, "calxeda,led-order",
-						pdata->port_to_sgpio,
-						pdata->n_ports);
-	if (of_property_read_u32(np, "calxeda,pre-clocks", &pdata->pre_clocks))
-		pdata->pre_clocks = 0;
-	if (of_property_read_u32(np, "calxeda,post-clocks",
-				&pdata->post_clocks))
-		pdata->post_clocks = 0;
-
-	/* store em_loc */
-	hpriv->em_loc = 0;
-	hpriv->em_buf_sz = 4;
-	hpriv->em_msg_type = EM_MSG_TYPE_LED;
-	pi->flags |= ATA_FLAG_EM | ATA_FLAG_SW_ACTIVITY;
-}
-
-static u32 __combo_phy_reg_read(u8 sata_port, u32 addr)
-{
-	u32 data;
-	u8 dev = port_data[sata_port].phy_devs;
-	spin_lock(&cphy_lock);
-	writel(CPHY_MAP(dev, addr), port_data[sata_port].phy_base + 0x800);
-	data = readl(port_data[sata_port].phy_base + CPHY_ADDR(addr));
-	spin_unlock(&cphy_lock);
-	return data;
-}
-
-static void __combo_phy_reg_write(u8 sata_port, u32 addr, u32 data)
-{
-	u8 dev = port_data[sata_port].phy_devs;
-	spin_lock(&cphy_lock);
-	writel(CPHY_MAP(dev, addr), port_data[sata_port].phy_base + 0x800);
-	writel(data, port_data[sata_port].phy_base + CPHY_ADDR(addr));
-	spin_unlock(&cphy_lock);
-}
-
-static void combo_phy_wait_for_ready(u8 sata_port)
-{
-	while (__combo_phy_reg_read(sata_port, SERDES_CR_CTL) & CR_BUSY)
-		udelay(5);
-}
-
-static u32 combo_phy_read(u8 sata_port, u32 addr)
-{
-	combo_phy_wait_for_ready(sata_port);
-	__combo_phy_reg_write(sata_port, SERDES_CR_ADDR, addr);
-	__combo_phy_reg_write(sata_port, SERDES_CR_CTL, CR_START);
-	combo_phy_wait_for_ready(sata_port);
-	return __combo_phy_reg_read(sata_port, SERDES_CR_DATA);
-}
-
-static void combo_phy_write(u8 sata_port, u32 addr, u32 data)
-{
-	combo_phy_wait_for_ready(sata_port);
-	__combo_phy_reg_write(sata_port, SERDES_CR_ADDR, addr);
-	__combo_phy_reg_write(sata_port, SERDES_CR_DATA, data);
-	__combo_phy_reg_write(sata_port, SERDES_CR_CTL, CR_WR_RDN | CR_START);
-}
-
-static void highbank_cphy_disable_overrides(u8 sata_port)
-{
-	u8 lane = port_data[sata_port].lane_mapping;
-	u32 tmp;
-	if (unlikely(port_data[sata_port].phy_base == NULL))
-		return;
-	tmp = combo_phy_read(sata_port, CPHY_RX_INPUT_STS + lane * SPHY_LANE);
-	tmp &= ~CPHY_SATA_RX_OVERRIDE;
-	combo_phy_write(sata_port, CPHY_RX_OVERRIDE + lane * SPHY_LANE, tmp);
-}
-
-static void cphy_override_tx_attenuation(u8 sata_port, u32 val)
-{
-	u8 lane = port_data[sata_port].lane_mapping;
-	u32 tmp;
-
-	if (val & 0x8)
-		return;
-
-	tmp = combo_phy_read(sata_port, CPHY_TX_INPUT_STS + lane * SPHY_LANE);
-	tmp &= ~CPHY_SATA_TX_OVERRIDE;
-	combo_phy_write(sata_port, CPHY_TX_OVERRIDE + lane * SPHY_LANE, tmp);
-
-	tmp |= CPHY_SATA_TX_OVERRIDE;
-	combo_phy_write(sata_port, CPHY_TX_OVERRIDE + lane * SPHY_LANE, tmp);
-
-	tmp |= (val << CPHY_SATA_TX_ATTEN_SHIFT) & CPHY_SATA_TX_ATTEN;
-	combo_phy_write(sata_port, CPHY_TX_OVERRIDE + lane * SPHY_LANE, tmp);
-}
-
-static void cphy_override_rx_mode(u8 sata_port, u32 val)
-{
-	u8 lane = port_data[sata_port].lane_mapping;
-	u32 tmp;
-	tmp = combo_phy_read(sata_port, CPHY_RX_INPUT_STS + lane * SPHY_LANE);
-	tmp &= ~CPHY_SATA_RX_OVERRIDE;
-	combo_phy_write(sata_port, CPHY_RX_OVERRIDE + lane * SPHY_LANE, tmp);
-
-	tmp |= CPHY_SATA_RX_OVERRIDE;
-	combo_phy_write(sata_port, CPHY_RX_OVERRIDE + lane * SPHY_LANE, tmp);
-
-	tmp &= ~CPHY_SATA_DPLL_MODE;
-	tmp |= val << CPHY_SATA_DPLL_SHIFT;
-	combo_phy_write(sata_port, CPHY_RX_OVERRIDE + lane * SPHY_LANE, tmp);
-
-	tmp |= CPHY_SATA_DPLL_RESET;
-	combo_phy_write(sata_port, CPHY_RX_OVERRIDE + lane * SPHY_LANE, tmp);
-
-	tmp &= ~CPHY_SATA_DPLL_RESET;
-	combo_phy_write(sata_port, CPHY_RX_OVERRIDE + lane * SPHY_LANE, tmp);
-
-	msleep(15);
-}
-
-static void highbank_cphy_override_lane(u8 sata_port)
-{
-	u8 lane = port_data[sata_port].lane_mapping;
-	u32 tmp, k = 0;
-
-	if (unlikely(port_data[sata_port].phy_base == NULL))
-		return;
-	do {
-		tmp = combo_phy_read(sata_port, CPHY_RX_INPUT_STS +
-						lane * SPHY_LANE);
-	} while ((tmp & SPHY_HALF_RATE) && (k++ < 1000));
-	cphy_override_rx_mode(sata_port, 3);
-	cphy_override_tx_attenuation(sata_port, port_data[sata_port].tx_atten);
-}
-
-static int highbank_initialize_phys(struct device *dev, void __iomem *addr)
-{
-	struct device_node *sata_node = dev->of_node;
-	int phy_count = 0, phy, port = 0, i;
-	void __iomem *cphy_base[CPHY_PHY_COUNT] = {};
-	struct device_node *phy_nodes[CPHY_PHY_COUNT] = {};
-	u32 tx_atten[CPHY_PORT_COUNT] = {};
-
-	memset(port_data, 0, sizeof(struct phy_lane_info) * CPHY_PORT_COUNT);
-
-	do {
-		u32 tmp;
-		struct of_phandle_args phy_data;
-		if (of_parse_phandle_with_args(sata_node,
-				"calxeda,port-phys", "#phy-cells",
-				port, &phy_data))
-			break;
-		for (phy = 0; phy < phy_count; phy++) {
-			if (phy_nodes[phy] == phy_data.np)
-				break;
-		}
-		if (phy_nodes[phy] == NULL) {
-			phy_nodes[phy] = phy_data.np;
-			cphy_base[phy] = of_iomap(phy_nodes[phy], 0);
-			if (cphy_base[phy] == NULL) {
-				return 0;
-			}
-			phy_count += 1;
-		}
-		port_data[port].lane_mapping = phy_data.args[0];
-		of_property_read_u32(phy_nodes[phy], "phydev", &tmp);
-		port_data[port].phy_devs = tmp;
-		port_data[port].phy_base = cphy_base[phy];
-		of_node_put(phy_data.np);
-		port += 1;
-	} while (port < CPHY_PORT_COUNT);
-	of_property_read_u32_array(sata_node, "calxeda,tx-atten",
-				tx_atten, port);
-	for (i = 0; i < port; i++)
-		port_data[i].tx_atten = (u8) tx_atten[i];
-	return 0;
-}
-
-/*
- * The Calxeda SATA phy intermittently fails to bring up a link with Gen3
- * Retrying the phy hard reset can work around the issue, but the drive
- * may fail again. In less than 150 out of 15000 test runs, it took more
- * than 10 tries for the link to be established (but never more than 35).
- * Triple the maximum observed retry count to provide plenty of margin for
- * rare events and to guarantee that the link is established.
- *
- * Also, the default 2 second time-out on a failed drive is too long in
- * this situation. The uboot implementation of the same driver function
- * uses a much shorter time-out period and never experiences a time out
- * issue. Reducing the time-out to 500ms improves the responsiveness.
- * The other timing constants were kept the same as the stock AHCI driver.
- * This change was also tested 15000 times on 24 drives and none of them
- * experienced a time out.
- */
-static int ahci_highbank_hardreset(struct ata_link *link, unsigned int *class,
-				unsigned long deadline)
-{
-	static const unsigned long timing[] = { 5, 100, 500};
-	struct ata_port *ap = link->ap;
-	struct ahci_port_priv *pp = ap->private_data;
-	struct ahci_host_priv *hpriv = ap->host->private_data;
-	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
-	struct ata_taskfile tf;
-	bool online;
-	u32 sstatus;
-	int rc;
-	int retry = 100;
-
-	hpriv->stop_engine(ap);
-
-	/* clear D2H reception area to properly wait for D2H FIS */
-	ata_tf_init(link->device, &tf);
-	tf.command = ATA_BUSY;
-	ata_tf_to_fis(&tf, 0, 0, d2h_fis);
-
-	do {
-		highbank_cphy_disable_overrides(link->ap->port_no);
-		rc = sata_link_hardreset(link, timing, deadline, &online, NULL);
-		highbank_cphy_override_lane(link->ap->port_no);
-
-		/* If the status is 1, we are connected, but the link did not
-		 * come up. So retry resetting the link again.
-		 */
-		if (sata_scr_read(link, SCR_STATUS, &sstatus))
-			break;
-		if (!(sstatus & 0x3))
-			break;
-	} while (!online && retry--);
-
-	hpriv->start_engine(ap);
-
-	if (online)
-		*class = ahci_dev_classify(ap);
-
-	return rc;
-}
-
-static struct ata_port_operations ahci_highbank_ops = {
-	.inherits		= &ahci_ops,
-	.hardreset		= ahci_highbank_hardreset,
-	.transmit_led_message   = ecx_transmit_led_message,
-};
-
-static const struct ata_port_info ahci_highbank_port_info = {
-	.flags          = AHCI_FLAG_COMMON,
-	.pio_mask       = ATA_PIO4,
-	.udma_mask      = ATA_UDMA6,
-	.port_ops       = &ahci_highbank_ops,
-};
-
-static struct scsi_host_template ahci_highbank_platform_sht = {
-	AHCI_SHT("sata_highbank"),
-};
-
-static const struct of_device_id ahci_of_match[] = {
-	{ .compatible = "calxeda,hb-ahci" },
-	{},
-};
-MODULE_DEVICE_TABLE(of, ahci_of_match);
-
-static int ahci_highbank_probe(struct platform_device *pdev)
-{
-	struct device *dev = &pdev->dev;
-	struct ahci_host_priv *hpriv;
-	struct ecx_plat_data *pdata;
-	struct ata_host *host;
-	struct resource *mem;
-	int irq;
-	int i;
-	int rc;
-	u32 n_ports;
-	struct ata_port_info pi = ahci_highbank_port_info;
-	const struct ata_port_info *ppi[] = { &pi, NULL };
-
-	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!mem) {
-		dev_err(dev, "no mmio space\n");
-		return -EINVAL;
-	}
-
-	irq = platform_get_irq(pdev, 0);
-	if (irq <= 0) {
-		dev_err(dev, "no irq\n");
-		return -EINVAL;
-	}
-
-	hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
-	if (!hpriv) {
-		dev_err(dev, "can't alloc ahci_host_priv\n");
-		return -ENOMEM;
-	}
-	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
-	if (!pdata) {
-		dev_err(dev, "can't alloc ecx_plat_data\n");
-		return -ENOMEM;
-	}
-
-	hpriv->irq = irq;
-	hpriv->flags |= (unsigned long)pi.private_data;
-
-	hpriv->mmio = devm_ioremap(dev, mem->start, resource_size(mem));
-	if (!hpriv->mmio) {
-		dev_err(dev, "can't map %pR\n", mem);
-		return -ENOMEM;
-	}
-
-	rc = highbank_initialize_phys(dev, hpriv->mmio);
-	if (rc)
-		return rc;
-
-
-	ahci_save_initial_config(dev, hpriv);
-
-	/* prepare host */
-	if (hpriv->cap & HOST_CAP_NCQ)
-		pi.flags |= ATA_FLAG_NCQ;
-
-	if (hpriv->cap & HOST_CAP_PMP)
-		pi.flags |= ATA_FLAG_PMP;
-
-	if (hpriv->cap & HOST_CAP_64)
-		dma_set_coherent_mask(dev, DMA_BIT_MASK(64));
-
-	/* CAP.NP sometimes indicate the index of the last enabled
-	 * port, at other times, that of the last possible port, so
-	 * determining the maximum port number requires looking at
-	 * both CAP.NP and port_map.
-	 */
-	n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
-
-	pdata->n_ports = n_ports;
-	hpriv->plat_data = pdata;
-	highbank_set_em_messages(dev, hpriv, &pi);
-
-	host = ata_host_alloc_pinfo(dev, ppi, n_ports);
-	if (!host) {
-		rc = -ENOMEM;
-		goto err0;
-	}
-
-	host->private_data = hpriv;
-
-	if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
-		host->flags |= ATA_HOST_PARALLEL_SCAN;
-
-	for (i = 0; i < host->n_ports; i++) {
-		struct ata_port *ap = host->ports[i];
-
-		ata_port_desc(ap, "mmio %pR", mem);
-		ata_port_desc(ap, "port 0x%x", 0x100 + ap->port_no * 0x80);
-
-		/* set enclosure management message type */
-		if (ap->flags & ATA_FLAG_EM)
-			ap->em_message_type = hpriv->em_msg_type;
-
-		/* disabled/not-implemented port */
-		if (!(hpriv->port_map & (1 << i)))
-			ap->ops = &ata_dummy_port_ops;
-	}
-
-	rc = ahci_reset_controller(host);
-	if (rc)
-		goto err0;
-
-	ahci_init_controller(host);
-	ahci_print_info(host, "platform");
-
-	rc = ahci_host_activate(host, &ahci_highbank_platform_sht);
-	if (rc)
-		goto err0;
-
-	return 0;
-err0:
-	return rc;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int ahci_highbank_suspend(struct device *dev)
-{
-	struct ata_host *host = dev_get_drvdata(dev);
-	struct ahci_host_priv *hpriv = host->private_data;
-	void __iomem *mmio = hpriv->mmio;
-	u32 ctl;
-	int rc;
-
-	if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) {
-		dev_err(dev, "firmware update required for suspend/resume\n");
-		return -EIO;
-	}
-
-	/*
-	 * AHCI spec rev1.1 section 8.3.3:
-	 * Software must disable interrupts prior to requesting a
-	 * transition of the HBA to D3 state.
-	 */
-	ctl = readl(mmio + HOST_CTL);
-	ctl &= ~HOST_IRQ_EN;
-	writel(ctl, mmio + HOST_CTL);
-	readl(mmio + HOST_CTL); /* flush */
-
-	rc = ata_host_suspend(host, PMSG_SUSPEND);
-	if (rc)
-		return rc;
-
-	return 0;
-}
-
-static int ahci_highbank_resume(struct device *dev)
-{
-	struct ata_host *host = dev_get_drvdata(dev);
-	int rc;
-
-	if (dev->power.power_state.event == PM_EVENT_SUSPEND) {
-		rc = ahci_reset_controller(host);
-		if (rc)
-			return rc;
-
-		ahci_init_controller(host);
-	}
-
-	ata_host_resume(host);
-
-	return 0;
-}
-#endif
-
-static SIMPLE_DEV_PM_OPS(ahci_highbank_pm_ops,
-		  ahci_highbank_suspend, ahci_highbank_resume);
-
-static struct platform_driver ahci_highbank_driver = {
-	.remove = ata_platform_remove_one,
-        .driver = {
-                .name = "highbank-ahci",
-                .of_match_table = ahci_of_match,
-                .pm = &ahci_highbank_pm_ops,
-        },
-	.probe = ahci_highbank_probe,
-};
-
-module_platform_driver(ahci_highbank_driver);
-
-MODULE_DESCRIPTION("Calxeda Highbank AHCI SATA platform driver");
-MODULE_AUTHOR("Mark Langsdorf <mark.langsdorf@calxeda.com>");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("sata:highbank");
--
2.20.1

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

  parent reply	other threads:[~2020-02-18 17:14 UTC|newest]

Thread overview: 104+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-02-18 17:13 [RFC PATCH 00/11] Removing Calxeda platform support Rob Herring
2020-02-18 17:13 ` Rob Herring
2020-02-18 17:13 ` Rob Herring
2020-02-18 17:13 ` [RFC PATCH 01/11] vfio: Remove Calxeda XGMAC reset driver Rob Herring
2020-02-18 17:13   ` Rob Herring
2020-02-18 17:13   ` Rob Herring
2020-02-24 13:07   ` Auger Eric
2020-02-24 13:07     ` Auger Eric
2020-02-24 13:07     ` Auger Eric
2020-02-18 17:13 ` Rob Herring [this message]
2020-02-18 17:13   ` [RFC PATCH 02/11] ata: Remove Calxeda AHCI driver Rob Herring
2020-02-18 17:13   ` Rob Herring
2020-02-20 17:07   ` Mark Langsdorf
2020-02-20 17:07     ` Mark Langsdorf
2020-02-20 17:07     ` Mark Langsdorf
2020-02-18 17:13 ` [RFC PATCH 03/11] cpuidle: Remove Calxeda driver Rob Herring
2020-02-18 17:13   ` Rob Herring
2020-02-18 17:13   ` Rob Herring
2020-02-18 17:35   ` Daniel Lezcano
2020-02-18 17:35     ` Daniel Lezcano
2020-02-18 17:35     ` Daniel Lezcano
2020-02-18 17:13 ` [RFC PATCH 04/11] cpufreq: " Rob Herring
2020-02-18 17:13   ` Rob Herring
2020-02-18 17:13   ` Rob Herring
2020-02-19  1:49   ` Viresh Kumar
2020-02-19  1:49     ` Viresh Kumar
2020-02-19  1:49     ` Viresh Kumar
2020-02-20 17:06   ` Mark Langsdorf
2020-02-20 17:06     ` Mark Langsdorf
2020-02-20 17:06     ` Mark Langsdorf
2020-02-18 17:13 ` [RFC PATCH 05/11] EDAC: Remove Calxeda drivers Rob Herring
2020-02-18 17:13   ` Rob Herring
2020-02-18 17:13   ` Rob Herring
2020-02-18 17:33   ` Borislav Petkov
2020-02-18 17:33     ` Borislav Petkov
2020-02-18 17:33     ` Borislav Petkov
2020-02-19 11:57   ` Robert Richter
2020-02-19 11:57     ` Robert Richter
2020-02-19 11:57     ` Robert Richter
2020-02-18 17:13 ` [RFC PATCH 06/11] iommu: arm-smmu: Remove Calxeda secure mode quirk Rob Herring
2020-02-18 17:13   ` Rob Herring
2020-02-18 17:13   ` Rob Herring
2020-02-18 17:20   ` Will Deacon
2020-02-18 17:20     ` Will Deacon
2020-02-18 17:20     ` Will Deacon
2020-02-18 17:32     ` Robin Murphy
2020-02-18 17:32       ` Robin Murphy
2020-02-18 17:32       ` Robin Murphy
2020-02-25 22:01     ` Rob Herring
2020-02-25 22:01       ` Rob Herring
2020-02-25 22:01       ` Rob Herring
2020-02-28 10:04       ` Will Deacon
2020-02-28 10:04         ` Will Deacon
2020-02-28 10:25         ` Andre Przywara
2020-02-28 10:25           ` Andre Przywara
2020-02-28 10:25           ` Andre Przywara
2020-02-28 10:50           ` Will Deacon
2020-02-28 10:50             ` Will Deacon
2020-02-28 13:42             ` Andre Przywara
2020-02-28 13:42               ` Andre Przywara
2020-02-28 13:42               ` Andre Przywara
2020-02-28 13:56               ` Will Deacon
2020-02-28 13:56                 ` Will Deacon
2020-02-28 14:11                 ` Andre Przywara
2020-02-28 14:11                   ` Andre Przywara
2020-02-28 14:11                   ` Andre Przywara
2020-02-18 17:13 ` [RFC PATCH 07/11] net: Remove Calxeda XGMAC driver Rob Herring
2020-02-18 17:13   ` Rob Herring
2020-02-18 17:13   ` Rob Herring
2020-02-18 17:13 ` [RFC PATCH 08/11] clk: Remove Calxeda driver Rob Herring
2020-02-18 17:13   ` Rob Herring
2020-02-18 17:13   ` Rob Herring
2020-02-19 17:55   ` Stephen Boyd
2020-02-19 17:55     ` Stephen Boyd
2020-02-18 17:13 ` [RFC PATCH 09/11] ARM: Remove Calxeda platform support Rob Herring
2020-02-18 17:13   ` Rob Herring
2020-02-18 17:13   ` Rob Herring
2020-02-18 17:13 ` [RFC PATCH 10/11] ARM: dts: Remove Calxeda platforms Rob Herring
2020-02-18 17:13   ` Rob Herring
2020-02-18 17:13   ` Rob Herring
2020-02-18 17:13 ` [RFC PATCH 11/11] dt-bindings: Remove Calxeda platforms bindings Rob Herring
2020-02-18 17:13   ` Rob Herring
2020-02-18 17:13   ` Rob Herring
2020-02-18 17:22   ` Will Deacon
2020-02-18 17:22     ` Will Deacon
2020-02-18 17:22     ` Will Deacon
2020-02-18 17:30     ` Rob Herring
2020-02-18 17:30       ` Rob Herring
2020-02-18 17:30       ` Rob Herring
2020-02-18 18:13 ` [RFC PATCH 00/11] Removing Calxeda platform support Andre Przywara
2020-02-18 18:13   ` Andre Przywara
2020-02-18 18:13   ` Andre Przywara
2020-02-18 18:40   ` Rob Herring
2020-02-18 18:40     ` Rob Herring
2020-02-18 18:40     ` Rob Herring
2020-02-18 18:51     ` Florian Fainelli
2020-02-18 18:51       ` Florian Fainelli
2020-02-18 18:51       ` Florian Fainelli
2020-02-19 22:54   ` Olof Johansson
2020-02-19 22:54     ` Olof Johansson
2020-02-19 22:54     ` Olof Johansson
2020-02-20  1:38     ` André Przywara
2020-02-20  1:38       ` André Przywara
2020-02-20  1:38       ` André Przywara

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200218171321.30990-3-robh@kernel.org \
    --to=robh@kernel.org \
    --cc=alex.williamson@redhat.com \
    --cc=andre.przywara@arm.com \
    --cc=axboe@kernel.dk \
    --cc=bp@alien8.de \
    --cc=cohuck@redhat.com \
    --cc=daniel.lezcano@linaro.org \
    --cc=davem@davemloft.net \
    --cc=devicetree@vger.kernel.org \
    --cc=eric.auger@redhat.com \
    --cc=graf@amazon.com \
    --cc=iommu@lists.linux-foundation.org \
    --cc=james.morse@arm.com \
    --cc=jdl@jdl.com \
    --cc=joro@8bytes.org \
    --cc=kvm@vger.kernel.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-clk@vger.kernel.org \
    --cc=linux-edac@vger.kernel.org \
    --cc=linux-ide@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pm@vger.kernel.org \
    --cc=mbrugger@suse.com \
    --cc=mchehab@kernel.org \
    --cc=mlangsdo@redhat.com \
    --cc=netdev@vger.kernel.org \
    --cc=rjw@rjwysocki.net \
    --cc=robin.murphy@arm.com \
    --cc=rrichter@marvell.com \
    --cc=sboyd@kernel.org \
    --cc=soc@kernel.org \
    --cc=tony.luck@intel.com \
    --cc=viresh.kumar@linaro.org \
    --cc=will@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.