Hi, Alex,

On 2017/2/15 19:53, Alexander Graf wrote:
> 
> 
> On 15/02/2017 12:35, zhichang.yuan wrote:
>> Hi, Alex,
>>
>>
>> On 2017/2/14 21:29, Alexander Graf wrote:
>>>
>>>
>>> On 13/02/2017 15:39, zhichang.yuan wrote:
>>>> Hi, Alex,
>>>>
>>>> Thanks for your review!
>>>>
>>>> John had replied most of your comments, I only mentioned those which 
>>>> haven't made clear.
>>>>
>>>>
>>>> On 2017/1/31 4:08, Alexander Graf wrote:
>>>>>
>>>>>
>>>>> On 24/01/2017 08:05, zhichang.yuan wrote:
>>>>>> The low-pin-count(LPC) interface of Hip06/Hip07 accesses the peripherals 
>>>>>> in
>>>>>> I/O port addresses. This patch implements the LPC host controller driver 
>>>>>> which
>>>>>> perform the I/O operations on the underlying hardware.
>>>>>> We don't want to touch those existing peripherals' driver, such as 
>>>>>> ipmi-bt. So
>>>>>> this driver applies the indirect-IO introduced in the previous patch 
>>>>>> after
>>>>>> registering an indirect-IO node to the indirect-IO devices list which 
>>>>>> will be
>>>>>> searched in the I/O accessors.
>>>>>> As the I/O translations for LPC children depend on the host I/O 
>>>>>> registration,
>>>>>> we should ensure the host I/O registration is finished before all the LPC
>>>>>> children scanning. That is why an arch_init() hook was added in this 
>>>>>> patch.
>>>>>>
>>>>>> Signed-off-by: zhichang.yuan <[email protected]>
>>>>>> Signed-off-by: Gabriele Paoloni <[email protected]>
>>>>>> ---
>> snip
>>>>>> +
>>>>>> +struct lpc_cycle_para {
>>>>>> +    unsigned int opflags;
>>>>>> +    unsigned int csize; /* the data length of each operation */
>>>>>> +};
>>>>>> +
>>>>>> +struct hisilpc_dev {
>>>>>> +    spinlock_t cycle_lock;
>>>>>> +    void __iomem  *membase;
>>>>>> +    struct extio_node *extio;
>>>>>> +};
>>>>>> +
>>>>>> +/* bounds of the LPC bus address range */
>>>>>> +#define LPC_MIN_BUS_RANGE    0x0
>>>>>> +
>>>>>> +/*
>>>>>> + * The maximal IO size for each leagcy bus.
>>>>>
>>>>> legacy?
>>>>>
>>>>> I don't really understand why this bus is legacy though. It looks like a 
>>>>> simple MMIO-to-LPC bridge to me.
>>>>
>>>> yes. The LPC bus is MMIO-to-LPC bridge.
>>>> My comment is not clear.
>>>>
>>>> How about "The maximal IO size of LPC bus"?
>>>
>>> That sounds better, but doesn't really tell me what it's about yet ;).
>>>
>>>>
>>>>>
>>>>>> + * The port size of legacy I/O devices is normally less than 0x400.
>>>>>> + * Defining the I/O range size as 0x400 here should be sufficient for
>>>>>> + * all peripherals under one bus.
>>>>>> + */
>>>>>
>>>>> This comment doesn't make a lot of sense. What is the limit? Is there a 
>>>>> hardware limit?
>>>>>
>>>>> We don't dynamically allocate devices on the lpc bus, so why imply a 
>>>>> limit at all?
>>>>
>>>> The limit here is to define an IO window for LPC.
>>>> It is not acceptable to describe the IO window with 'ranges' property in 
>>>> LPC host node, so we choose a fixable upper IO limit
>>>> for the static LPC IO space. Without this, LPC can't register its IO space 
>>>> through extio helpers.
>>>>
>>>> Why 0x400 is chosen? For our LPC, 0x400 cover all the peripherals under 
>>>> the LPC.
>>>
>>> This is information that should come from firmware then. Whether by 
>>> coincidence addresses 0x0 - 0x400 include all devices is an implementation 
>>> detail that the driver shouldn't have to know about.
>>
>>
>>>
>>> That said, as mentioned elsewhere, we don't need to define single windows 
>>> at all. Instead, can't we just do it like PCI BARs and declare all PIO 
>>> regions we get from firmware as readily allocated? Then we only need to 
>>> explicitly assign ports 0x80, 0x81, 0x99, etc to the LPC bridge and leave 
>>> the rest for grabs (by PCI hotplug for example)
>>>
>>
>> I worry I don't completely catch your idea.
>> From my understanding, each PCI host can parse its resource windows from 
>> firmware(such as ACPI, dts). But for our LPC, firmware configurations only 
>> tell kernel what is the IO resource of the peripherals under LPC. But to 
>> register the io range in the similar way of pci_register_io_range(), at 
>> least, we need to know the IO range size.
>> So, how to know this?
>> There is no similar BAR design in LPC, do we traverse all the peripherals to 
>> calculate that?
> 
> Yes, that's probably the most flexible approach. In fact, I would just 
> traverse all peripherals (or have peripherals call register functions for PIO 
> regions) and then dynamically allocate the PIO space for only those regions. 
> I don't see why you should only have 1 window for your LPC bridge.
> 
> Alternatively you could just have firmware indicate the region size, similar 
> to how it's done for PCI. Whatever you do, don't hard code it in the driver 
> :).
> 
>>
>>
>>>>
>>>>
>>>>
>>>>
>>>>>
>>>>>> +#define LPC_BUS_IO_SIZE        0x400
>>>>>> +
>>>>>> +/* The maximum continuous operations */
>>>>>> +#define LPC_MAX_OPCNT    16
>>>>>> +/* only support IO data unit length is four at maximum */
>>>>>> +#define LPC_MAX_DULEN    4
>> snip
>>>>>> + */
>>>>>> +static int
>>>>>> +hisilpc_target_in(struct hisilpc_dev *lpcdev, struct lpc_cycle_para 
>>>>>> *para,
>>>>>> +          unsigned long ptaddr, unsigned char *buf,
>>>>>> +          unsigned long opcnt)
>>>>>> +{
>>>>>> +    unsigned long cnt_per_trans;
>>>>>> +    unsigned int cmd_word;
>>>>>> +    unsigned int waitcnt;
>>>>>> +    int ret;
>>>>>> +
>>>>>> +    if (!buf || !opcnt || !para || !para->csize || !lpcdev)
>>>>>> +        return -EINVAL;
>>>>>> +
>>>>>> +    if (opcnt  > LPC_MAX_OPCNT)
>>>>>> +        return -EINVAL;
>>>>>> +
>>>>>> +    cmd_word = LPC_CMD_TYPE_IO | LPC_CMD_READ;
>>>>>> +    waitcnt = LPC_PEROP_WAITCNT;
>>>>>> +    if (!(para->opflags & FG_INCRADDR_LPC)) {
>>>>>> +        cmd_word |= LPC_CMD_SAMEADDR;
>>>>>> +        waitcnt = LPC_MAX_WAITCNT;
>>>>>> +    }
>>>>>> +
>>>>>> +    ret = 0;
>>>>>> +    cnt_per_trans = (para->csize == 1) ? opcnt : para->csize;
>>>>>> +    for (; opcnt && !ret; cnt_per_trans = para->csize) {
>>>>>> +        unsigned long flags;
>>>>>> +
>>>>>> +        /* whole operation must be atomic */
>>>>>> +        spin_lock_irqsave(&lpcdev->cycle_lock, flags);
>>>>>
>>>>> Ouch. This is going to kill your RT jitter. Is there no better way?
>>>>
>>>> I think there is no other choices. We have to ensure the I/O cycles 
>>>> triggered in serial mode....
>>>
>>> As nobody else accesses the LPC device in the meantime thanks to the lock, 
>>> you don't need to disable interrupts, right?
>>
>> O. Do you mean that we can replace spin_lock_irqsave with spin_lock?
> 
> That would be a good step into the right direction I think, yes.
> 
>> As we can connect UART to LPC, I worry the LPC can be accessed in the 
>> interrupt context.
> 
> In that case IRQs are already disabled for the non-preempt-rt case and in 
> preempt-rt, interrupt context should mostly live in threads which are 
> preemptible again.
> 

When the IRQs are disabled? Do you mean the interrupt disable just before 
kernel enters the interrupt routine?
It seems this processing can not protect a thread which had owned the LPC spin 
lock from being preempted.


Zhichang

> 
> Alex
> 
> .
> 

Reply via email to