It seems that the picture is too big, I change it from jpg to png.

On 2019/3/1 17:02, Leizhen (ThunderTown) wrote:
> Hi All,
>     I drew a flowchart, hope this can help you to understand my method.
> 
> On 2019/2/19 15:54, Zhen Lei wrote:
>> To reduce the risk of further crash, the device_shutdown() was not called
>> by the first kernel. That means some devices may still working in the
>> secondary kernel. For example, a netcard may still using ring buffer to
>> receive the broadcast messages in the kdump kernel. No events are reported
>> utill the related smmu reinitialized by the kdump kernel.
>>
>> commit b63b3439b856 ("iommu/arm-smmu-v3: Abort all transactions if SMMU is
>> enabled in kdump kernel") set SMMU_GBPA.ABORT to prevent the unexpected
>> devices accessing, but it also prevent the devices accessing which we
>> needed, like hard disk, netcard.
>>
>> In fact, we can use STE.config=0b000 to abort the unexpected devices
>> accessing only. As below:
>> 1. In the first kernel, all buffers used by the "unexpected" devices are
>>    correctly mapped, and it will not be used by the secondary kernel
>>    because the latter has its dedicated reserved memory.
>> 2. In the secondary kernel, set SMMU_GBPA.ABORT=1 before "disable smmu".
>> 3. In the secondary kernel, after the smmu was disabled, preset all
>>    STE.config=0b000. For 2-level Stream Table, make all L1STD.l2ptr
>>    pointer to a dummy L2ST. The dummy L2ST is shared by all L1STDs.
>> 4. In the secondary kernel, enable smmu. For the needed devices, allocate
>>    new L2STs accordingly.
>>
>> For phase 1 and 2, the unexpected devices base the old mapping access
>> memory, it will not corrupt others. For phase 3, SMMU_GBPA abort it. For
>> phase 4 STE abort it.
>>
>> Fixes: commit b63b3439b856 ("iommu/arm-smmu-v3: Abort all transactions ...")
>> Signed-off-by: Zhen Lei <thunder.leiz...@huawei.com>
>> ---
>>  drivers/iommu/arm-smmu-v3.c | 72 
>> ++++++++++++++++++++++++++++++++-------------
>>  1 file changed, 51 insertions(+), 21 deletions(-)
>>
>> diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
>> index 2072897..c3c4ff2 100644
>> --- a/drivers/iommu/arm-smmu-v3.c
>> +++ b/drivers/iommu/arm-smmu-v3.c
>> @@ -1219,35 +1219,57 @@ static void arm_smmu_init_bypass_stes(u64 *strtab, 
>> unsigned int nent)
>>      }
>>  }
>>
>> -static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid)
>> +static int __arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid,
>> +                                 struct arm_smmu_strtab_l1_desc *desc)
>>  {
>> -    size_t size;
>>      void *strtab;
>>      struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
>> -    struct arm_smmu_strtab_l1_desc *desc = &cfg->l1_desc[sid >> 
>> STRTAB_SPLIT];
>>
>> -    if (desc->l2ptr)
>> -            return 0;
>> -
>> -    size = 1 << (STRTAB_SPLIT + ilog2(STRTAB_STE_DWORDS) + 3);
>>      strtab = &cfg->strtab[(sid >> STRTAB_SPLIT) * STRTAB_L1_DESC_DWORDS];
>>
>> -    desc->span = STRTAB_SPLIT + 1;
>> -    desc->l2ptr = dmam_alloc_coherent(smmu->dev, size, &desc->l2ptr_dma,
>> -                                      GFP_KERNEL | __GFP_ZERO);
>>      if (!desc->l2ptr) {
>> -            dev_err(smmu->dev,
>> -                    "failed to allocate l2 stream table for SID %u\n",
>> -                    sid);
>> -            return -ENOMEM;
>> +            size_t size;
>> +
>> +            size = 1 << (STRTAB_SPLIT + ilog2(STRTAB_STE_DWORDS) + 3);
>> +            desc->l2ptr = dmam_alloc_coherent(smmu->dev, size,
>> +                                              &desc->l2ptr_dma,
>> +                                              GFP_KERNEL | __GFP_ZERO);
>> +            if (!desc->l2ptr) {
>> +                    dev_err(smmu->dev,
>> +                            "failed to allocate l2 stream table for SID 
>> %u\n",
>> +                            sid);
>> +                    return -ENOMEM;
>> +            }
>> +
>> +            desc->span = STRTAB_SPLIT + 1;
>> +            arm_smmu_init_bypass_stes(desc->l2ptr, 1 << STRTAB_SPLIT);
>>      }
>>
>> -    arm_smmu_init_bypass_stes(desc->l2ptr, 1 << STRTAB_SPLIT);
>>      arm_smmu_write_strtab_l1_desc(strtab, desc);
>> +    return 0;
>> +}
>> +
>> +static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid)
>> +{
>> +    int ret;
>> +    struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
>> +    struct arm_smmu_strtab_l1_desc *desc = &cfg->l1_desc[sid >> 
>> STRTAB_SPLIT];
>> +
>> +    ret = __arm_smmu_init_l2_strtab(smmu, sid, desc);
>> +    if (ret)
>> +            return ret;
>> +
>>      arm_smmu_sync_std_for_sid(smmu, sid);
>>      return 0;
>>  }
>>
>> +static int arm_smmu_init_dummy_l2_strtab(struct arm_smmu_device *smmu, u32 
>> sid)
>> +{
>> +    static struct arm_smmu_strtab_l1_desc dummy_desc;
>> +
>> +    return __arm_smmu_init_l2_strtab(smmu, sid, &dummy_desc);
>> +}
>> +
>>  /* IRQ and event handlers */
>>  static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
>>  {
>> @@ -2150,8 +2172,12 @@ static int arm_smmu_init_l1_strtab(struct 
>> arm_smmu_device *smmu)
>>      }
>>
>>      for (i = 0; i < cfg->num_l1_ents; ++i) {
>> -            arm_smmu_write_strtab_l1_desc(strtab, &cfg->l1_desc[i]);
>> -            strtab += STRTAB_L1_DESC_DWORDS << 3;
>> +            if (is_kdump_kernel()) {
>> +                    arm_smmu_init_dummy_l2_strtab(smmu, i << STRTAB_SPLIT);
>> +            } else {
>> +                    arm_smmu_write_strtab_l1_desc(strtab, &cfg->l1_desc[i]);
>> +                    strtab += STRTAB_L1_DESC_DWORDS << 3;
>> +            }
>>      }
>>
>>      return 0;
>> @@ -2467,11 +2493,8 @@ static int arm_smmu_device_reset(struct 
>> arm_smmu_device *smmu, bool bypass)
>>      /* Clear CR0 and sync (disables SMMU and queue processing) */
>>      reg = readl_relaxed(smmu->base + ARM_SMMU_CR0);
>>      if (reg & CR0_SMMUEN) {
>> -            if (is_kdump_kernel()) {
>> +            if (is_kdump_kernel())
>>                      arm_smmu_update_gbpa(smmu, GBPA_ABORT, 0);
>> -                    arm_smmu_device_disable(smmu);
>> -                    return -EBUSY;
>> -            }
>>
>>              dev_warn(smmu->dev, "SMMU currently enabled! Resetting...\n");
>>      }
>> @@ -2859,6 +2882,13 @@ static int arm_smmu_device_probe(struct 
>> platform_device *pdev)
>>      struct device *dev = &pdev->dev;
>>      bool bypass;
>>
>> +    /*
>> +     * Force to disable bypass for the kdump kernel, abort all incoming
>> +     * transactions from the unknown devices.
>> +     */
>> +    if (is_kdump_kernel())
>> +            disable_bypass = 1;
>> +
>>      smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL);
>>      if (!smmu) {
>>              dev_err(dev, "failed to allocate arm_smmu_device\n");
>> --
>> 1.8.3
>>
>>
>>
>> .
>>
> 

-- 
Thanks!
BestRegards
_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Reply via email to