svn commit: r327638 - in stable/11/sys/dev: ffec sdhci
Ian Lepore
ian at FreeBSD.org
Sat Jan 6 21:19:54 UTC 2018
Author: ian
Date: Sat Jan 6 21:19:52 2018
New Revision: 327638
URL: https://svnweb.freebsd.org/changeset/base/327638
Log:
MFC r325045, r325054-r325056, r325061, r325063, r325065
r325045:
Actually release resources in detach() rather than just returning EBUSY.
This will enable use of 'devctl disable', allow creation of a module, etc.
r325054:
Increase the alignment of the rx/tx descriptor ring buffers to 64 bytes.
16 was the correct alignment for older hardware, but the imx7 requires
64-byte alignment, which is a fine value to use on all systems.
PR: 222634
Submitted by: sebastian.huber at embedded-brains.de
r325055:
Add FECFLAG_AVB variant flag to support new features on imx7.
This flag is analogous to the Linux driver FEC_QUIRK_HAS_AVB. It
indicates an FEC with support for Audio Video Bridging (AVB). This
indicator is used for various other parts in the Linux driver
(drivers/net/ethernet/freescale/fec_main.c).
Use it to customize the receive/transmit buffer alignment. The receive
buffer alignment increased to 64-bytes on the i.MX 6SoloX and i.MX
7Dual. There are no hard alignment restrictions for transmit buffers on
these chips.
Fix the ffec_softc::fectype type to provide enough storage for the
feature flags.
PR: 222634
Submitted by: sebastian.huber at embedded-brains.de
r325056:
Avoid AXI bus issues due to a MAC reset on imx6sx and imx7.
When the FEC is connected to the AXI bus (indicated by AVB flag), a
MAC reset while a bus transaction is pending can hang the bus.
Instead of resetting, turn off the ENABLE bit, which allows the
hardware to complete any in-progress transfers (appending a bad CRC
to any partial packet) and release the AXI bus. This could probably
be done unconditionally for all hardware variants, but that hasn't
been tested.
PR: 222634
Submitted by: sebastian.huber at embedded-brains.de
r325061:
Support up to 3 IRQs in the ffec driver.
Newer hardware splits the interrupts onto 3 different irq lines, but the
docs barely mention that there are multiple interrupts, and do not detail
how they're split up. The code now supports 1-3 irqs, and uses the same
interrupt service routine to handle all of them.
I modified the submitted changes to use bus_alloc_resources() instead of
using loops to allocate each irq separately. Thus, blame any bugs on me (I
can't actually test on imx7 hardware).
PR: 222634
Submitted by: sebastian.huber at embedded-brains.de
r325063:
Use the 16-bit receive shift feature in ffec hardware that supports it.
When available, enabling this feature causes the hardware to write data
to the receive buffer starting at a 16-bit offset from the start address.
This eliminates the need to copy the data after receiving to re-align
the protocol headers to a 32-bit boundary.
PR: 222634
Submitted by: sebastian.huber at embedded-brains.de
r325065:
Split the hardware type enum and the hw feature flags bits into separate
fields in the softc; they're ORed together in the ofw_compat_data.
I already caught myself doing 'sc->fectype == <enum val>' without masking
out the feature bits in one place, and that's sure to happen again.
Glomming them together is convenient for storing them in the ofw_compat_data
array, but there's no reason to keep them together in the softc.
Modified:
stable/11/sys/dev/ffec/if_ffec.c
stable/11/sys/dev/ffec/if_ffecreg.h
stable/11/sys/dev/sdhci/fsl_sdhci.c
Directory Properties:
stable/11/ (props changed)
Modified: stable/11/sys/dev/ffec/if_ffec.c
==============================================================================
--- stable/11/sys/dev/ffec/if_ffec.c Sat Jan 6 20:52:30 2018 (r327637)
+++ stable/11/sys/dev/ffec/if_ffec.c Sat Jan 6 21:19:52 2018 (r327638)
@@ -97,16 +97,21 @@ enum {
FECTYPE_NONE,
FECTYPE_GENERIC,
FECTYPE_IMX53,
- FECTYPE_IMX6,
+ FECTYPE_IMX6, /* imx6 and imx7 */
FECTYPE_MVF,
};
/*
* Flags that describe general differences between the FEC hardware in various
- * SoCs. These are ORed into the FECTYPE enum values.
+ * SoCs. These are ORed into the FECTYPE enum values in the ofw_compat_data, so
+ * the low 8 bits are reserved for the type enum. In the softc, the type and
+ * flags are put into separate members, so that you don't need to mask the flags
+ * out of the type to compare it.
*/
-#define FECTYPE_MASK 0x0000ffff
-#define FECFLAG_GBE (0x0001 << 16)
+#define FECTYPE_MASK 0x000000ff
+#define FECFLAG_GBE (1 << 8)
+#define FECFLAG_AVB (1 << 9)
+#define FECFLAG_RACC (1 << 10)
/*
* Table of supported FDT compat strings and their associated FECTYPE values.
@@ -114,9 +119,11 @@ enum {
static struct ofw_compat_data compat_data[] = {
{"fsl,imx51-fec", FECTYPE_GENERIC},
{"fsl,imx53-fec", FECTYPE_IMX53},
- {"fsl,imx6q-fec", FECTYPE_IMX6 | FECFLAG_GBE},
- {"fsl,imx6ul-fec", FECTYPE_IMX6},
- {"fsl,mvf600-fec", FECTYPE_MVF},
+ {"fsl,imx6q-fec", FECTYPE_IMX6 | FECFLAG_RACC | FECFLAG_GBE },
+ {"fsl,imx6ul-fec", FECTYPE_IMX6 | FECFLAG_RACC },
+ {"fsl,imx7d-fec", FECTYPE_IMX6 | FECFLAG_RACC | FECFLAG_GBE |
+ FECFLAG_AVB },
+ {"fsl,mvf600-fec", FECTYPE_MVF | FECFLAG_RACC },
{"fsl,mvf-fec", FECTYPE_MVF},
{NULL, FECTYPE_NONE},
};
@@ -131,6 +138,8 @@ static struct ofw_compat_data compat_data[] = {
#define WATCHDOG_TIMEOUT_SECS 5
+#define MAX_IRQ_COUNT 3
+
struct ffec_bufmap {
struct mbuf *mbuf;
bus_dmamap_t map;
@@ -143,16 +152,19 @@ struct ffec_softc {
struct ifnet *ifp;
int if_flags;
struct mtx mtx;
- struct resource *irq_res;
+ struct resource *irq_res[MAX_IRQ_COUNT];
struct resource *mem_res;
- void * intr_cookie;
+ void * intr_cookie[MAX_IRQ_COUNT];
struct callout ffec_callout;
mii_contype_t phy_conn_type;
+ uint32_t fecflags;
uint8_t fectype;
boolean_t link_is_up;
boolean_t is_attached;
boolean_t is_detaching;
int tx_watchdog_count;
+ int rxbuf_align;
+ int txbuf_align;
bus_dma_tag_t rxdesc_tag;
bus_dmamap_t rxdesc_map;
@@ -173,6 +185,13 @@ struct ffec_softc {
int txcount;
};
+static struct resource_spec irq_res_spec[MAX_IRQ_COUNT + 1] = {
+ { SYS_RES_IRQ, 0, RF_ACTIVE },
+ { SYS_RES_IRQ, 1, RF_ACTIVE | RF_OPTIONAL },
+ { SYS_RES_IRQ, 2, RF_ACTIVE | RF_OPTIONAL },
+ RESOURCE_SPEC_END
+};
+
#define FFEC_LOCK(sc) mtx_lock(&(sc)->mtx)
#define FFEC_UNLOCK(sc) mtx_unlock(&(sc)->mtx)
#define FFEC_LOCK_INIT(sc) mtx_init(&(sc)->mtx, \
@@ -246,7 +265,7 @@ ffec_miigasket_setup(struct ffec_softc *sc)
* We only need the gasket for MII and RMII connections on certain SoCs.
*/
- switch (sc->fectype & FECTYPE_MASK)
+ switch (sc->fectype)
{
case FECTYPE_IMX53:
break;
@@ -747,14 +766,17 @@ ffec_setup_rxbuf(struct ffec_softc *sc, int idx, struc
int error, nsegs;
struct bus_dma_segment seg;
- /*
- * We need to leave at least ETHER_ALIGN bytes free at the beginning of
- * the buffer to allow the data to be re-aligned after receiving it (by
- * copying it backwards ETHER_ALIGN bytes in the same buffer). We also
- * have to ensure that the beginning of the buffer is aligned to the
- * hardware's requirements.
- */
- m_adj(m, roundup(ETHER_ALIGN, FEC_RXBUF_ALIGN));
+ if (!(sc->fecflags & FECFLAG_RACC)) {
+ /*
+ * The RACC[SHIFT16] feature is not available. So, we need to
+ * leave at least ETHER_ALIGN bytes free at the beginning of the
+ * buffer to allow the data to be re-aligned after receiving it
+ * (by copying it backwards ETHER_ALIGN bytes in the same
+ * buffer). We also have to ensure that the beginning of the
+ * buffer is aligned to the hardware's requirements.
+ */
+ m_adj(m, roundup(ETHER_ALIGN, sc->rxbuf_align));
+ }
error = bus_dmamap_load_mbuf_sg(sc->rxbuf_tag, sc->rxbuf_map[idx].map,
m, &seg, &nsegs, 0);
@@ -802,23 +824,6 @@ ffec_rxfinish_onebuf(struct ffec_softc *sc, int len)
return;
}
- /*
- * Unfortunately, the protocol headers need to be aligned on a 32-bit
- * boundary for the upper layers. The hardware requires receive
- * buffers to be 16-byte aligned. The ethernet header is 14 bytes,
- * leaving the protocol header unaligned. We used m_adj() after
- * allocating the buffer to leave empty space at the start of the
- * buffer, now we'll use the alignment agnostic bcopy() routine to
- * shuffle all the data backwards 2 bytes and adjust m_data.
- *
- * XXX imx6 hardware is able to do this 2-byte alignment by setting the
- * SHIFT16 bit in the RACC register. Older hardware doesn't have that
- * feature, but for them could we speed this up by copying just the
- * protocol headers into their own small mbuf then chaining the cluster
- * to it? That way we'd only need to copy like 64 bytes or whatever
- * the biggest header is, instead of the whole 1530ish-byte frame.
- */
-
FFEC_UNLOCK(sc);
bmap = &sc->rxbuf_map[sc->rx_idx];
@@ -831,10 +836,24 @@ ffec_rxfinish_onebuf(struct ffec_softc *sc, int len)
m->m_pkthdr.len = len;
m->m_pkthdr.rcvif = sc->ifp;
- src = mtod(m, uint8_t*);
- dst = src - ETHER_ALIGN;
- bcopy(src, dst, len);
- m->m_data = dst;
+ /*
+ * Align the protocol headers in the receive buffer on a 32-bit
+ * boundary. Newer hardware does the alignment for us. On hardware
+ * that doesn't support this feature, we have to copy-align the data.
+ *
+ * XXX for older hardware, could we speed this up by copying just the
+ * protocol headers into their own small mbuf then chaining the cluster
+ * to it? That way we'd only need to copy like 64 bytes or whatever the
+ * biggest header is, instead of the whole 1530ish-byte frame.
+ */
+ if (sc->fecflags & FECFLAG_RACC) {
+ m->m_data = mtod(m, uint8_t *) + 2;
+ } else {
+ src = mtod(m, uint8_t*);
+ dst = src - ETHER_ALIGN;
+ bcopy(src, dst, len);
+ m->m_data = dst;
+ }
sc->ifp->if_input(sc->ifp, m);
FFEC_LOCK(sc);
@@ -1098,7 +1117,7 @@ ffec_init_locked(struct ffec_softc *sc)
* when we support jumbo frames and receiving fragments of them into
* separate buffers.
*/
- maxbuf = MCLBYTES - roundup(ETHER_ALIGN, FEC_RXBUF_ALIGN);
+ maxbuf = MCLBYTES - roundup(ETHER_ALIGN, sc->rxbuf_align);
maxfl = min(maxbuf, 0x7ff);
if (ifp->if_drv_flags & IFF_DRV_RUNNING)
@@ -1208,6 +1227,14 @@ ffec_init_locked(struct ffec_softc *sc)
ffec_clear_stats(sc);
WR4(sc, FEC_MIBC_REG, regval & ~FEC_MIBC_DIS);
+ if (sc->fecflags & FECFLAG_RACC) {
+ /*
+ * RACC - Receive Accelerator Function Configuration.
+ */
+ regval = RD4(sc, FEC_RACC_REG);
+ WR4(sc, FEC_RACC_REG, regval | FEC_RACC_SHIFT16);
+ }
+
/*
* ECR - Ethernet control register.
*
@@ -1360,7 +1387,7 @@ ffec_detach(device_t dev)
{
struct ffec_softc *sc;
bus_dmamap_t map;
- int idx;
+ int idx, irq;
/*
* NB: This function can be called internally to unwind a failure to
@@ -1411,15 +1438,17 @@ ffec_detach(device_t dev)
bus_dmamap_destroy(sc->txdesc_tag, sc->txdesc_map);
}
if (sc->txdesc_tag != NULL)
- bus_dma_tag_destroy(sc->txdesc_tag);
+ bus_dma_tag_destroy(sc->txdesc_tag);
/* Release bus resources. */
- if (sc->intr_cookie)
- bus_teardown_intr(dev, sc->irq_res, sc->intr_cookie);
+ for (irq = 0; irq < MAX_IRQ_COUNT; ++irq) {
+ if (sc->intr_cookie[irq] != NULL) {
+ bus_teardown_intr(dev, sc->irq_res[irq],
+ sc->intr_cookie[irq]);
+ }
+ }
+ bus_release_resources(dev, irq_res_spec, sc->irq_res);
- if (sc->irq_res != NULL)
- bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
-
if (sc->mem_res != NULL)
bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
@@ -1434,10 +1463,11 @@ ffec_attach(device_t dev)
struct ifnet *ifp = NULL;
struct mbuf *m;
void *dummy;
+ uintptr_t typeflags;
phandle_t ofw_node;
- int error, phynum, rid;
- uint8_t eaddr[ETHER_ADDR_LEN];
uint32_t idx, mscr;
+ int error, phynum, rid, irq;
+ uint8_t eaddr[ETHER_ADDR_LEN];
sc = device_get_softc(dev);
sc->dev = dev;
@@ -1448,8 +1478,18 @@ ffec_attach(device_t dev)
* There are differences in the implementation and features of the FEC
* hardware on different SoCs, so figure out what type we are.
*/
- sc->fectype = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
+ typeflags = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
+ sc->fectype = (uint8_t)(typeflags & FECTYPE_MASK);
+ sc->fecflags = (uint32_t)(typeflags & ~FECTYPE_MASK);
+ if (sc->fecflags & FECFLAG_AVB) {
+ sc->rxbuf_align = 64;
+ sc->txbuf_align = 1;
+ } else {
+ sc->rxbuf_align = 16;
+ sc->txbuf_align = 16;
+ }
+
/*
* We have to be told what kind of electrical connection exists between
* the MAC and PHY or we can't operate correctly.
@@ -1478,12 +1518,10 @@ ffec_attach(device_t dev)
error = ENOMEM;
goto out;
}
- rid = 0;
- sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
- RF_ACTIVE);
- if (sc->irq_res == NULL) {
- device_printf(dev, "could not allocate interrupt resources.\n");
- error = ENOMEM;
+
+ error = bus_alloc_resources(dev, irq_res_spec, sc->irq_res);
+ if (error != 0) {
+ device_printf(dev, "could not allocate interrupt resources\n");
goto out;
}
@@ -1525,7 +1563,7 @@ ffec_attach(device_t dev)
error = bus_dma_tag_create(
bus_get_dma_tag(dev), /* Parent tag. */
- FEC_TXBUF_ALIGN, 0, /* alignment, boundary */
+ sc->txbuf_align, 0, /* alignment, boundary */
BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
BUS_SPACE_MAXADDR, /* highaddr */
NULL, NULL, /* filter, filterarg */
@@ -1627,15 +1665,34 @@ ffec_attach(device_t dev)
/* Try to get the MAC address from the hardware before resetting it. */
ffec_get_hwaddr(sc, eaddr);
- /* Reset the hardware. Disables all interrupts. */
- WR4(sc, FEC_ECR_REG, FEC_ECR_RESET);
+ /*
+ * Reset the hardware. Disables all interrupts.
+ *
+ * When the FEC is connected to the AXI bus (indicated by AVB flag), a
+ * MAC reset while a bus transaction is pending can hang the bus.
+ * Instead of resetting, turn off the ENABLE bit, which allows the
+ * hardware to complete any in-progress transfers (appending a bad CRC
+ * to any partial packet) and release the AXI bus. This could probably
+ * be done unconditionally for all hardware variants, but that hasn't
+ * been tested.
+ */
+ if (sc->fecflags & FECFLAG_AVB)
+ WR4(sc, FEC_ECR_REG, 0);
+ else
+ WR4(sc, FEC_ECR_REG, FEC_ECR_RESET);
/* Setup interrupt handler. */
- error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET | INTR_MPSAFE,
- NULL, ffec_intr, sc, &sc->intr_cookie);
- if (error != 0) {
- device_printf(dev, "could not setup interrupt handler.\n");
- goto out;
+ for (irq = 0; irq < MAX_IRQ_COUNT; ++irq) {
+ if (sc->irq_res[irq] != NULL) {
+ error = bus_setup_intr(dev, sc->irq_res[irq],
+ INTR_TYPE_NET | INTR_MPSAFE, NULL, ffec_intr, sc,
+ &sc->intr_cookie[irq]);
+ if (error != 0) {
+ device_printf(dev,
+ "could not setup interrupt handler.\n");
+ goto out;
+ }
+ }
}
/*
@@ -1701,7 +1758,7 @@ ffec_attach(device_t dev)
}
error = mii_attach(dev, &sc->miibus, ifp, ffec_media_change,
ffec_media_status, BMSR_DEFCAPMASK, phynum, MII_OFFSET_ANY,
- (sc->fectype & FECTYPE_MVF) ? MIIF_FORCEANEG : 0);
+ (sc->fecflags & FECTYPE_MVF) ? MIIF_FORCEANEG : 0);
if (error != 0) {
device_printf(dev, "PHY attach failed\n");
goto out;
Modified: stable/11/sys/dev/ffec/if_ffecreg.h
==============================================================================
--- stable/11/sys/dev/ffec/if_ffecreg.h Sat Jan 6 20:52:30 2018 (r327637)
+++ stable/11/sys/dev/ffec/if_ffecreg.h Sat Jan 6 21:19:52 2018 (r327638)
@@ -317,8 +317,6 @@ struct ffec_hwdesc
* The hardware imposes alignment restrictions on various objects involved in
* DMA transfers. These values are expressed in bytes (not bits).
*/
-#define FEC_DESC_RING_ALIGN 16
-#define FEC_RXBUF_ALIGN 16
-#define FEC_TXBUF_ALIGN 16
+#define FEC_DESC_RING_ALIGN 64
#endif /* IF_FFECREG_H */
Modified: stable/11/sys/dev/sdhci/fsl_sdhci.c
==============================================================================
--- stable/11/sys/dev/sdhci/fsl_sdhci.c Sat Jan 6 20:52:30 2018 (r327637)
+++ stable/11/sys/dev/sdhci/fsl_sdhci.c Sat Jan 6 21:19:52 2018 (r327638)
@@ -807,9 +807,26 @@ fsl_sdhci_get_platform_clock(device_t dev)
static int
fsl_sdhci_detach(device_t dev)
{
+ struct fsl_sdhci_softc *sc = device_get_softc(dev);
- /* sdhci_fdt_gpio_teardown(sc->gpio); */
- return (EBUSY);
+ if (sc->gpio != NULL)
+ sdhci_fdt_gpio_teardown(sc->gpio);
+
+ callout_drain(&sc->r1bfix_callout);
+
+ if (sc->intr_cookie != NULL)
+ bus_teardown_intr(dev, sc->irq_res, sc->intr_cookie);
+ if (sc->irq_res != NULL)
+ bus_release_resource(dev, SYS_RES_IRQ,
+ rman_get_rid(sc->irq_res), sc->irq_res);
+
+ if (sc->mem_res != NULL) {
+ sdhci_cleanup_slot(&sc->slot);
+ bus_release_resource(dev, SYS_RES_MEMORY,
+ rman_get_rid(sc->mem_res), sc->mem_res);
+ }
+
+ return (0);
}
static int
@@ -922,13 +939,7 @@ fsl_sdhci_attach(device_t dev)
return (0);
fail:
- if (sc->intr_cookie)
- bus_teardown_intr(dev, sc->irq_res, sc->intr_cookie);
- if (sc->irq_res)
- bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
- if (sc->mem_res)
- bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
-
+ fsl_sdhci_detach(dev);
return (err);
}
@@ -936,7 +947,7 @@ static int
fsl_sdhci_probe(device_t dev)
{
- if (!ofw_bus_status_okay(dev))
+ if (!ofw_bus_status_okay(dev))
return (ENXIO);
switch (ofw_bus_search_compatible(dev, compat_data)->ocd_data) {
More information about the svn-src-all
mailing list