* Re: [RFC,v3 7/9] media: platform: Add Mediatek ISP P1 device driver
From: Tomasz Figa @ 2019-08-06 9:47 UTC (permalink / raw)
To: Jungo Lin
Cc: devicetree, Sean Cheng (鄭昇弘),
Frederic Chen (陳俊元),
Rynn Wu (吳育恩), srv_heupstream, Rob Herring,
Ryan Yu (余孟修),
Frankie Chiu (邱文凱), Hans Verkuil, ddavenport,
Sj Huang, moderated list:ARM/Mediatek SoC support,
Laurent Pinchart, Matthias Brugger, Mauro Carvalho Chehab,
list@263.net:IOMMU DRIVERS <iommu@lists.linux-foundation.org>, Joerg Roedel <joro@8bytes.org>, ,
Linux Media Mailing List
In-Reply-To: <1564125828.1212.600.camel@mtksdccf07>
Hi Jungo,
On Fri, Jul 26, 2019 at 4:24 PM Jungo Lin <jungo.lin@mediatek.com> wrote:
>
> Hi, Tomasz:
>
> On Thu, 2019-07-25 at 18:23 +0900, Tomasz Figa wrote:
> > .Hi Jungo,
> >
> > On Sat, Jul 20, 2019 at 6:58 PM Jungo Lin <jungo.lin@mediatek.com> wrote:
> > >
> > > Hi, Tomasz:
> > >
> > > On Wed, 2019-07-10 at 18:56 +0900, Tomasz Figa wrote:
> > > > Hi Jungo,
> > > >
> > > > On Tue, Jun 11, 2019 at 11:53:42AM +0800, Jungo Lin wrote:
[snip]
> > > > > +
> > > > > + err_status = irq_status & INT_ST_MASK_CAM_ERR;
> > > > > +
> > > > > + /* Sof, done order check */
> > > > > + if ((irq_status & SOF_INT_ST) && (irq_status & HW_PASS1_DON_ST)) {
> > > > > + dev_dbg(dev, "sof_done block cnt:%d\n", isp_dev->sof_count);
> > > > > +
> > > > > + /* Notify IRQ event and enqueue frame */
> > > > > + irq_handle_notify_event(isp_dev, irq_status, dma_status, 0);
> > > > > + isp_dev->current_frame = hw_frame_num;
> > > >
> > > > What exactly is hw_frame_num? Shouldn't we assign it before notifying the
> > > > event?
> > > >
> > >
> > > This is a another spare register for frame sequence number usage.
> > > It comes from struct p1_frame_param:frame_seq_no which is sent by
> > > SCP_ISP_FRAME IPI command. We will rename this to dequeue_frame_seq_no.
> > > Is it a better understanding?
> >
> > I'm sorry, unfortunately it's still not clear to me. Is it the
> > sequence number of the frame that was just processed and returned to
> > the kernel or the next frame that is going to be processed from now
> > on?
> >
>
> It is the next frame that is going to be proceed.
> We simplify the implementation of isp_irq_cam function. The hw_frame_num
> is renamed to dequeue_frame_seq_no and saved this value from HW at
> SOF_INT_ST. Since it is obtained in SOF_INI_ST event, it means it is
> next frame to be processed. If there is SW_PASS1_DON_ST, it means this
> frame is processed done. We use this value to de-queue the frame request
> and return buffers to VB2.
>
> The normal IRQ sequence is SOF_INT_ST => SW_PASS1_DON_ST &
> HW_PASS1_DON_ST.
>
> a. SW_PASS_DON_ST is designed for DMAs done event.
> If there is no available DMA buffers en-queued into HW, there is no
> SW_PADD_DON_ST.
>
> b. HW_PASS_DON_ST is designed to trigger CQ buffer load procedure.
> It is paired with SOF IRQ event, even if there is no available DMA
> buffers.
>
> static void isp_irq_handle_sof(struct mtk_isp_p1_device *p1_dev,
> unsigned int dequeue_frame_seq_no)
> {
> dma_addr_t base_addr = p1_dev->composer_iova;
> int composed_frame_seq_no =
> atomic_read(&p1_dev->composed_frame_seq_no);
> unsigned int addr_offset;
>
> /* Send V4L2_EVENT_FRAME_SYNC event */
> mtk_cam_dev_event_frame_sync(&p1_dev->cam_dev, dequeue_frame_seq_no);
>
> p1_dev->sof_count += 1;
> /* Save dequeue frame information */
> p1_dev->dequeue_frame_seq_no = dequeue_frame_seq_no;
>
> /* Update CQ base address if needed */
> if (composed_frame_seq_no <= dequeue_frame_seq_no) {
> dev_dbg(p1_dev->dev,
> "SOF_INT_ST, no update, cq_num:%d, frame_seq:%d",
> composed_frame_seq_no, dequeue_frame_seq_no);
> return;
> }
> addr_offset = MTK_ISP_CQ_ADDRESS_OFFSET *
> (dequeue_frame_seq_no % MTK_ISP_CQ_BUFFER_COUNT);
> writel(base_addr + addr_offset, p1_dev->regs + REG_CQ_THR0_BASEADDR);
> dev_dbg(p1_dev->dev,
> "SOF_INT_ST, update next, cq_num:%d, frame_seq:%d cq_addr:0x%x",
> composed_frame_seq_no, dequeue_frame_seq_no, addr_offset);
> }
>
> void mtk_cam_dev_dequeue_req_frame(struct mtk_cam_dev *cam,
> unsigned int frame_seq_no)
> {
> struct mtk_cam_dev_request *req, *req_prev;
> unsigned long flags;
>
> spin_lock_irqsave(&cam->running_job_lock, flags);
> list_for_each_entry_safe(req, req_prev, &cam->running_job_list, list) {
> dev_dbg(cam->dev, "frame_seq:%d, de-queue frame_seq:%d\n",
> req->frame_params.frame_seq_no, frame_seq_no);
>
> /* Match by the en-queued request number */
> if (req->frame_params.frame_seq_no == frame_seq_no) {
> atomic_dec(&cam->running_job_count);
> /* Pass to user space */
> mtk_cam_dev_job_done(cam, req, VB2_BUF_STATE_DONE);
> list_del(&req->list);
> break;
> } else if (req->frame_params.frame_seq_no < frame_seq_no) {
> atomic_dec(&cam->running_job_count);
> /* Pass to user space for frame drop */
> mtk_cam_dev_job_done(cam, req, VB2_BUF_STATE_ERROR);
> dev_warn(cam->dev, "frame_seq:%d drop\n",
> req->frame_params.frame_seq_no);
> list_del(&req->list);
> } else {
> break;
> }
> }
> spin_unlock_irqrestore(&cam->running_job_lock, flags);
>
> static irqreturn_t isp_irq_cam(int irq, void *data)
> {
> struct mtk_isp_p1_device *p1_dev = (struct mtk_isp_p1_device *)data;
> struct device *dev = p1_dev->dev;
> unsigned int dequeue_frame_seq_no;
> unsigned int irq_status, err_status, dma_status;
> unsigned long flags;
>
> spin_lock_irqsave(&p1_dev->spinlock_irq, flags);
> irq_status = readl(p1_dev->regs + REG_CTL_RAW_INT_STAT);
> err_status = irq_status & INT_ST_MASK_CAM_ERR;
> dma_status = readl(p1_dev->regs + REG_CTL_RAW_INT2_STAT);
> dequeue_frame_seq_no = readl(p1_dev->regs + REG_FRAME_SEQ_NUM);
> spin_unlock_irqrestore(&p1_dev->spinlock_irq, flags);
>
> /*
> * In normal case, the next SOF ISR should come after HW PASS1 DONE
> ISR.
> * If these two ISRs come together, print warning msg to hint.
> */
> if ((irq_status & SOF_INT_ST) && (irq_status & HW_PASS1_DON_ST))
> dev_warn(dev, "sof_done block cnt:%d\n", p1_dev->sof_count);
>
> /* De-queue frame */
> if (irq_status & SW_PASS1_DON_ST) {
> mtk_cam_dev_dequeue_req_frame(&p1_dev->cam_dev,
> dequeue_frame_seq_no);
> mtk_cam_dev_req_try_queue(&p1_dev->cam_dev);
> }
>
> /* Save frame info. & update CQ address for frame HW en-queue */
> if (irq_status & SOF_INT_ST)
> isp_irq_handle_sof(p1_dev, dequeue_frame_seq_no);
>
> /* Check ISP error status */
> if (err_status) {
> dev_err(dev, "int_err:0x%x 0x%x\n", irq_status, err_status);
> /* Show DMA errors in detail */
> if (err_status & DMA_ERR_ST)
> isp_irq_handle_dma_err(p1_dev);
> }
>
> dev_dbg(dev, "SOF:%d irq:0x%x, dma:0x%x, frame_num:%d",
> p1_dev->sof_count, irq_status, dma_status,
> dequeue_frame_seq_no);
>
> return IRQ_HANDLED;
> }
I think I understand this now and the code above also looks good to
me. Thanks a lot!
>
> > >
> > > Below is our frame request handling in current design.
> > >
> > > 1. Buffer preparation
> > > - Combined image buffers (IMGO/RRZO) + meta input buffer (Tuining) +
> > > other meta histogram buffers (LCSO/LMVO) into one request.
> > > - Accumulated one unique frame sequence number to each request and send
> > > this request to the SCP composer to compose CQ (Command queue) buffer
> > > via SCP_ISP_FRAME IPI command.
> > > - CQ buffer is frame registers set. If ISP registers should be updated
> > > per frame, these registers are configured in the CQ buffer, such as
> > > frame sequence number, DMA addresses and tuning ISP registers.
> > > - One frame request will be composed into one CQ buffer.Once CQ buffer
> > > is composed done and kernel driver will receive ISP_CMD_FRAME_ACK with
> > > its corresponding frame sequence number. Based on this, kernel driver
> > > knows which request is ready to be en-queued and save this with
> > > p1_dev->isp_ctx.composed_frame_id.
> >
> > Hmm, why do we need to save this in p1_dev->isp_ctx? Wouldn't we
> > already have a linked lists of requests that are composed and ready to
> > be enqueued? Also, the request itself would contain its frame ID
> > inside the driver request struct, right?
> >
>
> Below is current implementation for frame request en-queued.
> Before en-queued into HW by CQ, the request should be composed by SCP
> composer.
>
> a. mtk_cam_dev_req_try_queue()
> - Insert the request into p1_dev->running_job_list
> b. mtk_isp_req_enqueue()
> - Assign new next frame ID to this request.
> - Sending to SCP by workqueue
> - This request is ready to compose
> c. isp_tx_frame_worker()
> - Send request to SCP with sync. mode. by SCP_IPI_ISP_FRAME command
> - SCP composer will compose the buffer CQ for this request frame based
> on struct mtk_p1_frame_param which includes frame ID.
> - If scp_ipi_send() is returned, it means the request is composed done.
> Or
> d. isp_composer_handler()
> - If we received the ISP_CMD_FRAME_ACK for SCP_IPI_ISP_FRAME, we save
> the frame ID in p1_dev->composed_frame_seq_no which is sent in step C.
> - The request is composed done here.
> e. isp_irq_handle_sof()
> - In SOF timing, we will check there is any available composed CQ
> buffers by comparing composed & current de-queued frame ID.
>
> For p1_dev->running_job_list, we can't guarantee the requests are
> composed until the end of step c. For step e, we need to know how many
> available composed requests are ready to en-queued.
>
> Do you suggest we add another new link-list to save these requests in
> step c or we could update p1_dev->composed_frame_seq_no in step c and
> remove the implementation in step d[1]?
Okay, thanks to your explanation above I think I understood how the
hardware flow behaves and so I think we can indeed keep the
composed_frame_seq counter. Thanks!
>
> [1]. isp_composer_handler() is mandatory callback function for SCP
> sending API with sync mode design.
>
> static void isp_composer_handler(void *data, unsigned int len, void
> *priv)
> {
> struct mtk_isp_p1_device *p1_dev = (struct mtk_isp_p1_device *)priv;
> struct mtk_isp_scp_p1_cmd *ipi_msg;
>
> ipi_msg = (struct mtk_isp_scp_p1_cmd *)data;
>
> if (ipi_msg->cmd_id != ISP_CMD_ACK)
> return;
>
> if (ipi_msg->ack_info.cmd_id == ISP_CMD_FRAME_ACK) {
> atomic_set(&p1_dev->composed_frame_seq_no,
> ipi_msg->ack_info.frame_seq_no);
> dev_dbg(p1_dev->dev, "ack frame_num:%d\n",
> p1_dev->composed_frame_seq_no);
> }
> }
>
> > > - The maximum number of CQ buffers in SCP is 3.
> > >
> > > 2. Buffer en-queue flow
> > > - In order to configure correct CQ buffer setting before next SQF event,
> > > it is depended on by MTK ISP P1 HW CQ mechanism.
> > > - The basic concept of CQ mechanism is loaded ISP CQ buffer settings
> > > when HW_PASS1_DON_ST is received which means DMA output is done.
> > > - Btw, the pre-condition of this, need to tell ISP HW which CQ buffer
> > > address is used. Otherwise, it will loaded one dummy CQ buffer to
> > > bypass.
> > > - So we will check available CQ buffers by comparing composed frame
> > > sequence number & dequeued frame sequence from ISP HW in SOF event.
> > > - If there are available CQ buffers, update the CQ base address to the
> > > next CQ buffer address based on current de-enqueue frame sequence
> > > number. So MTK ISP P1 HW will load this CQ buffer into HW when
> > > HW_PASS1_DON_ST is triggered which is before the next SOF.
> > > - So in next SOF event, ISP HW starts to output DMA buffers with this
> > > request until request is done.
> > > - But, for the first request, it is loaded into HW manually when
> > > streaming is on for better performance.
> > >
> > > 3. Buffer de-queue flow
> > > - We will use frame sequence number to decide which request is ready to
> > > de-queue.
> > > - We will save some important register setting from ISP HW when SOF is
> > > received. This is because the ISP HW starts to output the data with the
> > > corresponding settings, especially frame sequence number setting.
> >
> > Could you explain a bit more about these important register settings?
> > When does the hardware update the values in the register to new ones?
> > At SOF?
> >
>
> Sorry about my words.
> In the current implementation, we just save frame ID.
>
Ah, okay, makes sense. No worries. :)
>
> > > - When receiving SW_PASS1_DON_ST IRQ event, it means the DMA output is
> > > done. So we could call isp_deque_request_frame with frame sequence
> > > number to de-queue frame to VB2
> >
> > What's the difference between HW_PASS1_DON_ST and SW_PASS1_DON_ST?
> >
>
> This is explained above.
>
> > > - For AAO/AFO buffers, it has similar design concept. Sometimes, if only
> > > AAO/AFO non-request buffers are en-queued without request buffers at the
> > > same time, there will be no SW P1 done event for AAO/AFO DMA done.
> > > Needs to depend on other IRQ events, such as AAO/AFO_DONE_EVENT.
> >
> > Do we have a case like this? Wouldn't we normally always want to
> > bundle AAO/AFO buffers with frame buffers?
> >
>
> For upstream driver, we will remove non-request design.
>
I think we also talked about a thing related to this in the thread for
another patch from this series. Basically on Chrome OS we want to use
the upstream driver, so corresponding userspace changes might be
needed as well.
> > > - Due to CQ buffer number limitation, if we receive SW_PASS1_DONT_ST,
> > > we may try to send another request to SCP for composing.
> >
> > Okay, so basically in SW_PASS1_DONT_ST the CQ completed reading the CQ
> > buffers, right?
> >
>
> We expected the the life cycle of CQ buffer is same as frame request.
> So SW_PASS1_DON_ST is good timing to re-queue the next request to
> compose.
> For the CQ operations, we will explain later.
>
> > >
> > > Hopefully, my explanation is helpful for better understanding our
> > > implementation. If you still have any questions, please let me know.
> > >
> >
> > Yes, it's more clear now, thanks. Still some more comments above, though.
> >
> > > > > + isp_dev->meta0_vb2_index = meta0_vb2_index;
> > > > > + isp_dev->meta1_vb2_index = meta1_vb2_index;
> > > > > + } else {
> > > > > + if (irq_status & SOF_INT_ST) {
> > > > > + isp_dev->current_frame = hw_frame_num;
> > > > > + isp_dev->meta0_vb2_index = meta0_vb2_index;
> > > > > + isp_dev->meta1_vb2_index = meta1_vb2_index;
> > > > > + }
> > > > > + irq_handle_notify_event(isp_dev, irq_status, dma_status, 1);
> > > > > + }
> > > >
> > > > The if and else blocks do almost the same things just in different order. Is
> > > > it really expected?
> > > >
> > >
> > > If we receive HW_PASS1_DON_ST & SOF_INT_ST IRQ events at the same time,
> > > the correct sequence should be handle HW_PASS1_DON_ST firstly to check
> > > any de-queued frame and update the next frame setting later.
> > > Normally, this is a corner case or system performance issue.
> >
> > So it sounds like HW_PASS1_DON_ST means that all data from current
> > frame has been written, right? If I understand your explanation above
> > correctly, that would mean following handling of each interrupt:
> >
> > HW_PASS1_DON_ST:
> > - CQ executes with next CQ buffer to prepare for next frame. <- how
> > is this handled? does the CQ hardware automatically receive this event
> > from the ISP hadware?
> > - return VB2 buffers,
> > - complete requests.
> >
> > SOF_INT_ST:
> > - send VSYNC event to userspace,
> > - program next CQ buffer to CQ,
> >
> > SW_PASS1_DON_ST:
> > - reclaim CQ buffer and enqueue next frame to composing if available
> >
>
> Sorry for our implementation of HW_PASS1_DON_ST.
> It is confusing.
> Below is the revised version based on your conclusion.
> So in our new implemmenation, we just handle SOF_INT_ST &
> SW_PASS1_DON_ST events. We just add one warning message for
> HW_PASS1_DON_ST
>
> HW_PASS1_DON_ST:
> - CQ executes with next CQ buffer to prepare for next frame.
>
> SOF_INT_ST:
> - send VSYNC event to userspace,
> - program next CQ buffer to CQ,
>
> SW_PASS1_DON_ST:
> - reclaim CQ buffer and enqueue next frame to composing if available
> - return VB2 buffers,
> - complete requests.
>
> For CQ HW operations, it is listed below:
>
> a. The CQ buffer has two kinds of information
> - Which ISP registers needs to be updated.
> - Where the corresponding ISP register data to be read.
> b. The CQ buffer loading procedure is triggered by HW_PASS1_DONT_ST IRQ
> event periodically.
> - Normally, if the ISP HW receives the completed frame and it will
> trigger W_PASS1_DONT_ST IRQ and perform CQ buffer loading immediately.
> - So the CQ buffer loading is performed by ISP HW automatically.
> c. The ISP HW will read CQ base address register(REG_CQ_THR0_BASEADDR)
> to decide which CQ buffer is loaded.
> - So we configure the next CQ base address in SOF.
> d. For CQ buffer loading, CQ will read the ISP registers from CQ buffer
> and update the ISP register values into HW.
> - SCP composer will compose one dummy CQ buffer and assign it to
> REG_CQ_THR0_BASEADDR of each CQ buffer.
> - Dummy CQ buffer has no updated ISP registers comparing with other
> CQ buffers.
> - With this design, if there is no updated new CQ buffer by driver
> which may be caused no en-queue frames from user space. The CQ HW will
> load dummy CQ buffer and do nothing.
Does the set of registers programmed by CQ include destination buffer
addresses to? If yes, we would end up overwriting previous frames if
no new buffers are provided.
> f. The CQ buffer loading is guaranteed by HW to finish before the next
> SOF.
>
Okay, thanks a lot for the explanation. This is much more clear now.
[snip]
> > > > > +static const struct dev_pm_ops mtk_isp_pm_ops = {
> > > > > + SET_SYSTEM_SLEEP_PM_OPS(mtk_isp_suspend, mtk_isp_resume)
> > > > > + SET_RUNTIME_PM_OPS(mtk_isp_suspend, mtk_isp_resume, NULL)
> > > >
> > > > For V4L2 drivers system and runtime PM ops would normally be completely
> > > > different. Runtime PM ops would be called when the hardware is idle already
> > > > or is about to become active. System PM ops would be called at system power
> > > > state change and the hardware might be both idle or active. Please also see
> > > > my comments to mtk_isp_suspend() and mtk_isp_resume() above.
> > > >
> > >
> > > Here is the new implementation. It should be clear to show the
> > > difference between system and runtime PM ops.
> > >
> > > static const struct dev_pm_ops mtk_isp_pm_ops = {
> > > SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
> > > pm_runtime_force_resume)
> > > SET_RUNTIME_PM_OPS(mtk_isp_runtime_suspend, mtk_isp_runtime_resume,
> > > NULL)
> > > };
> >
> > That's still not correct. In runtime suspend/resume ops we already are
> > not streaming anymore, because we call pm_runtime_get/put_*() when
> > starting and stopping streaming. In system suspend/resume ops we might
> > be streaming and that's when we need to stop the hardware and wait for
> > it to finish. Please implement these ops separately.
> >
> > Best regards,
> > Tomasz
>
>
> Ok, got your point.
> Below is the new implementation for your review.
>
> static int mtk_isp_pm_suspend(struct device *dev)
> {
> struct mtk_isp_p1_device *p1_dev = dev_get_drvdata(dev);
> u32 val;
> int ret;
>
> dev_dbg(dev, "- %s\n", __func__);
>
> /* Check ISP is streaming or not */
> if (!p1_dev->cam_dev.streaming)
> goto done;
We would normally check here for pm_runtime_suspended(). Although they
both should be equivalent. Still, there is no need to call
pm_runtime_force_suspend() if the latter is true, so we could just
return 0 instantly.
>
> /* Disable ISP's view finder and wait for TG idle */
> dev_dbg(dev, "Cam suspend, disable VF\n");
> val = readl(p1_dev->regs + REG_TG_VF_CON);
> writel(val & (~TG_VF_CON_VFDATA_EN), p1_dev->regs + REG_TG_VF_CON);
> ret = readl_poll_timeout_atomic(p1_dev->regs + REG_TG_INTER_ST, val,
> (val & TG_CS_MASK) == TG_IDLE_ST,
> USEC_PER_MSEC, MTK_ISP_STOP_HW_TIMEOUT);
> if (ret)
> dev_warn(dev, "can't stop HW:%d:0x%x\n", ret, val);
>
> /* Disable CMOS */
> val = readl(p1_dev->regs + REG_TG_SEN_MODE);
> writel(val & (~TG_SEN_MODE_CMOS_EN), p1_dev->regs + REG_TG_SEN_MODE);
>
> done:
> /* Force ISP HW to idle */
> ret = pm_runtime_force_suspend(dev);
> if (ret)
> return ret;
>
> return 0;
> }
>
> static int mtk_isp_pm_resume(struct device *dev)
> {
> struct mtk_isp_p1_device *p1_dev = dev_get_drvdata(dev);
> u32 val;
> int ret;
>
> dev_dbg(dev, "- %s\n", __func__);
>
> /* Force ISP HW to resume if needed */
> ret = pm_runtime_force_resume(dev);
> if (ret)
> return ret;
We should do this conditionally based on what pm_runtime_suspended()
returns. If it's non-zero then we can just return 0 instantly.
>
> if (!p1_dev->cam_dev.streaming)
> return 0;
>
> /* Enable CMOS */
> dev_dbg(dev, "Cam resume, enable CMOS/VF\n");
> val = readl(p1_dev->regs + REG_TG_SEN_MODE);
> writel(val | TG_SEN_MODE_CMOS_EN, p1_dev->regs + REG_TG_SEN_MODE);
>
> /* Enable VF */
> val = readl(p1_dev->regs + REG_TG_VF_CON);
> writel(val | TG_VF_CON_VFDATA_EN, p1_dev->regs + REG_TG_VF_CON);
>
> return 0;
> }
>
> static int mtk_isp_runtime_suspend(struct device *dev)
> {
> struct mtk_isp_p1_device *p1_dev = dev_get_drvdata(dev);
>
> dev_dbg(dev, "- %s\n", __func__);
>
> if (pm_runtime_suspended(dev))
> return 0;
Sorry, I guess I wasn't clear in my reply. It's not possible to get
this callback called if the device is already runtime suspended.
>
> dev_dbg(dev, "%s:disable clock\n", __func__);
> clk_bulk_disable_unprepare(p1_dev->num_clks, p1_dev->clks);
>
> return 0;
> }
>
> static int mtk_isp_runtime_resume(struct device *dev)
> {
> struct mtk_isp_p1_device *p1_dev = dev_get_drvdata(dev);
> int ret;
>
> dev_dbg(dev, "- %s\n", __func__);
>
> if (pm_runtime_suspended(dev))
> return 0;
In this case the above call would always return non-zero, so the
behavior wouldn't be very good.
Best regards,
Tomasz
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH] cpufreq: mediatek-cpufreq: Add compatible for MT8516
From: Fabien Parent @ 2019-08-06 9:50 UTC (permalink / raw)
To: rjw, viresh.kumar, matthias.bgg
Cc: Fabien Parent, linux-mediatek, linux-kernel, linux-arm-kernel,
linux-pm
Add the compatible for MT8516 in order to take advantage of the
MediaTek CPUFreq driver for Mediatek's MT8516 SoC.
Signed-off-by: Fabien Parent <fparent@baylibre.com>
---
drivers/cpufreq/mediatek-cpufreq.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/cpufreq/mediatek-cpufreq.c b/drivers/cpufreq/mediatek-cpufreq.c
index f14f3a85f2f7..10bc06f5dd45 100644
--- a/drivers/cpufreq/mediatek-cpufreq.c
+++ b/drivers/cpufreq/mediatek-cpufreq.c
@@ -535,6 +535,7 @@ static const struct of_device_id mtk_cpufreq_machines[] __initconst = {
{ .compatible = "mediatek,mt817x", },
{ .compatible = "mediatek,mt8173", },
{ .compatible = "mediatek,mt8176", },
+ { .compatible = "mediatek,mt8516", },
{ }
};
--
2.23.0.rc1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* Re: [PATCH 2/2] nvmem: imx-ocotp: Support multiple word writes
From: Srinivas Kandagatla @ 2019-08-06 9:57 UTC (permalink / raw)
To: Trent Piepho, linux-arm-kernel@lists.infradead.org
Cc: Fabio Estevam, Sascha Hauer, Shawn Guo, NXP Linux Team
In-Reply-To: <20190709183016.4789-2-tpiepho@impinj.com>
On 09/07/2019 19:30, Trent Piepho wrote:
> All the other nvmem drivers here support multiple words being read, and
> for writable memory, written in one call. This driver appears to be the
> only one with a single word write restriction. It makes the driver fail
> with generic userspace nvmem tools.
>
> It's easy to support multiple words to write so do that.
>
> The nvmem core verifies the write length against the word size, so that
> can be removed from the driver. But offset still needs to be checked.
>
> Also simplify the bank write code for imx7 to avoid a lot of
> duplication.
>
> Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> Cc: Shawn Guo <shawnguo@kernel.org>
> Cc: Sascha Hauer <s.hauer@pengutronix.de>
> Cc: Fabio Estevam <festevam@gmail.com>
> Signed-off-by: Trent Piepho <tpiepho@impinj.com>
Any Acks or Tested-by before I can push this would be really appreciated.
--srini
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH v2 0/3] arm/arm64: Add support for function error injection
From: Leo Yan @ 2019-08-06 10:00 UTC (permalink / raw)
To: Russell King, Oleg Nesterov, Catalin Marinas, Will Deacon,
Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, H. Peter Anvin,
x86, Arnd Bergmann, Alexei Starovoitov, Daniel Borkmann,
Martin KaFai Lau, Song Liu, Yonghong Song, Naveen N. Rao,
linux-arm-kernel, linux-kernel, linuxppc-dev, linux-arch, netdev,
bpf, clang-built-linux, Masami Hiramatsu
Cc: Leo Yan
This small patch set is to add support for function error injection;
this can be used to eanble more advanced debugging feature, e.g.
CONFIG_BPF_KPROBE_OVERRIDE.
The patch 01/03 is to consolidate the function definition which can be
suared cross architectures, patches 02,03/03 are used for enabling
function error injection on arm64 and arm architecture respectively.
I tested on arm64 platform Juno-r2 and one of my laptop with x86
architecture with below steps; I don't test for Arm architecture so
only pass compilation.
- Enable kernel configuration:
CONFIG_BPF_KPROBE_OVERRIDE
CONFIG_BTRFS_FS
CONFIG_BPF_EVENTS=y
CONFIG_KPROBES=y
CONFIG_KPROBE_EVENTS=y
CONFIG_BPF_KPROBE_OVERRIDE=y
- Build samples/bpf on with Debian rootFS:
# cd $kernel
# make headers_install
# make samples/bpf/ LLC=llc-7 CLANG=clang-7
- Run the sample tracex7:
# dd if=/dev/zero of=testfile.img bs=1M seek=1000 count=1
# DEVICE=$(losetup --show -f testfile.img)
# mkfs.btrfs -f $DEVICE
# ./tracex7 testfile.img
[ 1975.211781] BTRFS error (device (efault)): open_ctree failed
mount: /mnt/linux-kernel/linux-cs-dev/samples/bpf/tmpmnt: mount(2) system call failed: Cannot allocate memory.
Changes from v1:
* Consolidated the function definition into asm-generic header (Will);
* Used APIs to access pt_regs elements (Will);
* Fixed typos in the comments (Will).
Leo Yan (3):
error-injection: Consolidate override function definition
arm64: Add support for function error injection
arm: Add support for function error injection
arch/arm/Kconfig | 1 +
arch/arm/include/asm/ptrace.h | 5 +++++
arch/arm/lib/Makefile | 2 ++
arch/arm/lib/error-inject.c | 19 +++++++++++++++++++
arch/arm64/Kconfig | 1 +
arch/arm64/include/asm/ptrace.h | 5 +++++
arch/arm64/lib/Makefile | 2 ++
arch/arm64/lib/error-inject.c | 18 ++++++++++++++++++
arch/powerpc/include/asm/error-injection.h | 13 -------------
arch/x86/include/asm/error-injection.h | 13 -------------
include/asm-generic/error-injection.h | 6 ++++++
include/linux/error-injection.h | 6 +++---
12 files changed, 62 insertions(+), 29 deletions(-)
create mode 100644 arch/arm/lib/error-inject.c
create mode 100644 arch/arm64/lib/error-inject.c
delete mode 100644 arch/powerpc/include/asm/error-injection.h
delete mode 100644 arch/x86/include/asm/error-injection.h
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH v2 1/3] error-injection: Consolidate override function definition
From: Leo Yan @ 2019-08-06 10:00 UTC (permalink / raw)
To: Russell King, Oleg Nesterov, Catalin Marinas, Will Deacon,
Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, H. Peter Anvin,
x86, Arnd Bergmann, Alexei Starovoitov, Daniel Borkmann,
Martin KaFai Lau, Song Liu, Yonghong Song, Naveen N. Rao,
linux-arm-kernel, linux-kernel, linuxppc-dev, linux-arch, netdev,
bpf, clang-built-linux, Masami Hiramatsu
Cc: Leo Yan
In-Reply-To: <20190806100015.11256-1-leo.yan@linaro.org>
The function override_function_with_return() is defined separately for
each architecture and every architecture's definition is almost same
with each other. E.g. x86 and powerpc both define function in its own
asm/error-injection.h header and override_function_with_return() has
the same definition, the only difference is that x86 defines an extra
function just_return_func() but it is specific for x86 and is only used
by x86's override_function_with_return(), so don't need to export this
function.
This patch consolidates override_function_with_return() definition into
asm-generic/error-injection.h header, thus all architectures can use the
common definition. As result, the architecture specific headers are
removed; the include/linux/error-injection.h header also changes to
include asm-generic/error-injection.h header rather than architecture
header, furthermore, it includes linux/compiler.h for successful
compilation.
Signed-off-by: Leo Yan <leo.yan@linaro.org>
---
arch/powerpc/include/asm/error-injection.h | 13 -------------
arch/x86/include/asm/error-injection.h | 13 -------------
include/asm-generic/error-injection.h | 6 ++++++
include/linux/error-injection.h | 6 +++---
4 files changed, 9 insertions(+), 29 deletions(-)
delete mode 100644 arch/powerpc/include/asm/error-injection.h
delete mode 100644 arch/x86/include/asm/error-injection.h
diff --git a/arch/powerpc/include/asm/error-injection.h b/arch/powerpc/include/asm/error-injection.h
deleted file mode 100644
index 62fd24739852..000000000000
--- a/arch/powerpc/include/asm/error-injection.h
+++ /dev/null
@@ -1,13 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-
-#ifndef _ASM_ERROR_INJECTION_H
-#define _ASM_ERROR_INJECTION_H
-
-#include <linux/compiler.h>
-#include <linux/linkage.h>
-#include <asm/ptrace.h>
-#include <asm-generic/error-injection.h>
-
-void override_function_with_return(struct pt_regs *regs);
-
-#endif /* _ASM_ERROR_INJECTION_H */
diff --git a/arch/x86/include/asm/error-injection.h b/arch/x86/include/asm/error-injection.h
deleted file mode 100644
index 47b7a1296245..000000000000
--- a/arch/x86/include/asm/error-injection.h
+++ /dev/null
@@ -1,13 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _ASM_ERROR_INJECTION_H
-#define _ASM_ERROR_INJECTION_H
-
-#include <linux/compiler.h>
-#include <linux/linkage.h>
-#include <asm/ptrace.h>
-#include <asm-generic/error-injection.h>
-
-asmlinkage void just_return_func(void);
-void override_function_with_return(struct pt_regs *regs);
-
-#endif /* _ASM_ERROR_INJECTION_H */
diff --git a/include/asm-generic/error-injection.h b/include/asm-generic/error-injection.h
index 95a159a4137f..80ca61058dd2 100644
--- a/include/asm-generic/error-injection.h
+++ b/include/asm-generic/error-injection.h
@@ -16,6 +16,8 @@ struct error_injection_entry {
int etype;
};
+struct pt_regs;
+
#ifdef CONFIG_FUNCTION_ERROR_INJECTION
/*
* Whitelist ganerating macro. Specify functions which can be
@@ -28,8 +30,12 @@ static struct error_injection_entry __used \
.addr = (unsigned long)fname, \
.etype = EI_ETYPE_##_etype, \
};
+
+void override_function_with_return(struct pt_regs *regs);
#else
#define ALLOW_ERROR_INJECTION(fname, _etype)
+
+static inline void override_function_with_return(struct pt_regs *regs) { }
#endif
#endif
diff --git a/include/linux/error-injection.h b/include/linux/error-injection.h
index 280c61ecbf20..635a95caf29f 100644
--- a/include/linux/error-injection.h
+++ b/include/linux/error-injection.h
@@ -2,16 +2,16 @@
#ifndef _LINUX_ERROR_INJECTION_H
#define _LINUX_ERROR_INJECTION_H
-#ifdef CONFIG_FUNCTION_ERROR_INJECTION
+#include <linux/compiler.h>
+#include <asm-generic/error-injection.h>
-#include <asm/error-injection.h>
+#ifdef CONFIG_FUNCTION_ERROR_INJECTION
extern bool within_error_injection_list(unsigned long addr);
extern int get_injectable_error_type(unsigned long addr);
#else /* !CONFIG_FUNCTION_ERROR_INJECTION */
-#include <asm-generic/error-injection.h>
static inline bool within_error_injection_list(unsigned long addr)
{
return false;
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 2/3] arm64: Add support for function error injection
From: Leo Yan @ 2019-08-06 10:00 UTC (permalink / raw)
To: Russell King, Oleg Nesterov, Catalin Marinas, Will Deacon,
Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, H. Peter Anvin,
x86, Arnd Bergmann, Alexei Starovoitov, Daniel Borkmann,
Martin KaFai Lau, Song Liu, Yonghong Song, Naveen N. Rao,
linux-arm-kernel, linux-kernel, linuxppc-dev, linux-arch, netdev,
bpf, clang-built-linux, Masami Hiramatsu
Cc: Leo Yan
In-Reply-To: <20190806100015.11256-1-leo.yan@linaro.org>
Inspired by the commit 7cd01b08d35f ("powerpc: Add support for function
error injection"), this patch supports function error injection for
Arm64.
This patch mainly support two functions: one is regs_set_return_value()
which is used to overwrite the return value; the another function is
override_function_with_return() which is to override the probed
function returning and jump to its caller.
Signed-off-by: Leo Yan <leo.yan@linaro.org>
---
arch/arm64/Kconfig | 1 +
arch/arm64/include/asm/ptrace.h | 5 +++++
arch/arm64/lib/Makefile | 2 ++
arch/arm64/lib/error-inject.c | 18 ++++++++++++++++++
4 files changed, 26 insertions(+)
create mode 100644 arch/arm64/lib/error-inject.c
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 3adcec05b1f6..b15803afb2a0 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -148,6 +148,7 @@ config ARM64
select HAVE_FAST_GUP
select HAVE_FTRACE_MCOUNT_RECORD
select HAVE_FUNCTION_TRACER
+ select HAVE_FUNCTION_ERROR_INJECTION
select HAVE_FUNCTION_GRAPH_TRACER
select HAVE_GCC_PLUGINS
select HAVE_HW_BREAKPOINT if PERF_EVENTS
diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h
index b1dd039023ef..891b9995cb4b 100644
--- a/arch/arm64/include/asm/ptrace.h
+++ b/arch/arm64/include/asm/ptrace.h
@@ -301,6 +301,11 @@ static inline unsigned long regs_return_value(struct pt_regs *regs)
return regs->regs[0];
}
+static inline void regs_set_return_value(struct pt_regs *regs, unsigned long rc)
+{
+ regs->regs[0] = rc;
+}
+
/**
* regs_get_kernel_argument() - get Nth function argument in kernel
* @regs: pt_regs of that context
diff --git a/arch/arm64/lib/Makefile b/arch/arm64/lib/Makefile
index 33c2a4abda04..f182ccb0438e 100644
--- a/arch/arm64/lib/Makefile
+++ b/arch/arm64/lib/Makefile
@@ -33,3 +33,5 @@ UBSAN_SANITIZE_atomic_ll_sc.o := n
lib-$(CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE) += uaccess_flushcache.o
obj-$(CONFIG_CRC32) += crc32.o
+
+obj-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o
diff --git a/arch/arm64/lib/error-inject.c b/arch/arm64/lib/error-inject.c
new file mode 100644
index 000000000000..ed15021da3ed
--- /dev/null
+++ b/arch/arm64/lib/error-inject.c
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/error-injection.h>
+#include <linux/kprobes.h>
+
+void override_function_with_return(struct pt_regs *regs)
+{
+ /*
+ * 'regs' represents the state on entry of a predefined function in
+ * the kernel/module and which is captured on a kprobe.
+ *
+ * When kprobe returns back from exception it will override the end
+ * of probed function and directly return to the predefined
+ * function's caller.
+ */
+ instruction_pointer_set(regs, procedure_link_pointer(regs));
+}
+NOKPROBE_SYMBOL(override_function_with_return);
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 3/3] arm: Add support for function error injection
From: Leo Yan @ 2019-08-06 10:00 UTC (permalink / raw)
To: Russell King, Oleg Nesterov, Catalin Marinas, Will Deacon,
Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, H. Peter Anvin,
x86, Arnd Bergmann, Alexei Starovoitov, Daniel Borkmann,
Martin KaFai Lau, Song Liu, Yonghong Song, Naveen N. Rao,
linux-arm-kernel, linux-kernel, linuxppc-dev, linux-arch, netdev,
bpf, clang-built-linux, Masami Hiramatsu
Cc: Leo Yan
In-Reply-To: <20190806100015.11256-1-leo.yan@linaro.org>
This patch implements arm specific functions regs_set_return_value() and
override_function_with_return() to support function error injection.
In the exception flow, it updates pt_regs::ARM_pc with pt_regs::ARM_lr
so can override the probed function return.
Signed-off-by: Leo Yan <leo.yan@linaro.org>
---
arch/arm/Kconfig | 1 +
arch/arm/include/asm/ptrace.h | 5 +++++
arch/arm/lib/Makefile | 2 ++
arch/arm/lib/error-inject.c | 19 +++++++++++++++++++
4 files changed, 27 insertions(+)
create mode 100644 arch/arm/lib/error-inject.c
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 33b00579beff..2d3d44a037f6 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -77,6 +77,7 @@ config ARM
select HAVE_EXIT_THREAD
select HAVE_FAST_GUP if ARM_LPAE
select HAVE_FTRACE_MCOUNT_RECORD if !XIP_KERNEL
+ select HAVE_FUNCTION_ERROR_INJECTION if !THUMB2_KERNEL
select HAVE_FUNCTION_GRAPH_TRACER if !THUMB2_KERNEL && !CC_IS_CLANG
select HAVE_FUNCTION_TRACER if !XIP_KERNEL
select HAVE_GCC_PLUGINS
diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h
index 91d6b7856be4..3b41f37b361a 100644
--- a/arch/arm/include/asm/ptrace.h
+++ b/arch/arm/include/asm/ptrace.h
@@ -89,6 +89,11 @@ static inline long regs_return_value(struct pt_regs *regs)
return regs->ARM_r0;
}
+static inline void regs_set_return_value(struct pt_regs *regs, unsigned long rc)
+{
+ regs->ARM_r0 = rc;
+}
+
#define instruction_pointer(regs) (regs)->ARM_pc
#ifdef CONFIG_THUMB2_KERNEL
diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile
index b25c54585048..8f56484a7156 100644
--- a/arch/arm/lib/Makefile
+++ b/arch/arm/lib/Makefile
@@ -42,3 +42,5 @@ ifeq ($(CONFIG_KERNEL_MODE_NEON),y)
CFLAGS_xor-neon.o += $(NEON_FLAGS)
obj-$(CONFIG_XOR_BLOCKS) += xor-neon.o
endif
+
+obj-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o
diff --git a/arch/arm/lib/error-inject.c b/arch/arm/lib/error-inject.c
new file mode 100644
index 000000000000..2d696dc94893
--- /dev/null
+++ b/arch/arm/lib/error-inject.c
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/error-injection.h>
+#include <linux/kprobes.h>
+
+void override_function_with_return(struct pt_regs *regs)
+{
+ /*
+ * 'regs' represents the state on entry of a predefined function in
+ * the kernel/module and which is captured on a kprobe.
+ *
+ * 'regs->ARM_lr' contains the the link register for the probed
+ * function, when kprobe returns back from exception it will override
+ * the end of probed function and directly return to the predefined
+ * function's caller.
+ */
+ instruction_pointer_set(regs, regs->ARM_lr);
+}
+NOKPROBE_SYMBOL(override_function_with_return);
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 03/12] dt-bindings: interrupt-controller: arm, gic-v3: Describe ESPI range support
From: Marc Zyngier @ 2019-08-06 10:01 UTC (permalink / raw)
To: Thomas Gleixner, Jason Cooper, Julien Thierry, Rob Herring
Cc: Lokesh Vutla, John Garry, linux-kernel, Shameerali Kolothum Thodi,
linux-arm-kernel
In-Reply-To: <20190806100121.240767-1-maz@kernel.org>
GICv3.1 introduces support for new interrupt ranges, one of them being
the Extended SPI range (ESPI). The DT binding is extended to deal with
it as a new interrupt class.
Reviewed-by: Lokesh Vutla <lokeshvutla@ti.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
.../devicetree/bindings/interrupt-controller/arm,gic-v3.yaml | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml b/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml
index c34df35a25fc..98a3ecda8e07 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml
+++ b/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml
@@ -44,11 +44,12 @@ properties:
be at least 4.
The 1st cell is the interrupt type; 0 for SPI interrupts, 1 for PPI
- interrupts. Other values are reserved for future use.
+ interrupts, 2 for interrupts in the Extended SPI range. Other values
+ are reserved for future use.
The 2nd cell contains the interrupt number for the interrupt type.
SPI interrupts are in the range [0-987]. PPI interrupts are in the
- range [0-15].
+ range [0-15]. Extented SPI interrupts are in the range [0-1023].
The 3rd cell is the flags, encoded as follows:
bits[3:0] trigger type and level flags.
--
2.20.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 02/12] irqchip/gic-v3: Add INTID range and convertion primitives
From: Marc Zyngier @ 2019-08-06 10:01 UTC (permalink / raw)
To: Thomas Gleixner, Jason Cooper, Julien Thierry, Rob Herring
Cc: Lokesh Vutla, John Garry, linux-kernel, Shameerali Kolothum Thodi,
linux-arm-kernel
In-Reply-To: <20190806100121.240767-1-maz@kernel.org>
In the beginning, life was simple. The GIC driver mostly cared about
PPIs, SPIs and LPIs, all with nicely layed out ranges.
We're about to change all that, with new ranges such as EPPI and ESPI
interleaved in the middle of the no-irq-land between the "special IDs"
and the LPI range. Boo.
In order to make our life less hellish, let's introduce a set of primitives
that will allow ranges to be identified easily and offsets to be remapped.
So far, there is no functionnal change.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
drivers/irqchip/irq-gic-v3.c | 112 ++++++++++++++++++++++++++---------
1 file changed, 83 insertions(+), 29 deletions(-)
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index b250e69908f8..db3bdedd7241 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -97,6 +97,32 @@ static DEFINE_PER_CPU(bool, has_rss);
/* Our default, arbitrary priority value. Linux only uses one anyway. */
#define DEFAULT_PMR_VALUE 0xf0
+enum gic_intid_range {
+ PPI_RANGE,
+ SPI_RANGE,
+ LPI_RANGE,
+ __INVALID_RANGE__
+};
+
+static enum gic_intid_range __get_intid_range(irq_hw_number_t hwirq)
+{
+ switch (hwirq) {
+ case 16 ... 31:
+ return PPI_RANGE;
+ case 32 ... 1019:
+ return SPI_RANGE;
+ case 8192 ... GENMASK(23, 0):
+ return LPI_RANGE;
+ default:
+ return __INVALID_RANGE__;
+ }
+}
+
+static enum gic_intid_range get_intid_range(struct irq_data *d)
+{
+ return __get_intid_range(d->hwirq);
+}
+
static inline unsigned int gic_irq(struct irq_data *d)
{
return d->hwirq;
@@ -104,18 +130,23 @@ static inline unsigned int gic_irq(struct irq_data *d)
static inline int gic_irq_in_rdist(struct irq_data *d)
{
- return gic_irq(d) < 32;
+ return get_intid_range(d) == PPI_RANGE;
}
static inline void __iomem *gic_dist_base(struct irq_data *d)
{
- if (gic_irq_in_rdist(d)) /* SGI+PPI -> SGI_base for this CPU */
+ switch (get_intid_range(d)) {
+ case PPI_RANGE:
+ /* SGI+PPI -> SGI_base for this CPU */
return gic_data_rdist_sgi_base();
- if (d->hwirq <= 1023) /* SPI -> dist_base */
+ case SPI_RANGE:
+ /* SPI -> dist_base */
return gic_data.dist_base;
- return NULL;
+ default:
+ return NULL;
+ }
}
static void gic_do_wait_for_rwp(void __iomem *base)
@@ -196,24 +227,46 @@ static void gic_enable_redist(bool enable)
/*
* Routines to disable, enable, EOI and route interrupts
*/
+static u32 convert_offset_index(struct irq_data *d, u32 offset, u32 *index)
+{
+ switch (get_intid_range(d)) {
+ case PPI_RANGE:
+ case SPI_RANGE:
+ *index = d->hwirq;
+ return offset;
+ default:
+ break;
+ }
+
+ WARN_ON(1);
+ *index = d->hwirq;
+ return offset;
+}
+
static int gic_peek_irq(struct irq_data *d, u32 offset)
{
- u32 mask = 1 << (gic_irq(d) % 32);
void __iomem *base;
+ u32 index, mask;
+
+ offset = convert_offset_index(d, offset, &index);
+ mask = 1 << (index % 32);
if (gic_irq_in_rdist(d))
base = gic_data_rdist_sgi_base();
else
base = gic_data.dist_base;
- return !!(readl_relaxed(base + offset + (gic_irq(d) / 32) * 4) & mask);
+ return !!(readl_relaxed(base + offset + (index / 32) * 4) & mask);
}
static void gic_poke_irq(struct irq_data *d, u32 offset)
{
- u32 mask = 1 << (gic_irq(d) % 32);
void (*rwp_wait)(void);
void __iomem *base;
+ u32 index, mask;
+
+ offset = convert_offset_index(d, offset, &index);
+ mask = 1 << (index % 32);
if (gic_irq_in_rdist(d)) {
base = gic_data_rdist_sgi_base();
@@ -223,7 +276,7 @@ static void gic_poke_irq(struct irq_data *d, u32 offset)
rwp_wait = gic_dist_wait_for_rwp;
}
- writel_relaxed(mask, base + offset + (gic_irq(d) / 32) * 4);
+ writel_relaxed(mask, base + offset + (index / 32) * 4);
rwp_wait();
}
@@ -316,8 +369,11 @@ static int gic_irq_get_irqchip_state(struct irq_data *d,
static void gic_irq_set_prio(struct irq_data *d, u8 prio)
{
void __iomem *base = gic_dist_base(d);
+ u32 offset, index;
- writeb_relaxed(prio, base + GICD_IPRIORITYR + gic_irq(d));
+ offset = convert_offset_index(d, GICD_IPRIORITYR, &index);
+
+ writeb_relaxed(prio, base + offset + index);
}
static int gic_irq_nmi_setup(struct irq_data *d)
@@ -407,6 +463,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
unsigned int irq = gic_irq(d);
void (*rwp_wait)(void);
void __iomem *base;
+ u32 offset, index;
int ret;
/* Interrupt configuration for SGIs can't be changed */
@@ -426,8 +483,9 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
rwp_wait = gic_dist_wait_for_rwp;
}
+ offset = convert_offset_index(d, GICD_ICFGR, &index);
- ret = gic_configure_irq(irq, type, base + GICD_ICFGR, rwp_wait);
+ ret = gic_configure_irq(index, type, base + offset, rwp_wait);
if (ret && irq < 32) {
/* Misconfigured PPIs are usually not fatal */
pr_warn("GIC: PPI%d is secure or misconfigured\n", irq - 16);
@@ -970,6 +1028,7 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
bool force)
{
unsigned int cpu;
+ u32 offset, index;
void __iomem *reg;
int enabled;
u64 val;
@@ -990,7 +1049,8 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
if (enabled)
gic_mask_irq(d);
- reg = gic_dist_base(d) + GICD_IROUTER + (gic_irq(d) * 8);
+ offset = convert_offset_index(d, GICD_IROUTER, &index);
+ reg = gic_dist_base(d) + offset + (index * 8);
val = gic_mpidr_to_affinity(cpu_logical_map(cpu));
gic_write_irouter(val, reg);
@@ -1084,36 +1144,30 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
if (static_branch_likely(&supports_deactivate_key))
chip = &gic_eoimode1_chip;
- /* SGIs are private to the core kernel */
- if (hw < 16)
- return -EPERM;
- /* Nothing here */
- if (hw >= gic_data.irq_nr && hw < 8192)
- return -EPERM;
- /* Off limits */
- if (hw >= GIC_ID_NR)
- return -EPERM;
-
- /* PPIs */
- if (hw < 32) {
+ switch (__get_intid_range(hw)) {
+ case PPI_RANGE:
irq_set_percpu_devid(irq);
irq_domain_set_info(d, irq, hw, chip, d->host_data,
handle_percpu_devid_irq, NULL, NULL);
irq_set_status_flags(irq, IRQ_NOAUTOEN);
- }
- /* SPIs */
- if (hw >= 32 && hw < gic_data.irq_nr) {
+ break;
+
+ case SPI_RANGE:
irq_domain_set_info(d, irq, hw, chip, d->host_data,
handle_fasteoi_irq, NULL, NULL);
irq_set_probe(irq);
irqd_set_single_target(irq_desc_get_irq_data(irq_to_desc(irq)));
- }
- /* LPIs */
- if (hw >= 8192 && hw < GIC_ID_NR) {
+ break;
+
+ case LPI_RANGE:
if (!gic_dist_supports_lpis())
return -EPERM;
irq_domain_set_info(d, irq, hw, chip, d->host_data,
handle_fasteoi_irq, NULL, NULL);
+ break;
+
+ default:
+ return -EPERM;
}
return 0;
--
2.20.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 00/12] irqchip/gic-v3: Add support for GICv3.1 extended PPI/SPI ranges
From: Marc Zyngier @ 2019-08-06 10:01 UTC (permalink / raw)
To: Thomas Gleixner, Jason Cooper, Julien Thierry, Rob Herring
Cc: Lokesh Vutla, John Garry, linux-kernel, Shameerali Kolothum Thodi,
linux-arm-kernel
Apparently, having ~1000 wired interrupts is not enough, and some
people need more. Fear not! The GIC Achitecture Department hereby
grants you another 1024 SPIs, together with 64 PPIs, provided that you
implement GICv3.1 (see [1] for the details)
This series implements the required support, which requires a bit of
infrastructure rework in order to make the thing less horrible...
This has been tested on a FastModel. If there is no additional issue being
reported, I plan to put this into -next toward the end of this week and
let it simmer there for a bit.
[1] https://developer.arm.com/docs/ihi0069/latest (version E)
* From v1:
- Tighten ESPI range matching
- Added a warning to detect inconsistent distributor/cpu interface
configurations
- Added quirks to handle HIP06/07 erratum 161010803 which unexpectedly
advertise ESPI support
Marc Zyngier (12):
irqchip/gic: Rework gic_configure_irq to take the full ICFGR base
irqchip/gic-v3: Add INTID range and convertion primitives
dt-bindings: interrupt-controller: arm,gic-v3: Describe ESPI range
support
irqchip/gic-v3: Add ESPI range support
irqchip/gic: Prepare for more than 16 PPIs
irqchip/gic-v3: Dynamically allocate PPI NMI refcounts
irqchip/gic-v3: Dynamically allocate PPI partition descriptors
dt-bindings: interrupt-controller: arm,gic-v3: Describe EPPI range
support
irqchip/gic-v3: Add EPPI range support
irqchip/gic-v3: Warn about inconsistent implementations of extended
ranges
irqchip/gic: Skip DT quirks when evaluating IIDR-based quirks
irqchip/gic-v3: Add quirks for HIP06/07 invalid GICD_TYPER erratum
161010803
Documentation/arm64/silicon-errata.rst | 2 +
.../interrupt-controller/arm,gic-v3.yaml | 6 +-
drivers/irqchip/irq-gic-common.c | 35 +-
drivers/irqchip/irq-gic-common.h | 2 +-
drivers/irqchip/irq-gic-v3.c | 380 ++++++++++++++----
drivers/irqchip/irq-gic.c | 12 +-
drivers/irqchip/irq-hip04.c | 9 +-
include/linux/irqchip/arm-gic-v3.h | 30 +-
8 files changed, 372 insertions(+), 104 deletions(-)
--
2.20.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH v2 01/12] irqchip/gic: Rework gic_configure_irq to take the full ICFGR base
From: Marc Zyngier @ 2019-08-06 10:01 UTC (permalink / raw)
To: Thomas Gleixner, Jason Cooper, Julien Thierry, Rob Herring
Cc: Lokesh Vutla, John Garry, linux-kernel, Shameerali Kolothum Thodi,
linux-arm-kernel
In-Reply-To: <20190806100121.240767-1-maz@kernel.org>
gic_configure_irq is currently passed the (re)distributor address,
to which it applies an a fixed offset to get to the configuration
registers. This offset is constant across all GICs, or rather it was
until to v3.1...
An easy way out is for the individual drivers to pass the base
address of the configuration register for the considered interrupt.
At the same time, move part of the error handling back to the
individual drivers, as things are about to change on that front.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
drivers/irqchip/irq-gic-common.c | 14 +++++---------
drivers/irqchip/irq-gic-v3.c | 11 ++++++++++-
drivers/irqchip/irq-gic.c | 10 +++++++++-
drivers/irqchip/irq-hip04.c | 7 ++++++-
4 files changed, 30 insertions(+), 12 deletions(-)
diff --git a/drivers/irqchip/irq-gic-common.c b/drivers/irqchip/irq-gic-common.c
index b0a8215a13fc..6900b6f0921c 100644
--- a/drivers/irqchip/irq-gic-common.c
+++ b/drivers/irqchip/irq-gic-common.c
@@ -63,7 +63,7 @@ int gic_configure_irq(unsigned int irq, unsigned int type,
* for "irq", depending on "type".
*/
raw_spin_lock_irqsave(&irq_controller_lock, flags);
- val = oldval = readl_relaxed(base + GIC_DIST_CONFIG + confoff);
+ val = oldval = readl_relaxed(base + confoff);
if (type & IRQ_TYPE_LEVEL_MASK)
val &= ~confmask;
else if (type & IRQ_TYPE_EDGE_BOTH)
@@ -83,14 +83,10 @@ int gic_configure_irq(unsigned int irq, unsigned int type,
* does not allow us to set the configuration or we are in a
* non-secure mode, and hence it may not be catastrophic.
*/
- writel_relaxed(val, base + GIC_DIST_CONFIG + confoff);
- if (readl_relaxed(base + GIC_DIST_CONFIG + confoff) != val) {
- if (WARN_ON(irq >= 32))
- ret = -EINVAL;
- else
- pr_warn("GIC: PPI%d is secure or misconfigured\n",
- irq - 16);
- }
+ writel_relaxed(val, base + confoff);
+ if (readl_relaxed(base + confoff) != val)
+ ret = -EINVAL;
+
raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
if (sync_access)
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 96d927f0f91a..b250e69908f8 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -407,6 +407,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
unsigned int irq = gic_irq(d);
void (*rwp_wait)(void);
void __iomem *base;
+ int ret;
/* Interrupt configuration for SGIs can't be changed */
if (irq < 16)
@@ -425,7 +426,15 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
rwp_wait = gic_dist_wait_for_rwp;
}
- return gic_configure_irq(irq, type, base, rwp_wait);
+
+ ret = gic_configure_irq(irq, type, base + GICD_ICFGR, rwp_wait);
+ if (ret && irq < 32) {
+ /* Misconfigured PPIs are usually not fatal */
+ pr_warn("GIC: PPI%d is secure or misconfigured\n", irq - 16);
+ ret = 0;
+ }
+
+ return ret;
}
static int gic_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu)
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index e45f45e68720..ab48760acabb 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -291,6 +291,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
{
void __iomem *base = gic_dist_base(d);
unsigned int gicirq = gic_irq(d);
+ int ret;
/* Interrupt configuration for SGIs can't be changed */
if (gicirq < 16)
@@ -301,7 +302,14 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
type != IRQ_TYPE_EDGE_RISING)
return -EINVAL;
- return gic_configure_irq(gicirq, type, base, NULL);
+ ret = gic_configure_irq(gicirq, type, base + GIC_DIST_CONFIG, NULL);
+ if (ret && gicirq < 32) {
+ /* Misconfigured PPIs are usually not fatal */
+ pr_warn("GIC: PPI%d is secure or misconfigured\n", gicirq - 16);
+ ret = 0;
+ }
+
+ return ret;
}
static int gic_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu)
diff --git a/drivers/irqchip/irq-hip04.c b/drivers/irqchip/irq-hip04.c
index cf705827599c..1626131834a6 100644
--- a/drivers/irqchip/irq-hip04.c
+++ b/drivers/irqchip/irq-hip04.c
@@ -130,7 +130,12 @@ static int hip04_irq_set_type(struct irq_data *d, unsigned int type)
raw_spin_lock(&irq_controller_lock);
- ret = gic_configure_irq(irq, type, base, NULL);
+ ret = gic_configure_irq(irq, type, base + GIC_DIST_CONFIG, NULL);
+ if (ret && irq < 32) {
+ /* Misconfigured PPIs are usually not fatal */
+ pr_warn("GIC: PPI%d is secure or misconfigured\n", irq - 16);
+ ret = 0;
+ }
raw_spin_unlock(&irq_controller_lock);
--
2.20.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 04/12] irqchip/gic-v3: Add ESPI range support
From: Marc Zyngier @ 2019-08-06 10:01 UTC (permalink / raw)
To: Thomas Gleixner, Jason Cooper, Julien Thierry, Rob Herring
Cc: Lokesh Vutla, John Garry, linux-kernel, Shameerali Kolothum Thodi,
linux-arm-kernel
In-Reply-To: <20190806100121.240767-1-maz@kernel.org>
Add the required support for the ESPI range, which behave exactly like
the SPIs of old, only with new funky INTIDs.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
drivers/irqchip/irq-gic-v3.c | 85 ++++++++++++++++++++++++------
include/linux/irqchip/arm-gic-v3.h | 17 +++++-
2 files changed, 85 insertions(+), 17 deletions(-)
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index db3bdedd7241..1ca4dde32034 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -51,13 +51,16 @@ struct gic_chip_data {
u32 nr_redist_regions;
u64 flags;
bool has_rss;
- unsigned int irq_nr;
struct partition_desc *ppi_descs[16];
};
static struct gic_chip_data gic_data __read_mostly;
static DEFINE_STATIC_KEY_TRUE(supports_deactivate_key);
+#define GIC_ID_NR (1U << GICD_TYPER_ID_BITS(gic_data.rdists.gicd_typer))
+#define GIC_LINE_NR GICD_TYPER_SPIS(gic_data.rdists.gicd_typer)
+#define GIC_ESPI_NR GICD_TYPER_ESPIS(gic_data.rdists.gicd_typer)
+
/*
* The behaviours of RPR and PMR registers differ depending on the value of
* SCR_EL3.FIQ, and the behaviour of non-secure priority registers of the
@@ -100,6 +103,7 @@ static DEFINE_PER_CPU(bool, has_rss);
enum gic_intid_range {
PPI_RANGE,
SPI_RANGE,
+ ESPI_RANGE,
LPI_RANGE,
__INVALID_RANGE__
};
@@ -111,6 +115,8 @@ static enum gic_intid_range __get_intid_range(irq_hw_number_t hwirq)
return PPI_RANGE;
case 32 ... 1019:
return SPI_RANGE;
+ case ESPI_BASE_INTID ... (ESPI_BASE_INTID + 1023):
+ return ESPI_RANGE;
case 8192 ... GENMASK(23, 0):
return LPI_RANGE;
default:
@@ -141,6 +147,7 @@ static inline void __iomem *gic_dist_base(struct irq_data *d)
return gic_data_rdist_sgi_base();
case SPI_RANGE:
+ case ESPI_RANGE:
/* SPI -> dist_base */
return gic_data.dist_base;
@@ -234,6 +241,31 @@ static u32 convert_offset_index(struct irq_data *d, u32 offset, u32 *index)
case SPI_RANGE:
*index = d->hwirq;
return offset;
+ case ESPI_RANGE:
+ *index = d->hwirq - ESPI_BASE_INTID;
+ switch (offset) {
+ case GICD_ISENABLER:
+ return GICD_ISENABLERnE;
+ case GICD_ICENABLER:
+ return GICD_ICENABLERnE;
+ case GICD_ISPENDR:
+ return GICD_ISPENDRnE;
+ case GICD_ICPENDR:
+ return GICD_ICPENDRnE;
+ case GICD_ISACTIVER:
+ return GICD_ISACTIVERnE;
+ case GICD_ICACTIVER:
+ return GICD_ICACTIVERnE;
+ case GICD_IPRIORITYR:
+ return GICD_IPRIORITYRnE;
+ case GICD_ICFGR:
+ return GICD_ICFGRnE;
+ case GICD_IROUTER:
+ return GICD_IROUTERnE;
+ default:
+ break;
+ }
+ break;
default:
break;
}
@@ -316,7 +348,7 @@ static int gic_irq_set_irqchip_state(struct irq_data *d,
{
u32 reg;
- if (d->hwirq >= gic_data.irq_nr) /* PPI/SPI only */
+ if (d->hwirq >= 8192) /* PPI/SPI only */
return -EINVAL;
switch (which) {
@@ -343,7 +375,7 @@ static int gic_irq_set_irqchip_state(struct irq_data *d,
static int gic_irq_get_irqchip_state(struct irq_data *d,
enum irqchip_irq_state which, bool *val)
{
- if (d->hwirq >= gic_data.irq_nr) /* PPI/SPI only */
+ if (d->hwirq >= 8192) /* PPI/SPI only */
return -EINVAL;
switch (which) {
@@ -567,7 +599,12 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs
gic_arch_enable_irqs();
}
- if (likely(irqnr > 15 && irqnr < 1020) || irqnr >= 8192) {
+ /* Check for special IDs first */
+ if ((irqnr >= 1020 && irqnr <= 1023))
+ return;
+
+ /* Treat anything but SGIs in a uniform way */
+ if (likely(irqnr > 15)) {
int err;
if (static_branch_likely(&supports_deactivate_key))
@@ -655,10 +692,26 @@ static void __init gic_dist_init(void)
* do the right thing if the kernel is running in secure mode,
* but that's not the intended use case anyway.
*/
- for (i = 32; i < gic_data.irq_nr; i += 32)
+ for (i = 32; i < GIC_LINE_NR; i += 32)
writel_relaxed(~0, base + GICD_IGROUPR + i / 8);
- gic_dist_config(base, gic_data.irq_nr, gic_dist_wait_for_rwp);
+ /* Extended SPI range, not handled by the GICv2/GICv3 common code */
+ for (i = 0; i < GIC_ESPI_NR; i += 32) {
+ writel_relaxed(~0U, base + GICD_ICENABLERnE + i / 8);
+ writel_relaxed(~0U, base + GICD_ICACTIVERnE + i / 8);
+ }
+
+ for (i = 0; i < GIC_ESPI_NR; i += 32)
+ writel_relaxed(~0U, base + GICD_IGROUPRnE + i / 8);
+
+ for (i = 0; i < GIC_ESPI_NR; i += 16)
+ writel_relaxed(0, base + GICD_ICFGRnE + i / 4);
+
+ for (i = 0; i < GIC_ESPI_NR; i += 4)
+ writel_relaxed(GICD_INT_DEF_PRI_X4, base + GICD_IPRIORITYRnE + i);
+
+ /* Now do the common stuff, and wait for the distributor to drain */
+ gic_dist_config(base, GIC_LINE_NR, gic_dist_wait_for_rwp);
/* Enable distributor with ARE, Group1 */
writel_relaxed(GICD_CTLR_ARE_NS | GICD_CTLR_ENABLE_G1A | GICD_CTLR_ENABLE_G1,
@@ -669,8 +722,11 @@ static void __init gic_dist_init(void)
* enabled.
*/
affinity = gic_mpidr_to_affinity(cpu_logical_map(smp_processor_id()));
- for (i = 32; i < gic_data.irq_nr; i++)
+ for (i = 32; i < GIC_LINE_NR; i++)
gic_write_irouter(affinity, base + GICD_IROUTER + i * 8);
+
+ for (i = 0; i < GIC_ESPI_NR; i++)
+ gic_write_irouter(affinity, base + GICD_IROUTERnE + i * 8);
}
static int gic_iterate_rdists(int (*fn)(struct redist_region *, void __iomem *))
@@ -1134,8 +1190,6 @@ static struct irq_chip gic_eoimode1_chip = {
IRQCHIP_MASK_ON_SUSPEND,
};
-#define GIC_ID_NR (1U << GICD_TYPER_ID_BITS(gic_data.rdists.gicd_typer))
-
static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
irq_hw_number_t hw)
{
@@ -1153,6 +1207,7 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
break;
case SPI_RANGE:
+ case ESPI_RANGE:
irq_domain_set_info(d, irq, hw, chip, d->host_data,
handle_fasteoi_irq, NULL, NULL);
irq_set_probe(irq);
@@ -1192,6 +1247,9 @@ static int gic_irq_domain_translate(struct irq_domain *d,
case GIC_IRQ_TYPE_PARTITION:
*hwirq = fwspec->param[1] + 16;
break;
+ case 2: /* ESPI */
+ *hwirq = fwspec->param[1] + ESPI_BASE_INTID;
+ break;
case GIC_IRQ_TYPE_LPI: /* LPI */
*hwirq = fwspec->param[1];
break;
@@ -1346,7 +1404,6 @@ static int __init gic_init_bases(void __iomem *dist_base,
struct fwnode_handle *handle)
{
u32 typer;
- int gic_irqs;
int err;
if (!is_hyp_mode_available())
@@ -1363,15 +1420,11 @@ static int __init gic_init_bases(void __iomem *dist_base,
/*
* Find out how many interrupts are supported.
- * The GIC only supports up to 1020 interrupt sources (SGI+PPI+SPI)
*/
typer = readl_relaxed(gic_data.dist_base + GICD_TYPER);
gic_data.rdists.gicd_typer = typer;
- gic_irqs = GICD_TYPER_IRQS(typer);
- if (gic_irqs > 1020)
- gic_irqs = 1020;
- gic_data.irq_nr = gic_irqs;
-
+ pr_info("%d SPIs implemented\n", GIC_LINE_NR - 32);
+ pr_info("%d Extended SPIs implemented\n", GIC_ESPI_NR);
gic_data.domain = irq_domain_create_tree(handle, &gic_irq_domain_ops,
&gic_data);
irq_domain_update_bus_token(gic_data.domain, DOMAIN_BUS_WIRED);
diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index 67c4b9806d43..c523bf1faa55 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -30,10 +30,22 @@
#define GICD_ICFGR 0x0C00
#define GICD_IGRPMODR 0x0D00
#define GICD_NSACR 0x0E00
+#define GICD_IGROUPRnE 0x1000
+#define GICD_ISENABLERnE 0x1200
+#define GICD_ICENABLERnE 0x1400
+#define GICD_ISPENDRnE 0x1600
+#define GICD_ICPENDRnE 0x1800
+#define GICD_ISACTIVERnE 0x1A00
+#define GICD_ICACTIVERnE 0x1C00
+#define GICD_IPRIORITYRnE 0x2000
+#define GICD_ICFGRnE 0x3000
#define GICD_IROUTER 0x6000
+#define GICD_IROUTERnE 0x8000
#define GICD_IDREGS 0xFFD0
#define GICD_PIDR2 0xFFE8
+#define ESPI_BASE_INTID 4096
+
/*
* Those registers are actually from GICv2, but the spec demands that they
* are implemented as RES0 if ARE is 1 (which we do in KVM's emulated GICv3).
@@ -69,10 +81,13 @@
#define GICD_TYPER_RSS (1U << 26)
#define GICD_TYPER_LPIS (1U << 17)
#define GICD_TYPER_MBIS (1U << 16)
+#define GICD_TYPER_ESPI (1U << 8)
#define GICD_TYPER_ID_BITS(typer) ((((typer) >> 19) & 0x1f) + 1)
#define GICD_TYPER_NUM_LPIS(typer) ((((typer) >> 11) & 0x1f) + 1)
-#define GICD_TYPER_IRQS(typer) ((((typer) & 0x1f) + 1) * 32)
+#define GICD_TYPER_SPIS(typer) ((((typer) & 0x1f) + 1) * 32)
+#define GICD_TYPER_ESPIS(typer) \
+ (((typer) & GICD_TYPER_ESPI) ? GICD_TYPER_SPIS((typer) >> 27) : 0)
#define GICD_IROUTER_SPI_MODE_ONE (0U << 31)
#define GICD_IROUTER_SPI_MODE_ANY (1U << 31)
--
2.20.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 05/12] irqchip/gic: Prepare for more than 16 PPIs
From: Marc Zyngier @ 2019-08-06 10:01 UTC (permalink / raw)
To: Thomas Gleixner, Jason Cooper, Julien Thierry, Rob Herring
Cc: Lokesh Vutla, John Garry, linux-kernel, Shameerali Kolothum Thodi,
linux-arm-kernel
In-Reply-To: <20190806100121.240767-1-maz@kernel.org>
GICv3.1 allows up to 80 PPIs (16 legaci PPIs and 64 Extended PPIs),
meaning we can't just leave the old 16 hardcoded everywhere.
We also need to add the infrastructure to discover the number of PPIs
on a per redistributor basis, although we still pretend there is only
16 of them for now.
No functional change.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
drivers/irqchip/irq-gic-common.c | 19 ++++++++++++-------
drivers/irqchip/irq-gic-common.h | 2 +-
drivers/irqchip/irq-gic-v3.c | 22 +++++++++++++++-------
drivers/irqchip/irq-gic.c | 2 +-
drivers/irqchip/irq-hip04.c | 2 +-
5 files changed, 30 insertions(+), 17 deletions(-)
diff --git a/drivers/irqchip/irq-gic-common.c b/drivers/irqchip/irq-gic-common.c
index 6900b6f0921c..14110db01c05 100644
--- a/drivers/irqchip/irq-gic-common.c
+++ b/drivers/irqchip/irq-gic-common.c
@@ -128,26 +128,31 @@ void gic_dist_config(void __iomem *base, int gic_irqs,
sync_access();
}
-void gic_cpu_config(void __iomem *base, void (*sync_access)(void))
+void gic_cpu_config(void __iomem *base, int nr, void (*sync_access)(void))
{
int i;
/*
* Deal with the banked PPI and SGI interrupts - disable all
- * PPI interrupts, ensure all SGI interrupts are enabled.
- * Make sure everything is deactivated.
+ * private interrupts. Make sure everything is deactivated.
*/
- writel_relaxed(GICD_INT_EN_CLR_X32, base + GIC_DIST_ACTIVE_CLEAR);
- writel_relaxed(GICD_INT_EN_CLR_PPI, base + GIC_DIST_ENABLE_CLEAR);
- writel_relaxed(GICD_INT_EN_SET_SGI, base + GIC_DIST_ENABLE_SET);
+ for (i = 0; i < nr; i += 32) {
+ writel_relaxed(GICD_INT_EN_CLR_X32,
+ base + GIC_DIST_ACTIVE_CLEAR + i / 8);
+ writel_relaxed(GICD_INT_EN_CLR_X32,
+ base + GIC_DIST_ENABLE_CLEAR + i / 8);
+ }
/*
* Set priority on PPI and SGI interrupts
*/
- for (i = 0; i < 32; i += 4)
+ for (i = 0; i < nr; i += 4)
writel_relaxed(GICD_INT_DEF_PRI_X4,
base + GIC_DIST_PRI + i * 4 / 4);
+ /* Ensure all SGI interrupts are now enabled */
+ writel_relaxed(GICD_INT_EN_SET_SGI, base + GIC_DIST_ENABLE_SET);
+
if (sync_access)
sync_access();
}
diff --git a/drivers/irqchip/irq-gic-common.h b/drivers/irqchip/irq-gic-common.h
index 5a46b6b57750..ccba8b0fe0f5 100644
--- a/drivers/irqchip/irq-gic-common.h
+++ b/drivers/irqchip/irq-gic-common.h
@@ -22,7 +22,7 @@ int gic_configure_irq(unsigned int irq, unsigned int type,
void __iomem *base, void (*sync_access)(void));
void gic_dist_config(void __iomem *base, int gic_irqs,
void (*sync_access)(void));
-void gic_cpu_config(void __iomem *base, void (*sync_access)(void));
+void gic_cpu_config(void __iomem *base, int nr, void (*sync_access)(void));
void gic_enable_quirks(u32 iidr, const struct gic_quirk *quirks,
void *data);
void gic_enable_of_quirks(const struct device_node *np,
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 1ca4dde32034..e03fb6d7c2ce 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -51,6 +51,7 @@ struct gic_chip_data {
u32 nr_redist_regions;
u64 flags;
bool has_rss;
+ unsigned int ppi_nr;
struct partition_desc *ppi_descs[16];
};
@@ -812,19 +813,24 @@ static int gic_populate_rdist(void)
return -ENODEV;
}
-static int __gic_update_vlpi_properties(struct redist_region *region,
- void __iomem *ptr)
+static int __gic_update_rdist_properties(struct redist_region *region,
+ void __iomem *ptr)
{
u64 typer = gic_read_typer(ptr + GICR_TYPER);
gic_data.rdists.has_vlpis &= !!(typer & GICR_TYPER_VLPIS);
gic_data.rdists.has_direct_lpi &= !!(typer & GICR_TYPER_DirectLPIS);
+ gic_data.ppi_nr = 16;
return 1;
}
-static void gic_update_vlpi_properties(void)
+static void gic_update_rdist_properties(void)
{
- gic_iterate_rdists(__gic_update_vlpi_properties);
+ gic_data.ppi_nr = UINT_MAX;
+ gic_iterate_rdists(__gic_update_rdist_properties);
+ if (WARN_ON(gic_data.ppi_nr == UINT_MAX))
+ gic_data.ppi_nr = 0;
+ pr_info("%d PPIs implemented\n", gic_data.ppi_nr);
pr_info("%sVLPI support, %sdirect LPI support\n",
!gic_data.rdists.has_vlpis ? "no " : "",
!gic_data.rdists.has_direct_lpi ? "no " : "");
@@ -968,6 +974,7 @@ static int gic_dist_supports_lpis(void)
static void gic_cpu_init(void)
{
void __iomem *rbase;
+ int i;
/* Register ourselves with the rest of the world */
if (gic_populate_rdist())
@@ -978,9 +985,10 @@ static void gic_cpu_init(void)
rbase = gic_data_rdist_sgi_base();
/* Configure SGIs/PPIs as non-secure Group-1 */
- writel_relaxed(~0, rbase + GICR_IGROUPR0);
+ for (i = 0; i < gic_data.ppi_nr + 16; i += 32)
+ writel_relaxed(~0, rbase + GICR_IGROUPR0 + i / 8);
- gic_cpu_config(rbase, gic_redist_wait_for_rwp);
+ gic_cpu_config(rbase, gic_data.ppi_nr + 16, gic_redist_wait_for_rwp);
/* initialise system registers */
gic_cpu_sys_reg_init();
@@ -1449,7 +1457,7 @@ static int __init gic_init_bases(void __iomem *dist_base,
set_handle_irq(gic_handle_irq);
- gic_update_vlpi_properties();
+ gic_update_rdist_properties();
gic_smp_init();
gic_dist_init();
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index ab48760acabb..25c1ae69db30 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -543,7 +543,7 @@ static int gic_cpu_init(struct gic_chip_data *gic)
gic_cpu_map[i] &= ~cpu_mask;
}
- gic_cpu_config(dist_base, NULL);
+ gic_cpu_config(dist_base, 32, NULL);
writel_relaxed(GICC_INT_PRI_THRESHOLD, base + GIC_CPU_PRIMASK);
gic_cpu_if_up(gic);
diff --git a/drivers/irqchip/irq-hip04.c b/drivers/irqchip/irq-hip04.c
index 1626131834a6..130caa1c9d93 100644
--- a/drivers/irqchip/irq-hip04.c
+++ b/drivers/irqchip/irq-hip04.c
@@ -273,7 +273,7 @@ static void hip04_irq_cpu_init(struct hip04_irq_data *intc)
if (i != cpu)
hip04_cpu_map[i] &= ~cpu_mask;
- gic_cpu_config(dist_base, NULL);
+ gic_cpu_config(dist_base, 32, NULL);
writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
writel_relaxed(1, base + GIC_CPU_CTRL);
--
2.20.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 06/12] irqchip/gic-v3: Dynamically allocate PPI NMI refcounts
From: Marc Zyngier @ 2019-08-06 10:01 UTC (permalink / raw)
To: Thomas Gleixner, Jason Cooper, Julien Thierry, Rob Herring
Cc: Lokesh Vutla, John Garry, linux-kernel, Shameerali Kolothum Thodi,
linux-arm-kernel
In-Reply-To: <20190806100121.240767-1-maz@kernel.org>
As we're about to have a variable number of PPIs, let's make the
allocation of the NMI refcounts dynamic. Also apply some minor
cleanups (moving things around).
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
drivers/irqchip/irq-gic-v3.c | 47 ++++++++++++++++++++++++++----------
1 file changed, 34 insertions(+), 13 deletions(-)
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index e03fb6d7c2ce..4253c7f67c86 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -88,7 +88,7 @@ static DEFINE_STATIC_KEY_TRUE(supports_deactivate_key);
static DEFINE_STATIC_KEY_FALSE(supports_pseudo_nmis);
/* ppi_nmi_refs[n] == number of cpus having ppi[n + 16] set as NMI */
-static refcount_t ppi_nmi_refs[16];
+static refcount_t *ppi_nmi_refs;
static struct gic_kvm_info gic_v3_kvm_info;
static DEFINE_PER_CPU(bool, has_rss);
@@ -409,6 +409,16 @@ static void gic_irq_set_prio(struct irq_data *d, u8 prio)
writeb_relaxed(prio, base + offset + index);
}
+static u32 gic_get_ppi_index(struct irq_data *d)
+{
+ switch (get_intid_range(d)) {
+ case PPI_RANGE:
+ return d->hwirq - 16;
+ default:
+ unreachable();
+ }
+}
+
static int gic_irq_nmi_setup(struct irq_data *d)
{
struct irq_desc *desc = irq_to_desc(d->irq);
@@ -429,10 +439,12 @@ static int gic_irq_nmi_setup(struct irq_data *d)
return -EINVAL;
/* desc lock should already be held */
- if (gic_irq(d) < 32) {
+ if (gic_irq_in_rdist(d)) {
+ u32 idx = gic_get_ppi_index(d);
+
/* Setting up PPI as NMI, only switch handler for first NMI */
- if (!refcount_inc_not_zero(&ppi_nmi_refs[gic_irq(d) - 16])) {
- refcount_set(&ppi_nmi_refs[gic_irq(d) - 16], 1);
+ if (!refcount_inc_not_zero(&ppi_nmi_refs[idx])) {
+ refcount_set(&ppi_nmi_refs[idx], 1);
desc->handle_irq = handle_percpu_devid_fasteoi_nmi;
}
} else {
@@ -464,9 +476,11 @@ static void gic_irq_nmi_teardown(struct irq_data *d)
return;
/* desc lock should already be held */
- if (gic_irq(d) < 32) {
+ if (gic_irq_in_rdist(d)) {
+ u32 idx = gic_get_ppi_index(d);
+
/* Tearing down NMI, only switch handler for last NMI */
- if (refcount_dec_and_test(&ppi_nmi_refs[gic_irq(d) - 16]))
+ if (refcount_dec_and_test(&ppi_nmi_refs[idx]))
desc->handle_irq = handle_percpu_devid_irq;
} else {
desc->handle_irq = handle_fasteoi_irq;
@@ -1394,7 +1408,19 @@ static void gic_enable_nmi_support(void)
{
int i;
- for (i = 0; i < 16; i++)
+ if (!gic_prio_masking_enabled())
+ return;
+
+ if (gic_has_group0() && !gic_dist_security_disabled()) {
+ pr_warn("SCR_EL3.FIQ is cleared, cannot enable use of pseudo-NMIs\n");
+ return;
+ }
+
+ ppi_nmi_refs = kcalloc(gic_data.ppi_nr, sizeof(*ppi_nmi_refs), GFP_KERNEL);
+ if (!ppi_nmi_refs)
+ return;
+
+ for (i = 0; i < gic_data.ppi_nr; i++)
refcount_set(&ppi_nmi_refs[i], 0);
static_branch_enable(&supports_pseudo_nmis);
@@ -1472,12 +1498,7 @@ static int __init gic_init_bases(void __iomem *dist_base,
gicv2m_init(handle, gic_data.domain);
}
- if (gic_prio_masking_enabled()) {
- if (!gic_has_group0() || gic_dist_security_disabled())
- gic_enable_nmi_support();
- else
- pr_warn("SCR_EL3.FIQ is cleared, cannot enable use of pseudo-NMIs\n");
- }
+ gic_enable_nmi_support();
return 0;
--
2.20.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 07/12] irqchip/gic-v3: Dynamically allocate PPI partition descriptors
From: Marc Zyngier @ 2019-08-06 10:01 UTC (permalink / raw)
To: Thomas Gleixner, Jason Cooper, Julien Thierry, Rob Herring
Cc: Lokesh Vutla, John Garry, linux-kernel, Shameerali Kolothum Thodi,
linux-arm-kernel
In-Reply-To: <20190806100121.240767-1-maz@kernel.org>
Again, PPIs are becoming a variable set. Let's hack the PPI partition
code to make the top-level array dynamically allocated.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
drivers/irqchip/irq-gic-v3.c | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 4253c7f67c86..34f8a96bd747 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -52,7 +52,7 @@ struct gic_chip_data {
u64 flags;
bool has_rss;
unsigned int ppi_nr;
- struct partition_desc *ppi_descs[16];
+ struct partition_desc **ppi_descs;
};
static struct gic_chip_data gic_data __read_mostly;
@@ -1354,7 +1354,8 @@ static int gic_irq_domain_select(struct irq_domain *d,
* then we need to match the partition domain.
*/
if (fwspec->param_count >= 4 &&
- fwspec->param[0] == 1 && fwspec->param[3] != 0)
+ fwspec->param[0] == 1 && fwspec->param[3] != 0 &&
+ gic_data.ppi_descs)
return d == partition_get_domain(gic_data.ppi_descs[fwspec->param[1]]);
return d == gic_data.domain;
@@ -1375,6 +1376,9 @@ static int partition_domain_translate(struct irq_domain *d,
struct device_node *np;
int ret;
+ if (!gic_data.ppi_descs)
+ return -ENOMEM;
+
np = of_find_node_by_phandle(fwspec->param[3]);
if (WARN_ON(!np))
return -EINVAL;
@@ -1531,6 +1535,10 @@ static void __init gic_populate_ppi_partitions(struct device_node *gic_node)
if (!parts_node)
return;
+ gic_data.ppi_descs = kcalloc(gic_data.ppi_nr, sizeof(*gic_data.ppi_descs), GFP_KERNEL);
+ if (!gic_data.ppi_descs)
+ return;
+
nr_parts = of_get_child_count(parts_node);
if (!nr_parts)
@@ -1582,7 +1590,7 @@ static void __init gic_populate_ppi_partitions(struct device_node *gic_node)
part_idx++;
}
- for (i = 0; i < 16; i++) {
+ for (i = 0; i < gic_data.ppi_nr; i++) {
unsigned int irq;
struct partition_desc *desc;
struct irq_fwspec ppi_fwspec = {
--
2.20.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 08/12] dt-bindings: interrupt-controller: arm, gic-v3: Describe EPPI range support
From: Marc Zyngier @ 2019-08-06 10:01 UTC (permalink / raw)
To: Thomas Gleixner, Jason Cooper, Julien Thierry, Rob Herring
Cc: Lokesh Vutla, John Garry, linux-kernel, Shameerali Kolothum Thodi,
linux-arm-kernel
In-Reply-To: <20190806100121.240767-1-maz@kernel.org>
Update the GICv3 binding to allow interrupts in the EPPI range.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
.../devicetree/bindings/interrupt-controller/arm,gic-v3.yaml | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml b/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml
index 98a3ecda8e07..1fe147daca4c 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml
+++ b/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml
@@ -44,12 +44,13 @@ properties:
be at least 4.
The 1st cell is the interrupt type; 0 for SPI interrupts, 1 for PPI
- interrupts, 2 for interrupts in the Extended SPI range. Other values
- are reserved for future use.
+ interrupts, 2 for interrupts in the Extended SPI range, 3 for the
+ Extended PPI range. Other values are reserved for future use.
The 2nd cell contains the interrupt number for the interrupt type.
SPI interrupts are in the range [0-987]. PPI interrupts are in the
range [0-15]. Extented SPI interrupts are in the range [0-1023].
+ Extended PPI interrupts are in the range [0-127].
The 3rd cell is the flags, encoded as follows:
bits[3:0] trigger type and level flags.
--
2.20.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 09/12] irqchip/gic-v3: Add EPPI range support
From: Marc Zyngier @ 2019-08-06 10:01 UTC (permalink / raw)
To: Thomas Gleixner, Jason Cooper, Julien Thierry, Rob Herring
Cc: Lokesh Vutla, John Garry, linux-kernel, Shameerali Kolothum Thodi,
linux-arm-kernel
In-Reply-To: <20190806100121.240767-1-maz@kernel.org>
Expand the pre-existing PPI support to be able to deal with the
Extended PPI range (EPPI). This includes obtaining the number of PPIs
from each individual redistributor, and compute the minimum set
(just in case someone builds something really clever...).
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
drivers/irqchip/irq-gic-v3.c | 42 +++++++++++++++++++++++++-----
include/linux/irqchip/arm-gic-v3.h | 12 +++++++++
2 files changed, 47 insertions(+), 7 deletions(-)
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 34f8a96bd747..f53e58d398ba 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -104,6 +104,7 @@ static DEFINE_PER_CPU(bool, has_rss);
enum gic_intid_range {
PPI_RANGE,
SPI_RANGE,
+ EPPI_RANGE,
ESPI_RANGE,
LPI_RANGE,
__INVALID_RANGE__
@@ -116,6 +117,8 @@ static enum gic_intid_range __get_intid_range(irq_hw_number_t hwirq)
return PPI_RANGE;
case 32 ... 1019:
return SPI_RANGE;
+ case EPPI_BASE_INTID ... (EPPI_BASE_INTID + 63):
+ return EPPI_RANGE;
case ESPI_BASE_INTID ... (ESPI_BASE_INTID + 1023):
return ESPI_RANGE;
case 8192 ... GENMASK(23, 0):
@@ -137,13 +140,15 @@ static inline unsigned int gic_irq(struct irq_data *d)
static inline int gic_irq_in_rdist(struct irq_data *d)
{
- return get_intid_range(d) == PPI_RANGE;
+ enum gic_intid_range range = get_intid_range(d);
+ return range == PPI_RANGE || range == EPPI_RANGE;
}
static inline void __iomem *gic_dist_base(struct irq_data *d)
{
switch (get_intid_range(d)) {
case PPI_RANGE:
+ case EPPI_RANGE:
/* SGI+PPI -> SGI_base for this CPU */
return gic_data_rdist_sgi_base();
@@ -242,6 +247,14 @@ static u32 convert_offset_index(struct irq_data *d, u32 offset, u32 *index)
case SPI_RANGE:
*index = d->hwirq;
return offset;
+ case EPPI_RANGE:
+ /*
+ * Contrary to the ESPI range, the EPPI range is contiguous
+ * to the PPI range in the registers, so let's adjust the
+ * displacement accordingly. Consistency is overrated.
+ */
+ *index = d->hwirq - EPPI_BASE_INTID + 32;
+ return offset;
case ESPI_RANGE:
*index = d->hwirq - ESPI_BASE_INTID;
switch (offset) {
@@ -414,6 +427,8 @@ static u32 gic_get_ppi_index(struct irq_data *d)
switch (get_intid_range(d)) {
case PPI_RANGE:
return d->hwirq - 16;
+ case EPPI_RANGE:
+ return d->hwirq - EPPI_BASE_INTID + 16;
default:
unreachable();
}
@@ -507,6 +522,7 @@ static void gic_eoimode1_eoi_irq(struct irq_data *d)
static int gic_set_type(struct irq_data *d, unsigned int type)
{
+ enum gic_intid_range range;
unsigned int irq = gic_irq(d);
void (*rwp_wait)(void);
void __iomem *base;
@@ -517,9 +533,11 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
if (irq < 16)
return -EINVAL;
+ range = get_intid_range(d);
+
/* SPIs have restrictions on the supported types */
- if (irq >= 32 && type != IRQ_TYPE_LEVEL_HIGH &&
- type != IRQ_TYPE_EDGE_RISING)
+ if ((range == SPI_RANGE || range == ESPI_RANGE) &&
+ type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
return -EINVAL;
if (gic_irq_in_rdist(d)) {
@@ -533,9 +551,9 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
offset = convert_offset_index(d, GICD_ICFGR, &index);
ret = gic_configure_irq(index, type, base + offset, rwp_wait);
- if (ret && irq < 32) {
+ if (ret && (range == PPI_RANGE || range == EPPI_RANGE)) {
/* Misconfigured PPIs are usually not fatal */
- pr_warn("GIC: PPI%d is secure or misconfigured\n", irq - 16);
+ pr_warn("GIC: PPI INTID%d is secure or misconfigured\n", irq);
ret = 0;
}
@@ -833,7 +851,7 @@ static int __gic_update_rdist_properties(struct redist_region *region,
u64 typer = gic_read_typer(ptr + GICR_TYPER);
gic_data.rdists.has_vlpis &= !!(typer & GICR_TYPER_VLPIS);
gic_data.rdists.has_direct_lpi &= !!(typer & GICR_TYPER_DirectLPIS);
- gic_data.ppi_nr = 16;
+ gic_data.ppi_nr = min(GICR_TYPER_NR_PPIS(typer), gic_data.ppi_nr);
return 1;
}
@@ -1222,6 +1240,7 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
switch (__get_intid_range(hw)) {
case PPI_RANGE:
+ case EPPI_RANGE:
irq_set_percpu_devid(irq);
irq_domain_set_info(d, irq, hw, chip, d->host_data,
handle_percpu_devid_irq, NULL, NULL);
@@ -1266,15 +1285,24 @@ static int gic_irq_domain_translate(struct irq_domain *d,
*hwirq = fwspec->param[1] + 32;
break;
case 1: /* PPI */
- case GIC_IRQ_TYPE_PARTITION:
*hwirq = fwspec->param[1] + 16;
break;
case 2: /* ESPI */
*hwirq = fwspec->param[1] + ESPI_BASE_INTID;
break;
+ case 3: /* EPPI */
+ *hwirq = fwspec->param[1] + EPPI_BASE_INTID;
+ break;
case GIC_IRQ_TYPE_LPI: /* LPI */
*hwirq = fwspec->param[1];
break;
+ case GIC_IRQ_TYPE_PARTITION:
+ *hwirq = fwspec->param[1];
+ if (fwspec->param[1] >= 16)
+ *hwirq += EPPI_BASE_INTID - 16;
+ else
+ *hwirq += 16;
+ break;
default:
return -EINVAL;
}
diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index c523bf1faa55..9ec3349dee04 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -124,6 +124,18 @@
#define GICR_TYPER_CPU_NUMBER(r) (((r) >> 8) & 0xffff)
+#define EPPI_BASE_INTID 1056
+
+#define GICR_TYPER_NR_PPIS(r) \
+ ({ \
+ unsigned int __ppinum = ((r) >> 27) & 0x1f; \
+ unsigned int __nr_ppis = 16; \
+ if (__ppinum == 1 || __ppinum == 2) \
+ __nr_ppis += __ppinum * 32; \
+ \
+ __nr_ppis; \
+ })
+
#define GICR_WAKER_ProcessorSleep (1U << 1)
#define GICR_WAKER_ChildrenAsleep (1U << 2)
--
2.20.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 11/12] irqchip/gic: Skip DT quirks when evaluating IIDR-based quirks
From: Marc Zyngier @ 2019-08-06 10:01 UTC (permalink / raw)
To: Thomas Gleixner, Jason Cooper, Julien Thierry, Rob Herring
Cc: Lokesh Vutla, John Garry, linux-kernel, Shameerali Kolothum Thodi,
linux-arm-kernel
In-Reply-To: <20190806100121.240767-1-maz@kernel.org>
When evaluating potential quirks matched by reads of the IIDR
register, skip the quirk entries that use a "compatible"
property attached to them, as these are DT based.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
drivers/irqchip/irq-gic-common.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/irqchip/irq-gic-common.c b/drivers/irqchip/irq-gic-common.c
index 14110db01c05..82520006195d 100644
--- a/drivers/irqchip/irq-gic-common.c
+++ b/drivers/irqchip/irq-gic-common.c
@@ -41,6 +41,8 @@ void gic_enable_quirks(u32 iidr, const struct gic_quirk *quirks,
void *data)
{
for (; quirks->desc; quirks++) {
+ if (quirks->compatible)
+ continue;
if (quirks->iidr != (quirks->mask & iidr))
continue;
if (quirks->init(data))
--
2.20.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 12/12] irqchip/gic-v3: Add quirks for HIP06/07 invalid GICD_TYPER erratum 161010803
From: Marc Zyngier @ 2019-08-06 10:01 UTC (permalink / raw)
To: Thomas Gleixner, Jason Cooper, Julien Thierry, Rob Herring
Cc: Lokesh Vutla, John Garry, linux-kernel, Shameerali Kolothum Thodi,
linux-arm-kernel
In-Reply-To: <20190806100121.240767-1-maz@kernel.org>
It looks like the HIP06/07 SoCs have extra bits in their GICD_TYPER
registers, which confuse the GICv3.1 code (these systems appear to
expose ESPIs while they actually don't).
Detect these systems as early as possible and wipe the fields that
should be RES0 in the register.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
Documentation/arm64/silicon-errata.rst | 2 +
drivers/irqchip/irq-gic-v3.c | 54 +++++++++++++++++++++-----
2 files changed, 46 insertions(+), 10 deletions(-)
diff --git a/Documentation/arm64/silicon-errata.rst b/Documentation/arm64/silicon-errata.rst
index 3e57d09246e6..17ea3fecddaa 100644
--- a/Documentation/arm64/silicon-errata.rst
+++ b/Documentation/arm64/silicon-errata.rst
@@ -115,6 +115,8 @@ stable kernels.
+----------------+-----------------+-----------------+-----------------------------+
| Hisilicon | Hip0{6,7} | #161010701 | N/A |
+----------------+-----------------+-----------------+-----------------------------+
+| Hisilicon | Hip0{6,7} | #161010803 | N/A |
++----------------+-----------------+-----------------+-----------------------------+
| Hisilicon | Hip07 | #161600802 | HISILICON_ERRATUM_161600802 |
+----------------+-----------------+-----------------+-----------------------------+
| Hisilicon | Hip08 SMMU PMCG | #162001800 | N/A |
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 334a10d9dbfb..bee141613b67 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -1441,6 +1441,46 @@ static bool gic_enable_quirk_msm8996(void *data)
return true;
}
+static bool gic_enable_quirk_hip06_07(void *data)
+{
+ struct gic_chip_data *d = data;
+
+ /*
+ * HIP06 GICD_IIDR clashes with GIC-600 product number (despite
+ * not being an actual ARM implementation). The saving grace is
+ * that GIC-600 doesn't have ESPI, so nothing to do in that case.
+ * HIP07 doesn't even have a proper IIDR, and still pretends to
+ * have ESPI. In both cases, put them right.
+ */
+ if (d->rdists.gicd_typer & GICD_TYPER_ESPI) {
+ /* Zero both ESPI and the RES0 field next to it... */
+ d->rdists.gicd_typer &= ~GENMASK(9, 8);
+ return true;
+ }
+
+ return false;
+}
+
+static const struct gic_quirk gic_quirks[] = {
+ {
+ .desc = "GICv3: Qualcomm MSM8996 broken firmware",
+ .compatible = "qcom,msm8996-gic-v3",
+ .init = gic_enable_quirk_msm8996,
+ },
+ {
+ .desc = "GICv3: HIP06 erratum 161010803",
+ .iidr = 0x0204043b,
+ .init = gic_enable_quirk_hip06_07,
+ },
+ {
+ .desc = "GICv3: HIP07 erratum 161010803",
+ .iidr = 0x00000000,
+ .init = gic_enable_quirk_hip06_07,
+ },
+ {
+ }
+};
+
static void gic_enable_nmi_support(void)
{
int i;
@@ -1494,6 +1534,10 @@ static int __init gic_init_bases(void __iomem *dist_base,
*/
typer = readl_relaxed(gic_data.dist_base + GICD_TYPER);
gic_data.rdists.gicd_typer = typer;
+
+ gic_enable_quirks(readl_relaxed(gic_data.dist_base + GICD_IIDR),
+ gic_quirks, &gic_data);
+
pr_info("%d SPIs implemented\n", GIC_LINE_NR - 32);
pr_info("%d Extended SPIs implemented\n", GIC_ESPI_NR);
gic_data.domain = irq_domain_create_tree(handle, &gic_irq_domain_ops,
@@ -1676,16 +1720,6 @@ static void __init gic_of_setup_kvm_info(struct device_node *node)
gic_set_kvm_info(&gic_v3_kvm_info);
}
-static const struct gic_quirk gic_quirks[] = {
- {
- .desc = "GICv3: Qualcomm MSM8996 broken firmware",
- .compatible = "qcom,msm8996-gic-v3",
- .init = gic_enable_quirk_msm8996,
- },
- {
- }
-};
-
static int __init gic_of_init(struct device_node *node, struct device_node *parent)
{
void __iomem *dist_base;
--
2.20.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 10/12] irqchip/gic-v3: Warn about inconsistent implementations of extended ranges
From: Marc Zyngier @ 2019-08-06 10:01 UTC (permalink / raw)
To: Thomas Gleixner, Jason Cooper, Julien Thierry, Rob Herring
Cc: Lokesh Vutla, John Garry, linux-kernel, Shameerali Kolothum Thodi,
linux-arm-kernel
In-Reply-To: <20190806100121.240767-1-maz@kernel.org>
As is it usual for the GIC, it isn't disallowed to put together a system
that is majorly inconsistent, with a distributor supporting the
extended ranges while some of the CPUs don't.
Kindly tell the user that things are sailing isn't going to be smooth.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
drivers/irqchip/irq-gic-v3.c | 5 +++++
include/linux/irqchip/arm-gic-v3.h | 1 +
2 files changed, 6 insertions(+)
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index f53e58d398ba..334a10d9dbfb 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -1014,6 +1014,11 @@ static void gic_cpu_init(void)
gic_enable_redist(true);
+ WARN((gic_data.ppi_nr > 16 || GIC_ESPI_NR != 0) &&
+ !(gic_read_ctlr() & ICC_CTLR_EL1_ExtRange),
+ "Distributor has extended ranges, but CPU%d doesn't\n",
+ smp_processor_id());
+
rbase = gic_data_rdist_sgi_base();
/* Configure SGIs/PPIs as non-secure Group-1 */
diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index 9ec3349dee04..5cc10cf7cb3e 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -496,6 +496,7 @@
#define ICC_CTLR_EL1_A3V_SHIFT 15
#define ICC_CTLR_EL1_A3V_MASK (0x1 << ICC_CTLR_EL1_A3V_SHIFT)
#define ICC_CTLR_EL1_RSS (0x1 << 18)
+#define ICC_CTLR_EL1_ExtRange (0x1 << 19)
#define ICC_PMR_EL1_SHIFT 0
#define ICC_PMR_EL1_MASK (0xff << ICC_PMR_EL1_SHIFT)
#define ICC_BPR0_EL1_SHIFT 0
--
2.20.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* Re: [PATCH v2] nvmem: meson-mx-efuse: allow reading data smaller than word_size
From: Srinivas Kandagatla @ 2019-08-06 10:03 UTC (permalink / raw)
To: Martin Blumenstingl, linux-amlogic; +Cc: linux-kernel, linux-arm-kernel
In-Reply-To: <20190727193414.11371-1-martin.blumenstingl@googlemail.com>
On 27/07/2019 20:34, Martin Blumenstingl wrote:
> Some Amlogic boards store the Ethernet MAC address inside the eFuse. The
> Ethernet MAC address uses 6 bytes. The existing logic in
> meson_mx_efuse_read() would write beyond the end of the data buffer when
> trying to read data with a size that is not aligned to word_size (4
> bytes on Meson8, Meson8b and Meson8m2).
>
> Calculate the remaining data to copy inside meson_mx_efuse_read() so
> reading 6 bytes doesn't write beyond the end of the data buffer.
>
> Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
> ---
Applied Thanks,
Srini
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH nvmem 1/1] nvmem: imx: add i.MX8QM platform support
From: Srinivas Kandagatla @ 2019-08-06 10:03 UTC (permalink / raw)
To: fugang.duan, shawnguo, s.hauer
Cc: gregkh, festevam, linux-arm-kernel, kernel, linux-kernel
In-Reply-To: <20190704142032.10745-1-fugang.duan@nxp.com>
On 04/07/2019 15:20, fugang.duan@nxp.com wrote:
> From: Fugang Duan <fugang.duan@nxp.com>
>
> i.MX8QM efuse table has some difference with i.MX8QXP platform,
> so add i.MX8QM platform support.
>
> Signed-off-by: Fugang Duan <fugang.duan@nxp.com>
> ---
> drivers/nvmem/imx-ocotp-scu.c | 7 +++++++
> 1 file changed, 7 insertions(+)
>
> diff --git a/drivers/nvmem/imx-ocotp-scu.c b/drivers/nvmem/imx-ocotp-scu.c
> index be2f5f0..0d78ab4 100644
> --- a/drivers/nvmem/imx-ocotp-scu.c
> +++ b/drivers/nvmem/imx-ocotp-scu.c
> @@ -16,6 +16,7 @@
>
> enum ocotp_devtype {
> IMX8QXP,
> + IMX8QM,
> };
>
> struct ocotp_devtype_data {
> @@ -39,6 +40,11 @@ static struct ocotp_devtype_data imx8qxp_data = {
> .nregs = 800,
> };
>
> +static struct ocotp_devtype_data imx8qm_data = {
> + .devtype = IMX8QM,
> + .nregs = 800,
> +};
> +
> static int imx_sc_misc_otp_fuse_read(struct imx_sc_ipc *ipc, u32 word,
> u32 *val)
> {
> @@ -118,6 +124,7 @@ static struct nvmem_config imx_scu_ocotp_nvmem_config = {
>
> static const struct of_device_id imx_scu_ocotp_dt_ids[] = {
> { .compatible = "fsl,imx8qxp-scu-ocotp", (void *)&imx8qxp_data },
> + { .compatible = "fsl,imx8qm-scu-ocotp", (void *)&imx8qm_data },
> { },
Looks like you forgot to add this new compatible to device tree bindings
at ./Documentation/devicetree/bindings/nvmem/imx-ocotp.txt or forgot to
add me to CC.
Please resend the patch with it, I can not apply this as it is.
Thanks,
srini
> };
> MODULE_DEVICE_TABLE(of, imx_scu_ocotp_dt_ids);
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH 1/1] nvmem: sunxi_sid: fix A64 SID controller support
From: Srinivas Kandagatla @ 2019-08-06 10:03 UTC (permalink / raw)
To: Stefan Mavrodiev, Maxime Ripard, Chen-Yu Tsai,
moderated list:ARM/Allwinner sunXi SoC support, open list
Cc: linux-sunxi
In-Reply-To: <20190731071447.9019-2-stefan@olimex.com>
On 31/07/2019 08:14, Stefan Mavrodiev wrote:
> Like in H3, A64 SID controller doesn't return correct data
> when using direct access. It appears that on A64, SID needs
> 8 bytes of word_size.
>
> Workaround is to enable read by registers.
>
> Signed-off-by: Stefan Mavrodiev <stefan@olimex.com>
Applied Thanks,
srini
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH 0/2] nvmem: imx-ocotp: allow reads with arbitrary size and offset
From: Srinivas Kandagatla @ 2019-08-06 10:05 UTC (permalink / raw)
To: Jose Diaz de Grenu
Cc: shawnguo, s.hauer, linux-kernel, linux-imx, kernel, festevam,
linux-arm-kernel
In-Reply-To: <1563895963-19526-1-git-send-email-Jose.DiazdeGrenu@digi.com>
On 23/07/2019 16:32, Jose Diaz de Grenu wrote:
> Currently the imx-ocotp driver does only allow reading complete OTP words
> correcty aligned.
>
> Usually OTP memory is limited, so the fields are stored using as few bits as
> possible. This means that a given value rarely uses 32 bits and happens to be
> aligned.
>
> Even though the NVMEM API offers a way to define offset and size of each cell
> (at bit level) this is not currently usable iwth the imx-ocotp driver, which
> forces consumers to read complete words and then hardcode the necessary
> shifting and masking in the driver code.
>
> As an example take the nvmem consumer imx_thermal.c, which reads nvmem cells
> as uint32_t words:
>
> ret = nvmem_cell_read_u32(&pdev->dev, "calib", &val);
> if (ret)
> return ret;
>
> ret = imx_init_calib(pdev, val);
> if (ret)
> return ret;
>
> ret = nvmem_cell_read_u32(&pdev->dev, "temp_grade", &val);
> if (ret)
> return ret;
> imx_init_temp_grade(pdev, val);
>
> but needs to later adjust the values in code:
>
> // Inside imx_init_calib()
> data->c1 = (ocotp_ana1 >> 9) & 0x1ff;
>
> // Inside imx_init_temp_grade()
> switch ((ocotp_mem0 >> 6) & 0x3) {
>
> This patch adjusts the driver so that reads can be requested using any size
> and offset. Then, for example the nvmem cell "calib" could use the 'bits'
> property to specify size and offset in bits, removing the need to mask and
> shift in the driver code.
>
> This is specially useful when several drivers use the same nvmem cell and when
> the specific size and offset of a OTP value depends on a hardware version.
>
> Jose Diaz de Grenu (2):
> nvmem: imx-ocotp: use constant for write restriction
> nvmem: imx-ocotp: allow reads with arbitrary size and offset
>
> drivers/nvmem/imx-ocotp.c | 34 ++++++++++++++++------------------
> 1 file changed, 16 insertions(+), 18 deletions(-)
Anyone form IMX can test this patchset before I push this out?
Thanks,
srini
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v2 10/12] irqchip/gic-v3: Warn about inconsistent implementations of extended ranges
From: Vladimir Murzin @ 2019-08-06 10:15 UTC (permalink / raw)
To: Marc Zyngier, Thomas Gleixner, Jason Cooper, Julien Thierry,
Rob Herring
Cc: Lokesh Vutla, John Garry, linux-kernel, Shameerali Kolothum Thodi,
linux-arm-kernel
In-Reply-To: <20190806100121.240767-11-maz@kernel.org>
Hi Marc,
On 8/6/19 11:01 AM, Marc Zyngier wrote:
> As is it usual for the GIC, it isn't disallowed to put together a system
> that is majorly inconsistent, with a distributor supporting the
> extended ranges while some of the CPUs don't.
>
> Kindly tell the user that things are sailing isn't going to be smooth.
>
> Signed-off-by: Marc Zyngier <maz@kernel.org>
> ---
> drivers/irqchip/irq-gic-v3.c | 5 +++++
> include/linux/irqchip/arm-gic-v3.h | 1 +
> 2 files changed, 6 insertions(+)
>
> diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
> index f53e58d398ba..334a10d9dbfb 100644
> --- a/drivers/irqchip/irq-gic-v3.c
> +++ b/drivers/irqchip/irq-gic-v3.c
> @@ -1014,6 +1014,11 @@ static void gic_cpu_init(void)
>
> gic_enable_redist(true);
>
> + WARN((gic_data.ppi_nr > 16 || GIC_ESPI_NR != 0) &&
> + !(gic_read_ctlr() & ICC_CTLR_EL1_ExtRange),
> + "Distributor has extended ranges, but CPU%d doesn't\n",
> + smp_processor_id());
> +
Should such setup be tainted?
Cheers
Vladimir
> rbase = gic_data_rdist_sgi_base();
>
> /* Configure SGIs/PPIs as non-secure Group-1 */
> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> index 9ec3349dee04..5cc10cf7cb3e 100644
> --- a/include/linux/irqchip/arm-gic-v3.h
> +++ b/include/linux/irqchip/arm-gic-v3.h
> @@ -496,6 +496,7 @@
> #define ICC_CTLR_EL1_A3V_SHIFT 15
> #define ICC_CTLR_EL1_A3V_MASK (0x1 << ICC_CTLR_EL1_A3V_SHIFT)
> #define ICC_CTLR_EL1_RSS (0x1 << 18)
> +#define ICC_CTLR_EL1_ExtRange (0x1 << 19)
> #define ICC_PMR_EL1_SHIFT 0
> #define ICC_PMR_EL1_MASK (0xff << ICC_PMR_EL1_SHIFT)
> #define ICC_BPR0_EL1_SHIFT 0
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox