mirror of
https://github.com/apache/nuttx.git
synced 2026-08-26 11:50:50 +00:00
arch/arm64/src/imx9/imx9_usbdev.c: Clean up cache operations, add DEBUGASSERTS
Correct some of the cache operations: - EP0 request length was handled incorrectly - Received data cache invalidate was exceeding the received buffer - writedtd is also called with no data (EP0 ACK/NACK). Don't touch cache in that case. Fix trip wire handling to conform with the IMX93 reference manual Also add DEBUGASSERTS for future to check the validity of pointers and sizes Co-authored-by: Jukka Laitinen <jukkax@ssrc.tii.ae>
This commit is contained in:
parent
534114395e
commit
9ea098558a
1 changed files with 60 additions and 33 deletions
|
|
@ -60,7 +60,7 @@
|
|||
#endif
|
||||
|
||||
#define DCACHE_LINEMASK (ARMV8A_DCACHE_LINESIZE - 1)
|
||||
|
||||
#define DCACHE_ALIGN_UP(a) (((a) + DCACHE_LINEMASK) & ~DCACHE_LINEMASK)
|
||||
#if !defined(CONFIG_ARM64_DCACHE_DISABLE)
|
||||
# define cache_aligned_alloc(s) kmm_memalign(ARMV8A_DCACHE_LINESIZE,(s))
|
||||
# define CACHE_ALIGNED_DATA aligned_data(ARMV8A_DCACHE_LINESIZE)
|
||||
|
|
@ -69,6 +69,11 @@
|
|||
# define CACHE_ALIGNED_DATA
|
||||
#endif
|
||||
|
||||
/* Check that both start and length are cache-aligned */
|
||||
|
||||
#define IS_CACHE_ALIGNED(x,y) (((uintptr_t)(x) & DCACHE_LINEMASK) == 0 && \
|
||||
((y) & DCACHE_LINEMASK) == 0)
|
||||
|
||||
/* Configuration ************************************************************/
|
||||
|
||||
#ifndef CONFIG_USBDEV_EP0_MAXSIZE
|
||||
|
|
@ -218,6 +223,10 @@ const struct trace_msg_t g_usb_trace_strings_intdecode[] =
|
|||
};
|
||||
#endif
|
||||
|
||||
/* Length of allocated EP0 buffer (DCACHE aligned) */
|
||||
|
||||
#define EP0_MAXBUFLEN 64
|
||||
|
||||
/* Hardware interface *******************************************************/
|
||||
|
||||
/* This represents a Endpoint Transfer Descriptor dQH overlay (32 bytes) */
|
||||
|
|
@ -528,20 +537,20 @@ static int imx9_pullup(struct usbdev_s *dev, bool enable);
|
|||
*/
|
||||
|
||||
#ifdef CONFIG_IMX9_USBDEV_USBC1
|
||||
static uint8_t g_usb0_ep0buf[64] CACHE_ALIGNED_DATA;
|
||||
static uint8_t g_usb0_ep0buf[EP0_MAXBUFLEN] CACHE_ALIGNED_DATA;
|
||||
static struct imx9_dqh_s g_usb0_qh[IMX9_NPHYSENDPOINTS] aligned_data(2048);
|
||||
static struct imx9_dtd_s g_usb0_td[IMX9_NPHYSENDPOINTS];
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_IMX9_USBDEV_USBC2
|
||||
static uint8_t g_usb1_ep0buf[64] CACHE_ALIGNED_DATA;
|
||||
static uint8_t g_usb1_ep0buf[EP0_MAXBUFLEN] CACHE_ALIGNED_DATA;
|
||||
static struct imx9_dqh_s g_usb1_qh[IMX9_NPHYSENDPOINTS] aligned_data(2048);
|
||||
static struct imx9_dtd_s g_usb1_td[IMX9_NPHYSENDPOINTS];
|
||||
#endif
|
||||
|
||||
static struct imx9_usb_s g_usbdev[] =
|
||||
{
|
||||
#ifdef CONFIG_IMX9_USBDEV_USBC1
|
||||
#ifdef CONFIG_IMX9_USBDEV_USBC1
|
||||
{
|
||||
.id = 0,
|
||||
.base = IMX9_USB_OTG1_BASE,
|
||||
|
|
@ -692,10 +701,7 @@ static void imx9_putreg(struct imx9_usb_s *priv, off_t offset, uint32_t val)
|
|||
static inline void imx9_modifyreg(struct imx9_usb_s *priv, off_t offset,
|
||||
uint32_t clear, uint32_t set)
|
||||
{
|
||||
uint32_t reg = imx9_getreg(priv, offset);
|
||||
reg &= ~clear;
|
||||
reg |= set;
|
||||
imx9_putreg(priv, offset, reg);
|
||||
modifyreg32(priv->base + offset, clear, set);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -764,6 +770,8 @@ static inline void imx9_writedtd(struct imx9_dtd_s *dtd,
|
|||
const uint8_t *data,
|
||||
uint32_t nbytes)
|
||||
{
|
||||
DEBUGASSERT(IS_CACHE_ALIGNED(dtd, sizeof(*dtd)));
|
||||
|
||||
dtd->nextdesc = DTD_NEXTDESC_INVALID;
|
||||
dtd->config = DTD_CONFIG_LENGTH(nbytes) | DTD_CONFIG_IOC |
|
||||
DTD_CONFIG_ACTIVE;
|
||||
|
|
@ -776,8 +784,18 @@ static inline void imx9_writedtd(struct imx9_dtd_s *dtd,
|
|||
|
||||
up_clean_dcache((uintptr_t)dtd,
|
||||
(uintptr_t)dtd + sizeof(struct imx9_dtd_s));
|
||||
up_clean_dcache((uintptr_t)data,
|
||||
(uintptr_t)data + nbytes);
|
||||
|
||||
/* the pointer is NULL for EP0 NAK IN/OUT */
|
||||
|
||||
if (data != NULL)
|
||||
{
|
||||
DEBUGASSERT(IS_CACHE_ALIGNED(data, DCACHE_ALIGN_UP(nbytes)));
|
||||
DEBUGASSERT(nbytes <= 0x5000);
|
||||
|
||||
/* Data needs to be clean before TX, clean or invalid before RX */
|
||||
|
||||
up_clean_dcache((uintptr_t)data, (uintptr_t)data + nbytes);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -803,7 +821,7 @@ static void imx9_queuedtd(struct imx9_usb_s *priv, uint8_t epphy,
|
|||
dqh->overlay.nextdesc = (uint32_t)(uintptr_t)dtd;
|
||||
dqh->overlay.config &= ~(DTD_CONFIG_ACTIVE | DTD_CONFIG_HALTED);
|
||||
|
||||
up_flush_dcache((uintptr_t)dqh,
|
||||
up_clean_dcache((uintptr_t)dqh,
|
||||
(uintptr_t)dqh + sizeof(struct imx9_dqh_s));
|
||||
|
||||
uint32_t bit = IMX9_ENDPTMASK(epphy);
|
||||
|
|
@ -845,21 +863,20 @@ static void imx9_readsetup(struct imx9_usb_s *priv, uint8_t epphy,
|
|||
struct imx9_dqh_s *dqh = &priv->qh[epphy];
|
||||
int i;
|
||||
|
||||
do
|
||||
/* Set the trip wire */
|
||||
|
||||
imx9_modifyreg(priv, IMX9_USBDEV_USBCMD_OFFSET, 0, USBDEV_USBCMD_SUTW);
|
||||
ARM64_DSB();
|
||||
|
||||
DEBUGASSERT(IS_CACHE_ALIGNED(dqh, sizeof(struct imx9_dqh_s)));
|
||||
up_invalidate_dcache((uintptr_t)dqh,
|
||||
(uintptr_t)dqh + sizeof(struct imx9_dqh_s));
|
||||
|
||||
/* Copy the request... */
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
/* Set the trip wire */
|
||||
|
||||
imx9_modifyreg(priv, IMX9_USBDEV_USBCMD_OFFSET, 0, USBDEV_USBCMD_SUTW);
|
||||
|
||||
up_invalidate_dcache((uintptr_t)dqh,
|
||||
(uintptr_t)dqh + sizeof(struct imx9_dqh_s));
|
||||
|
||||
/* Copy the request... */
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
((uint8_t *) ctrl)[i] = ((uint8_t *) dqh->setup)[i];
|
||||
}
|
||||
((uint8_t *) ctrl)[i] = ((uint8_t *) dqh->setup)[i];
|
||||
}
|
||||
|
||||
while (!(imx9_getreg(priv,
|
||||
|
|
@ -869,13 +886,11 @@ static void imx9_readsetup(struct imx9_usb_s *priv, uint8_t epphy,
|
|||
|
||||
imx9_modifyreg(priv, IMX9_USBDEV_USBCMD_OFFSET, USBDEV_USBCMD_SUTW, 0);
|
||||
|
||||
up_clean_dcache((uintptr_t)dqh,
|
||||
(uintptr_t)dqh + sizeof(struct imx9_dqh_s));
|
||||
|
||||
/* Clear the Setup Interrupt */
|
||||
|
||||
imx9_putreg(priv, IMX9_USBDEV_ENDPTSETUPSTAT_OFFSET,
|
||||
IMX9_ENDPTMASK(IMX9_EP0_OUT));
|
||||
ARM64_DSB();
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -1120,8 +1135,9 @@ static void imx9_dispatchrequest(struct imx9_usb_s *priv,
|
|||
{
|
||||
/* Invalidate buffer data cache */
|
||||
|
||||
DEBUGASSERT(IS_CACHE_ALIGNED(priv->ep0.buf, EP0_MAXBUFLEN));
|
||||
up_invalidate_dcache((uintptr_t)priv->ep0.buf,
|
||||
(uintptr_t)priv->ep0.buf + sizeof(priv->ep0.buf));
|
||||
(uintptr_t)priv->ep0.buf + EP0_MAXBUFLEN);
|
||||
|
||||
/* Forward to the control request to the class driver implementation */
|
||||
|
||||
|
|
@ -1162,7 +1178,7 @@ static void imx9_ep0configure(struct imx9_usb_s *priv)
|
|||
priv->qh[IMX9_EP0_IN].currdesc = DTD_NEXTDESC_INVALID;
|
||||
|
||||
up_clean_dcache((uintptr_t)priv->qh,
|
||||
(uintptr_t)priv->qh + (sizeof(struct imx9_dqh_s) * 2));
|
||||
(uintptr_t)priv->qh + (sizeof(struct imx9_dqh_s)));
|
||||
|
||||
/* Enable EP0 */
|
||||
|
||||
|
|
@ -1303,6 +1319,8 @@ static inline void imx9_ep0state(struct imx9_usb_s *priv,
|
|||
imx9_putreg(priv, IMX9_USBDEV_ENDPTNAKEN_OFFSET, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
ARM64_DSB();
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -1347,7 +1365,9 @@ static inline void imx9_ep0setup(struct imx9_usb_s *priv)
|
|||
index = GETUINT16(ctrl->index);
|
||||
len = GETUINT16(ctrl->len);
|
||||
|
||||
priv->ep0.buf_len = len;
|
||||
/* Limit the ep0 length to maximum */
|
||||
|
||||
priv->ep0.buf_len = len <= EP0_MAXBUFLEN ? len : EP0_MAXBUFLEN;
|
||||
|
||||
uinfo("type=%02x req=%02x value=%04x index=%04x len=%04x\n",
|
||||
ctrl->type, ctrl->req, value, index, len);
|
||||
|
|
@ -1868,10 +1888,9 @@ bool imx9_epcomplete(struct imx9_usb_s *priv, uint8_t epphy)
|
|||
|
||||
/* Make sure we have updated data after the DMA transfer. */
|
||||
|
||||
DEBUGASSERT(IS_CACHE_ALIGNED(dtd, sizeof(struct imx9_dtd_s)));
|
||||
up_invalidate_dcache((uintptr_t)dtd,
|
||||
(uintptr_t)dtd + sizeof(struct imx9_dtd_s));
|
||||
up_invalidate_dcache((uintptr_t)dtd->buffer0,
|
||||
(uintptr_t)dtd->buffer0 + dtd->xfer_len);
|
||||
|
||||
int xfrd = dtd->xfer_len - (dtd->config >> 16);
|
||||
|
||||
|
|
@ -1885,6 +1904,14 @@ bool imx9_epcomplete(struct imx9_usb_s *priv, uint8_t epphy)
|
|||
*/
|
||||
|
||||
usbtrace(TRACE_INTDECODE(IMX9_TRACEINTID_EPIN), complete);
|
||||
|
||||
/* Invalidate rx buffer cache */
|
||||
|
||||
DEBUGASSERT(IS_CACHE_ALIGNED(privreq->req.buf,
|
||||
DCACHE_ALIGN_UP(privreq->req.xfrd)));
|
||||
up_invalidate_dcache((uintptr_t)privreq->req.buf,
|
||||
(uintptr_t)privreq->req.buf +
|
||||
DCACHE_ALIGN_UP(privreq->req.xfrd));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue