From ab96e3fdc72846515a746b87f6efa47faaf06c3c Mon Sep 17 00:00:00 2001 From: Masayuki Ishikawa Date: Fri, 8 Dec 2017 12:31:34 +0000 Subject: [PATCH] Merged in masayuki2009/nuttx.nuttx/lc823450_smp_improvement (pull request #554) lc823450 smp improvement * arch/arm/src/common: Apply irq_spin APIs to modifyregXX Replace enter_critical_section with spin_lock_irqsave. Replace leave_critical_section with spin_unlock_irqrestore. Please see 6150299f5406641ce03fa29e506727f1e72068e4 as well. Signed-off-by: Masayuki Ishikawa * arch/arm/src/lc823450: Do not use modifyreg32() to enable Mutex. Signed-off-by: Masayuki Ishikawa * arch/arm/src/lc823450: Modify IRQ control for i2s Interrupt will be handled on CPU0 with this change. Signed-off-by: Masayuki Ishikawa * arch/arm/src/lc823450: Apply irq_spin APIs to dma/syscontrol/usbdev. Signed-off-by: Masayuki Ishikawa * configs/lc823450-xgevk: Assign CPU1 to lpwork This change will improve load balancing for networking with RNDIS. Signed-off-by: Masayuki Ishikawa * drivers/audio/wm8776.c: Improve stability in SMP mode Apply irq_spin APIs to improbe performance. Repeat to process a message to avoid deadlock. Signed-off-by: Masayuki Ishikawa * configs/lc823450-xgevk: Enable SPINLOCK_IRQ and NXPLAYER in rndis Signed-off-by: Masayuki Ishikawa Approved-by: Gregory Nutt --- arch/arm/src/common/up_modifyreg16.c | 4 +- arch/arm/src/common/up_modifyreg32.c | 4 +- arch/arm/src/common/up_modifyreg8.c | 4 +- arch/arm/src/lc823450/lc823450_dma.c | 14 +++---- arch/arm/src/lc823450/lc823450_i2s.c | 16 ++++---- arch/arm/src/lc823450/lc823450_start.c | 7 +++- arch/arm/src/lc823450/lc823450_syscontrol.c | 8 ++-- arch/arm/src/lc823450/lc823450_usbdev.c | 38 +++++++++---------- configs/lc823450-xgevk/rndis/defconfig | 3 ++ configs/lc823450-xgevk/src/lc823450_bringup.c | 14 +++++++ drivers/audio/wm8776.c | 29 ++++++++++---- 11 files changed, 87 insertions(+), 54 deletions(-) diff --git a/arch/arm/src/common/up_modifyreg16.c b/arch/arm/src/common/up_modifyreg16.c index 8871d7f60c0..796732093e3 100644 --- a/arch/arm/src/common/up_modifyreg16.c +++ b/arch/arm/src/common/up_modifyreg16.c @@ -64,10 +64,10 @@ void modifyreg16(unsigned int addr, uint16_t clearbits, uint16_t setbits) irqstate_t flags; uint16_t regval; - flags = enter_critical_section(); + flags = spin_lock_irqsave(); regval = getreg16(addr); regval &= ~clearbits; regval |= setbits; putreg16(regval, addr); - leave_critical_section(flags); + spin_unlock_irqrestore(flags); } diff --git a/arch/arm/src/common/up_modifyreg32.c b/arch/arm/src/common/up_modifyreg32.c index 0a1619592b5..c49cdfa425a 100644 --- a/arch/arm/src/common/up_modifyreg32.c +++ b/arch/arm/src/common/up_modifyreg32.c @@ -64,10 +64,10 @@ void modifyreg32(unsigned int addr, uint32_t clearbits, uint32_t setbits) irqstate_t flags; uint32_t regval; - flags = enter_critical_section(); + flags = spin_lock_irqsave(); regval = getreg32(addr); regval &= ~clearbits; regval |= setbits; putreg32(regval, addr); - leave_critical_section(flags); + spin_unlock_irqrestore(flags); } diff --git a/arch/arm/src/common/up_modifyreg8.c b/arch/arm/src/common/up_modifyreg8.c index abc4b60885c..b67cbdc028c 100644 --- a/arch/arm/src/common/up_modifyreg8.c +++ b/arch/arm/src/common/up_modifyreg8.c @@ -64,10 +64,10 @@ void modifyreg8(unsigned int addr, uint8_t clearbits, uint8_t setbits) irqstate_t flags; uint8_t regval; - flags = enter_critical_section(); + flags = spin_lock_irqsave(); regval = getreg8(addr); regval &= ~clearbits; regval |= setbits; putreg8(regval, addr); - leave_critical_section(flags); + spin_unlock_irqrestore(flags); } diff --git a/arch/arm/src/lc823450/lc823450_dma.c b/arch/arm/src/lc823450/lc823450_dma.c index 104c1d2ac6d..916a7a9182c 100644 --- a/arch/arm/src/lc823450/lc823450_dma.c +++ b/arch/arm/src/lc823450/lc823450_dma.c @@ -218,14 +218,14 @@ static int phydmastart(struct lc823450_phydmach_s *pdmach) struct lc823450_dmach_s *dmach; sq_entry_t *q_ent; - flags = enter_critical_section(); + flags = spin_lock_irqsave(); q_ent = pdmach->req_q.tail; if (!q_ent) { pdmach->inprogress = 0; - leave_critical_section(flags); + spin_unlock_irqrestore(flags); return 0; } @@ -288,7 +288,7 @@ static int phydmastart(struct lc823450_phydmach_s *pdmach) modifyreg32(DMACCFG(dmach->chn), 0, DMACCFG_ITC | DMACCFG_E); - leave_critical_section(flags); + spin_unlock_irqrestore(flags); return 0; } @@ -614,7 +614,7 @@ int lc823450_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg) /* select physical channel */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(); sq_addfirst(&dmach->q_ent, &g_dma.phydmach[dmach->chn].req_q); @@ -628,7 +628,7 @@ int lc823450_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg) phydmastart(&g_dma.phydmach[dmach->chn]); } - leave_critical_section(flags); + spin_unlock_irqrestore(flags); return OK; } @@ -645,7 +645,7 @@ void lc823450_dmastop(DMA_HANDLE handle) DEBUGASSERT(dmach); - flags = enter_critical_section(); + flags = spin_lock_irqsave(); modifyreg32(DMACCFG(dmach->chn), DMACCFG_ITC | DMACCFG_E, 0); @@ -660,6 +660,6 @@ void lc823450_dmastop(DMA_HANDLE handle) sq_rem(&dmach->q_ent, &pdmach->req_q); } - leave_critical_section(flags); + spin_unlock_irqrestore(flags); return; } diff --git a/arch/arm/src/lc823450/lc823450_i2s.c b/arch/arm/src/lc823450/lc823450_i2s.c index b2cef037db0..3eced5cb4f2 100644 --- a/arch/arm/src/lc823450/lc823450_i2s.c +++ b/arch/arm/src/lc823450/lc823450_i2s.c @@ -280,9 +280,9 @@ static uint32_t lc823450_i2s_txdatawidth(struct i2s_dev_s *dev, int bits) static int _i2s_isr(int irq, FAR void *context, FAR void *arg) { - /* disable interrupt */ + /* Disable Buffer F Under Level IRQ */ - up_disable_irq(LC823450_IRQ_AUDIOBUF0); + putreg32(0, ABUFIRQEN0); /* post semaphore for the waiter */ @@ -298,9 +298,9 @@ static int lc823450_i2s_send(struct i2s_dev_s *dev, struct ap_buffer_s *apb, i2s_callback_t callback, void *arg, uint32_t timeout) { - /* Enable IRQ for Audio Buffer */ + /* Enable Buffer F Under Level IRQ */ - up_enable_irq(LC823450_IRQ_AUDIOBUF0); + putreg32(ABUFIRQEN0_BFULIRQEN, ABUFIRQEN0); /* Wait for Audio Buffer */ @@ -374,10 +374,6 @@ static int lc823450_i2s_configure(void) putreg32(1024, BUF_F_ULVL); - /* Enable Buffer F Under Level IRQ */ - - putreg32(ABUFIRQEN0_BFULIRQEN, ABUFIRQEN0); - /* Clear Audio Buffer */ putreg32(0xffff, ABUFCLR); @@ -466,6 +462,10 @@ FAR struct i2s_dev_s *lc823450_i2sdev_initialize(void) irq_attach(LC823450_IRQ_AUDIOBUF0, _i2s_isr, NULL); + /* Enable IRQ for Audio Buffer */ + + up_enable_irq(LC823450_IRQ_AUDIOBUF0); + /* Success exit */ return &priv->dev; diff --git a/arch/arm/src/lc823450/lc823450_start.c b/arch/arm/src/lc823450/lc823450_start.c index adde59c14a9..089f21eaee6 100644 --- a/arch/arm/src/lc823450/lc823450_start.c +++ b/arch/arm/src/lc823450/lc823450_start.c @@ -259,9 +259,12 @@ void __start(void) #endif /* CONFIG_LC823450_IPL2 */ #endif /* CONFIG_LC823450_SPIFLASH_BOOT */ - /* Mutex enable */ + /* Enable Mutex */ + /* NOTE: modyfyreg32() can not be used because it might use spin_lock */ - modifyreg32(MRSTCNTBASIC, 0, MRSTCNTBASIC_MUTEX_RSTB); + uint32_t val = getreg32(MRSTCNTBASIC); + val |= MRSTCNTBASIC_MUTEX_RSTB; + putreg32(val, MRSTCNTBASIC); /* Configure the uart so that we can get debug output as soon as possible */ diff --git a/arch/arm/src/lc823450/lc823450_syscontrol.c b/arch/arm/src/lc823450/lc823450_syscontrol.c index 35d18b2a2a6..82e6c2ee018 100644 --- a/arch/arm/src/lc823450/lc823450_syscontrol.c +++ b/arch/arm/src/lc823450/lc823450_syscontrol.c @@ -144,7 +144,7 @@ void mod_stby_regs(uint32_t enabits, uint32_t disbits) void up_enable_clk(enum clock_e clk) { irqstate_t flags; - flags = enter_critical_section(); + flags = spin_lock_irqsave(); ASSERT(clk < LC823450_CLOCK_NUM); @@ -154,7 +154,7 @@ void up_enable_clk(enum clock_e clk) 0, lc823450_clocks[clk].regmask); } - leave_critical_section(flags); + spin_unlock_irqrestore(flags); } /**************************************************************************** @@ -164,7 +164,7 @@ void up_enable_clk(enum clock_e clk) void up_disable_clk(enum clock_e clk) { irqstate_t flags; - flags = enter_critical_section(); + flags = spin_lock_irqsave(); ASSERT(clk < LC823450_CLOCK_NUM); @@ -181,7 +181,7 @@ void up_disable_clk(enum clock_e clk) lc823450_clocks[clk].count = 0; } - leave_critical_section(flags); + spin_unlock_irqrestore(flags); } /**************************************************************************** diff --git a/arch/arm/src/lc823450/lc823450_usbdev.c b/arch/arm/src/lc823450/lc823450_usbdev.c index f8c0a09787c..f5311e377bf 100644 --- a/arch/arm/src/lc823450/lc823450_usbdev.c +++ b/arch/arm/src/lc823450/lc823450_usbdev.c @@ -487,7 +487,7 @@ static int lc823450_epclearreq(struct usbdev_ep_s *ep) struct lc823450_ep_s *privep = (struct lc823450_ep_s *)ep; irqstate_t flags; - flags = enter_critical_section(); + flags = spin_lock_irqsave(); while (privep->req_q.tail) { struct usbdev_req_s *req; @@ -504,7 +504,7 @@ static int lc823450_epclearreq(struct usbdev_ep_s *ep) req->callback(ep, req); } - leave_critical_section(flags); + spin_unlock_irqrestore(flags); return 0; } @@ -666,27 +666,27 @@ static int lc823450_epsubmit(struct usbdev_ep_s *ep, struct usbdev_req_s *req) if (privep->epphy == 0) { - flags = enter_critical_section(); + flags = spin_lock_irqsave(); req->xfrd = epbuf_write(privep->epphy, req->buf, req->len); - leave_critical_section(flags); + spin_unlock_irqrestore(flags); req->callback(ep, req); } else if (privep->in) { /* Send packet requst from function driver */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(); if ((getreg32(USB_EPCOUNT(privep->epphy * 2)) & USB_EPCOUNT_PHYCNT_MASK) >> USB_EPCOUNT_PHYCNT_SHIFT || privep->req_q.tail) { sq_addfirst(&privreq->q_ent, &privep->req_q); /* non block */ - leave_critical_section(flags); + spin_unlock_irqrestore(flags); } else { - leave_critical_section(flags); + spin_unlock_irqrestore(flags); req->xfrd = epbuf_write(privep->epphy, req->buf, req->len); req->callback(ep, req); } @@ -695,9 +695,9 @@ static int lc823450_epsubmit(struct usbdev_ep_s *ep, struct usbdev_req_s *req) { /* receive packet buffer from function driver */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(); sq_addfirst(&privreq->q_ent, &privep->req_q); /* non block */ - leave_critical_section(flags); + spin_unlock_irqrestore(flags); lc823450_epack(privep->epphy, 1); } @@ -738,7 +738,7 @@ static int lc823450_epstall(struct usbdev_ep_s *ep, bool resume) /* STALL or RESUME the endpoint */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(); usbtrace(resume ? TRACE_EPRESUME : TRACE_EPSTALL, privep->epphy); if (resume) @@ -752,7 +752,7 @@ static int lc823450_epstall(struct usbdev_ep_s *ep, bool resume) epcmd_write(privep->epphy, USB_EPCMD_STALL_SET | USB_EPCMD_TGL_SET); } - leave_critical_section(flags); + spin_unlock_irqrestore(flags); return OK; } @@ -761,11 +761,11 @@ void up_epignore_clear_stall(struct usbdev_ep_s *ep, bool ignore) { struct lc823450_ep_s *privep = (struct lc823450_ep_s *)ep; irqstate_t flags; - flags = enter_critical_section(); + flags = spin_lock_irqsave(); privep->ignore_clear_stall = ignore; - leave_critical_section(flags); + spin_unlock_irqrestore(flags); } #endif /* CONFIG_USBMSC_IGNORE_CLEAR_STALL */ @@ -922,7 +922,7 @@ static void usb_suspend_work_func(void *arg) } #endif - flags = enter_critical_section(); + flags = spin_lock_irqsave(); if (getreg32(USB_DEVS) & USB_DEVS_SUSPEND) { uinfo("USB BUS SUSPEND\n"); @@ -936,7 +936,7 @@ static void usb_suspend_work_func(void *arg) g_usbsuspend = 1; wake_unlock(&priv->wlock); } - leave_critical_section(flags); + spin_unlock_irqrestore(flags); } #endif @@ -1630,7 +1630,7 @@ int usbdev_unregister(struct usbdevclass_driver_s *driver) * canceled while the class driver is still bound. */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(); #ifdef CONFIG_WAKELOCK /* cancel USB suspend work */ @@ -1666,7 +1666,7 @@ int usbdev_unregister(struct usbdevclass_driver_s *driver) pm_unregister(&pm_cb); #endif /* CONFIG_PM */ - leave_critical_section(flags); + spin_unlock_irqrestore(flags); #ifdef CONFIG_LC823450_LSISTBY /* disable USB */ @@ -1915,7 +1915,7 @@ static void usbdev_pmnotify(struct pm_callback_s *cb, enum pm_state_e pmstate) { irqstate_t flags; - flags = enter_critical_section(); + flags = spin_lock_irqsave(); switch (pmstate) { @@ -1936,6 +1936,6 @@ static void usbdev_pmnotify(struct pm_callback_s *cb, enum pm_state_e pmstate) default: break; } - leave_critical_section(flags); + spin_unlock_irqrestore(flags); } #endif diff --git a/configs/lc823450-xgevk/rndis/defconfig b/configs/lc823450-xgevk/rndis/defconfig index 619cada77b7..f8d43f2e932 100644 --- a/configs/lc823450-xgevk/rndis/defconfig +++ b/configs/lc823450-xgevk/rndis/defconfig @@ -122,6 +122,7 @@ CONFIG_NSH_WGET_USERAGENT="NuttX/7.2x.x (; http://www.nuttx.org/)" CONFIG_NX_BLOCKING=y # CONFIG_NX_DISABLE_1BPP is not set CONFIG_NXFONT_MONO5X8=y +CONFIG_NXPLAYER_DEFAULT_MEDIADIR="/mnt/sd1" CONFIG_NX=y CONFIG_PIPES=y CONFIG_POSIX_SPAWN_PROXY_STACKSIZE=2048 @@ -154,11 +155,13 @@ CONFIG_SERIAL_TERMIOS=y CONFIG_SMP_NCPUS=2 CONFIG_SMP=y # CONFIG_SPI_EXCHANGE is not set +CONFIG_SPINLOCK_IRQ=y CONFIG_SPI=y CONFIG_START_DAY=3 CONFIG_START_MONTH=10 CONFIG_START_YEAR=2013 CONFIG_SYSTEM_I2CTOOL=y +CONFIG_SYSTEM_NXPLAYER=y CONFIG_SYSTEM_PING=y CONFIG_TASK_NAME_SIZE=24 CONFIG_UART0_RXBUFSIZE=512 diff --git a/configs/lc823450-xgevk/src/lc823450_bringup.c b/configs/lc823450-xgevk/src/lc823450_bringup.c index c21799e02ab..392b7143423 100644 --- a/configs/lc823450-xgevk/src/lc823450_bringup.c +++ b/configs/lc823450-xgevk/src/lc823450_bringup.c @@ -45,6 +45,10 @@ #include #include +#ifdef CONFIG_SMP +# include +#endif + #ifdef CONFIG_RNDIS # include #endif @@ -112,6 +116,16 @@ int lc823450_bringup(void) usbdev_rndis_initialize(mac); #endif +#if defined(CONFIG_SMP) && defined (CONFIG_RNDIS) + cpu_set_t cpuset; + CPU_ZERO(&cpuset); + CPU_SET(1, &cpuset); /* assigned to CPU1 */ + + /* NOTE: pid=4 is assumed to be lpwork */ + + sched_setaffinity(4, sizeof(cpu_set_t), &cpuset); +#endif + /* If we got here then perhaps not all initialization was successful, but * at least enough succeeded to bring-up NSH with perhaps reduced * capabilities. diff --git a/drivers/audio/wm8776.c b/drivers/audio/wm8776.c index 72750372ed7..c9a9ebebcc8 100644 --- a/drivers/audio/wm8776.c +++ b/drivers/audio/wm8776.c @@ -538,7 +538,7 @@ static void wm8776_senddone(FAR struct i2s_dev_s *i2s, * against that possibility. */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(); /* Add the completed buffer to the end of our doneq. We do not yet * decrement the reference count. @@ -555,7 +555,7 @@ static void wm8776_senddone(FAR struct i2s_dev_s *i2s, /* REVISIT: This can be overwritten */ priv->result = result; - leave_critical_section(flags); + spin_unlock_irqrestore(flags); /* Now send a message to the worker thread, informing it that there are * buffers in the done queue that need to be cleaned up. @@ -590,13 +590,13 @@ static void wm8776_returnbuffers(FAR struct wm8776_dev_s *priv) * use interrupt controls to protect against that possibility. */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(); while (dq_peek(&priv->doneq) != NULL) { /* Take the next buffer from the queue of completed transfers */ apb = (FAR struct ap_buffer_s *)dq_remfirst(&priv->doneq); - leave_critical_section(flags); + spin_unlock_irqrestore(flags); audinfo("Returning: apb=%p curbyte=%d nbytes=%d flags=%04x\n", apb, apb->curbyte, apb->nbytes, apb->flags); @@ -631,10 +631,10 @@ static void wm8776_returnbuffers(FAR struct wm8776_dev_s *priv) #else priv->dev.upper(priv->dev.priv, AUDIO_CALLBACK_DEQUEUE, apb, OK); #endif - flags = enter_critical_section(); + flags = spin_lock_irqsave(); } - leave_critical_section(flags); + spin_unlock_irqrestore(flags); } /**************************************************************************** @@ -682,9 +682,9 @@ static int wm8776_sendbuffer(FAR struct wm8776_dev_s *priv) * to avoid a possible race condition. */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(); priv->inflight++; - leave_critical_section(flags); + spin_unlock_irqrestore(flags); shift = (priv->bpsamp == 8) ? 14 - 3 : 14 - 4; shift -= (priv->nchannels > 1) ? 1 : 0; @@ -1153,6 +1153,7 @@ static void *wm8776_workerthread(pthread_addr_t pvarg) FAR struct ap_buffer_s *apb; int msglen; int prio; + struct mq_attr attr; audinfo("Entry\n"); @@ -1187,6 +1188,8 @@ static void *wm8776_workerthread(pthread_addr_t pvarg) wm8776_sendbuffer(priv); } +repeat: + /* Wait for messages from our message queue */ msglen = mq_receive(priv->mq, (FAR char *)&msg, sizeof(msg), &prio); @@ -1241,6 +1244,16 @@ static void *wm8776_workerthread(pthread_addr_t pvarg) auderr("ERROR: Ignoring message ID %d\n", msg.msgId); break; } + + (void)mq_getattr(priv->mq, &attr); + + /* If there is a message in the queue, process it */ + + if (0 < attr.mq_curmsgs) + { + goto repeat; + } + } /* Reset the WM8776 hardware */