pciide(4): port NetBSD's rdcide(4)

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

pciide(4): port NetBSD's rdcide(4)

SASANO Takayoshi
Hello,

I am playing with 86duino EduCake, and I found pciide(4) did not support DMA
of Vortex86EX SoC (RDC R1012).

I tried to port NetBSD's rdcide(4) and it seems to work.

Here is the diff, and please tell me how to test more verbose.
At least there is no problem to build -current kernel, but poor performance
boost because CPU is too slow... 109min -> 101min :-(.

Regards,

--
SASANO Takayoshi <[hidden email]>

Index: pciide.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/pciide.c,v
retrieving revision 1.345
diff -u -p -r1.345 pciide.c
--- pciide.c 24 Apr 2014 15:38:25 -0000 1.345
+++ pciide.c 13 Jul 2014 20:44:40 -0000
@@ -123,6 +123,7 @@ int wdcdebug_pciide_mask = WDCDEBUG_PCII
 #include <dev/pci/pciide_ixp_reg.h>
 #include <dev/pci/pciide_svwsata_reg.h>
 #include <dev/pci/pciide_jmicron_reg.h>
+#include <dev/pci/pciide_rdc_reg.h>
 #include <dev/pci/cy82c693var.h>
 
 /* functions for reading/writing 8-bit PCI registers */
@@ -282,6 +283,9 @@ void phison_setup_channel(struct channel
 void sch_chip_map(struct pciide_softc *, struct pci_attach_args *);
 void sch_setup_channel(struct channel_softc *);
 
+void rdc_chip_map(struct pciide_softc *, struct pci_attach_args *);
+void rdc_setup_channel(struct channel_softc *);
+
 struct pciide_product_desc {
  u_int32_t ide_product;
  u_short ide_flags;
@@ -1335,6 +1339,13 @@ const struct pciide_product_desc pciide_
  },
 };
 
+const struct pciide_product_desc pciide_rdc_products[] = {
+ { PCI_PRODUCT_RDC_R1012_IDE,
+  0,
+  rdc_chip_map
+ },
+};
+
 struct pciide_vendor_desc {
  u_int32_t ide_vendor;
  const struct pciide_product_desc *ide_products;
@@ -1379,7 +1390,9 @@ const struct pciide_vendor_desc pciide_v
  { PCI_VENDOR_JMICRON, pciide_jmicron_products,
   nitems(pciide_jmicron_products) },
  { PCI_VENDOR_PHISON, pciide_phison_products,
-  nitems(pciide_phison_products) }
+  nitems(pciide_phison_products) },
+ { PCI_VENDOR_RDC, pciide_rdc_products,
+  nitems(pciide_rdc_products) }
 };
 
 /* options passed via the 'flags' config keyword */
@@ -1581,6 +1594,7 @@ pciide_activate(struct device *self, int
     sc->sc_pp->chip_map == piix_chip_map ||
     sc->sc_pp->chip_map == amd756_chip_map ||
     sc->sc_pp->chip_map == phison_chip_map ||
+    sc->sc_pp->chip_map == rdc_chip_map ||
     sc->sc_pp->chip_map == ixp_chip_map ||
     sc->sc_pp->chip_map == acard_chip_map ||
     sc->sc_pp->chip_map == apollo_chip_map ||
@@ -9103,4 +9117,151 @@ pio:
  }
 
  pciide_print_modes(cp);
+}
+
+void
+rdc_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
+{
+ struct pciide_channel *cp;
+ int channel;
+ u_int32_t patr;
+ pcireg_t interface = PCI_INTERFACE(pa->pa_class);
+ bus_size_t cmdsize, ctlsize;
+
+ printf(": DMA");
+ pciide_mapreg_dma(sc, pa);
+ sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32;
+ if (sc->sc_dma_ok) {
+ sc->sc_wdcdev.cap |= WDC_CAPABILITY_UDMA |
+ WDC_CAPABILITY_DMA | WDC_CAPABILITY_IRQACK;
+ sc->sc_wdcdev.irqack = pciide_irqack;
+ sc->sc_wdcdev.dma_init = pciide_dma_init;
+ }
+ sc->sc_wdcdev.PIO_cap = 4;
+ sc->sc_wdcdev.DMA_cap = 2;
+ sc->sc_wdcdev.UDMA_cap = 5;
+ sc->sc_wdcdev.set_modes = rdc_setup_channel;
+ sc->sc_wdcdev.channels = sc->wdc_chanarray;
+ sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS;
+
+ pciide_print_channels(sc->sc_wdcdev.nchannels, interface);
+
+ WDCDEBUG_PRINT(("rdc_chip_map: old PATR=0x%x, "
+ "PSD1ATR=0x%x, UDCCR=0x%x, IIOCR=0x%x\n",
+ pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_PATR),
+ pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_PSD1ATR),
+ pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_UDCCR),
+ pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_IIOCR)),
+       DEBUG_PROBE);
+
+ for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) {
+ cp = &sc->pciide_channels[channel];
+
+ if (pciide_chansetup(sc, channel, interface) == 0)
+ continue;
+ patr = pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_PATR);
+ if ((patr & RDCIDE_PATR_EN(channel)) == 0) {
+ printf("%s: %s ignored (disabled)\n",
+       sc->sc_wdcdev.sc_dev.dv_xname, cp->name);
+ continue;
+ }
+ pciide_map_compat_intr(pa, cp, channel, interface);
+ if (cp->hw_ok == 0)
+ continue;
+ pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize,
+       pciide_pci_intr);
+ if (cp->hw_ok == 0)
+ goto next;
+ if (pciide_chan_candisable(cp)) {
+ patr &= ~RDCIDE_PATR_EN(channel);
+ pci_conf_write(sc->sc_pc, sc->sc_tag, RDCIDE_PATR,
+       patr);
+ }
+ if (cp->hw_ok == 0)
+ goto next;
+ sc->sc_wdcdev.set_modes(&cp->wdc_channel);
+next:
+ if (cp->hw_ok == 0)
+ pciide_unmap_compat_intr(pa, cp, channel, interface);
+ }
+
+ WDCDEBUG_PRINT(("rdc_chip_map: PATR=0x%x, "
+ "PSD1ATR=0x%x, UDCCR=0x%x, IIOCR=0x%x\n",
+ pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_PATR),
+ pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_PSD1ATR),
+ pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_UDCCR),
+ pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_IIOCR)),
+       DEBUG_PROBE);
+}
+
+void
+rdc_setup_channel(struct channel_softc *chp)
+{
+ u_int8_t drive;
+ u_int32_t patr, psd1atr, udccr, iiocr;
+ struct pciide_channel *cp = (struct pciide_channel *)chp;
+ struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
+ struct ata_drive_datas *drvp;
+
+ patr = pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_PATR);
+ psd1atr = pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_PSD1ATR);
+ udccr = pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_UDCCR);
+ iiocr = pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_IIOCR);
+
+ /* setup DMA */
+ pciide_channel_dma_setup(cp);
+
+ /* clear modes */
+ patr = patr & (RDCIDE_PATR_EN(0) | RDCIDE_PATR_EN(1));
+ psd1atr &= ~RDCIDE_PSD1ATR_SETUP_MASK(chp->channel);
+ psd1atr &= ~RDCIDE_PSD1ATR_HOLD_MASK(chp->channel);
+ for (drive = 0; drive < 2; drive++) {
+ udccr &= ~RDCIDE_UDCCR_EN(chp->channel, drive);
+ udccr &= ~RDCIDE_UDCCR_TIM_MASK(chp->channel, drive);
+ iiocr &= ~RDCIDE_IIOCR_CLK_MASK(chp->channel, drive);
+ }
+ /* now setup modes */
+ for (drive = 0; drive < 2; drive++) {
+ drvp = &cp->wdc_channel.ch_drive[drive];
+ if ((drvp->drive_flags & DRIVE) == 0)
+ continue;
+ if (drvp->drive_flags & DRIVE_ATAPI)
+ patr |= RDCIDE_PATR_ATA(chp->channel, drive);
+ if (drive == 0) {
+ patr |= RDCIDE_PATR_SETUP(rdcide_setup[drvp->PIO_mode],
+  chp->channel);
+ patr |= RDCIDE_PATR_HOLD(rdcide_hold[drvp->PIO_mode],
+ chp->channel);
+ } else {
+ patr |= RDCIDE_PATR_DEV1_TEN(chp->channel);
+ psd1atr |= RDCIDE_PSD1ATR_SETUP(
+ rdcide_setup[drvp->PIO_mode],
+ chp->channel);
+ psd1atr |= RDCIDE_PSD1ATR_HOLD(
+ rdcide_hold[drvp->PIO_mode],
+ chp->channel);
+ }
+ if (drvp->PIO_mode > 0) {
+ patr |= RDCIDE_PATR_FTIM(chp->channel, drive);
+ patr |= RDCIDE_PATR_IORDY(chp->channel, drive);
+ }
+ if (drvp->drive_flags & DRIVE_DMA)
+ patr |= RDCIDE_PATR_DMAEN(chp->channel, drive);
+ if ((drvp->drive_flags & DRIVE_UDMA) == 0)
+ continue;
+
+ if ((iiocr & RDCIDE_IIOCR_CABLE(chp->channel, drive)) == 0
+    && drvp->UDMA_mode > 2)
+ drvp->UDMA_mode = 2;
+ udccr |= RDCIDE_UDCCR_EN(chp->channel, drive);
+ udccr |= RDCIDE_UDCCR_TIM(rdcide_udmatim[drvp->UDMA_mode],
+ chp->channel, drive);
+ iiocr |= RDCIDE_IIOCR_CLK(rdcide_udmaclk[drvp->UDMA_mode],
+ chp->channel, drive);
+ }
+
+ pci_conf_write(sc->sc_pc, sc->sc_tag, RDCIDE_PATR, patr);
+ pci_conf_write(sc->sc_pc, sc->sc_tag, RDCIDE_PSD1ATR, psd1atr);
+ pci_conf_write(sc->sc_pc, sc->sc_tag, RDCIDE_UDCCR, udccr);
+ pci_conf_write(sc->sc_pc, sc->sc_tag, RDCIDE_IIOCR, iiocr);
 }
Index: pciide_rdc_reg.h
===================================================================
RCS file: pciide_rdc_reg.h
diff -N pciide_rdc_reg.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ pciide_rdc_reg.h 13 Jul 2014 20:44:40 -0000
@@ -0,0 +1,75 @@
+/*      $OpenBSD$    */
+/*      $NetBSD: rdcide_reg.h,v 1.1 2011/04/04 14:33:51 bouyer Exp $    */
+
+/*
+ * Copyright (c) 2011 Manuel Bouyer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*
+ * register definitions for the RDC ide controller as found in the
+ * PMX-1000 SoC
+ */
+/* ATA Timing Register */
+#define RDCIDE_PATR 0x40
+#define RDCIDE_PATR_EN(chan) (0x8000 << ((chan) * 16))
+#define RDCIDE_PATR_DEV1_TEN(chan) (0x4000 << ((chan) * 16))
+#define RDCIDE_PATR_SETUP(val, chan) (((val) << 12) << ((chan) * 16))
+#define RDCIDE_PATR_SETUP_MASK(chan) (0x3000 << ((chan) * 16))
+#define RDCIDE_PATR_HOLD(val, chan) (((val) << 8) << ((chan) * 16))
+#define RDCIDE_PATR_HOLD_MASK(chan) (0x0300 << ((chan) * 16))
+#define RDCIDE_PATR_DMAEN(chan, drv) ((0x0008 << (drv * 4)) << ((chan) * 16))
+#define RDCIDE_PATR_ATA(chan, drv) ((0x0004 << (drv * 4)) << ((chan) * 16))
+#define RDCIDE_PATR_IORDY(chan, drv) ((0x0002 << (drv * 4)) << ((chan) * 16))
+#define RDCIDE_PATR_FTIM(chan, drv) ((0x0001 << (drv * 4)) << ((chan) * 16))
+
+/* Primary and Secondary Device 1 ATA Timing */
+#define RDCIDE_PSD1ATR 0x44
+#define RDCIDE_PSD1ATR_SETUP(val, chan) (((val) << 2) << (chan * 4))
+#define RDCIDE_PSD1ATR_SETUP_MASK(chan) (0x0c << (chan * 4))
+#define RDCIDE_PSD1ATR_HOLD(val, chan) (((val) << 0) << (chan * 4))
+#define RDCIDE_PSD1ATR_HOLD_MASK(chan) (0x03 << (chan * 4))
+
+const uint8_t rdcide_setup[] = {0, 0, 1, 2, 2};
+const uint8_t rdcide_hold[] = {0, 0, 0, 1, 3};
+
+/* Ultra DMA Control and timing Register */
+#define RDCIDE_UDCCR 0x48
+#define RDCIDE_UDCCR_EN(chan, drv) ((1 << (drv)) << (chan * 2))
+#define RDCIDE_UDCCR_TIM(val, chan, drv) (((val) << ((drv) * 4)) << (chan * 8))
+#define RDCIDE_UDCCR_TIM_MASK(chan, drv) ((0x3 << ((drv) * 4)) << (chan * 8))
+
+const uint8_t rdcide_udmatim[] = {0, 1, 2, 1, 2, 1};
+
+/* IDE I/O Configuration Registers */
+#define RDCIDE_IIOCR 0x54
+#define RDCIDE_IIOCR_CABLE(chan, drv) ((0x10 << (drv)) << (chan * 2))
+#define RDCIDE_IIOCR_CLK(val, chan, drv) (((val) << drv) << (chan * 2))
+#define RDCIDE_IIOCR_CLK_MASK(chan, drv) ((0x1001 << drv) << (chan * 2))
+
+const uint32_t rdcide_udmaclk[] =
+    {0x0000, 0x0000, 0x0000, 0x0001, 0x0001, 0x1000};
+
+/* Miscellaneous Control Register */
+#define RDCIDE_MCR 0x90
+#define RDCIDE_MCR_RESET(chan) (0x01000000 << (chan))