* [powerpc:merge] BUILD SUCCESS 78e00acdd35c0ada7c7d83eab11df0468cc602b7
From: kernel test robot @ 2021-12-08 6:21 UTC (permalink / raw)
To: Michael Ellerman; +Cc: linuxppc-dev
tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git merge
branch HEAD: 78e00acdd35c0ada7c7d83eab11df0468cc602b7 Automatic merge of 'master' into merge (2021-12-03 22:55)
elapsed time: 6754m
configs tested: 349
configs skipped: 4
The following configs have been built successfully.
More configs may be tested in the coming days.
gcc tested configs:
arm defconfig
arm64 defconfig
arm allyesconfig
arm allmodconfig
arm64 allyesconfig
mips randconfig-c004-20211203
i386 randconfig-c001-20211203
i386 randconfig-c001-20211207
i386 randconfig-c001-20211206
mips ip27_defconfig
sh r7780mp_defconfig
powerpc tqm5200_defconfig
powerpc asp8347_defconfig
arm xcep_defconfig
arm clps711x_defconfig
alpha alldefconfig
ia64 bigsur_defconfig
sh shx3_defconfig
arc vdk_hs38_defconfig
sh landisk_defconfig
arm imx_v6_v7_defconfig
arm tegra_defconfig
powerpc storcenter_defconfig
arm imote2_defconfig
powerpc adder875_defconfig
m68k m5208evb_defconfig
s390 allyesconfig
powerpc arches_defconfig
powerpc mpc5200_defconfig
sh rts7751r2d1_defconfig
s390 defconfig
nios2 defconfig
arm shannon_defconfig
powerpc mpc8540_ads_defconfig
sh edosk7760_defconfig
powerpc tqm8555_defconfig
openrisc or1ksim_defconfig
x86_64 allyesconfig
arm trizeps4_defconfig
arc axs101_defconfig
m68k m5407c3_defconfig
mips maltaup_defconfig
sparc sparc64_defconfig
mips vocore2_defconfig
arc allyesconfig
sh hp6xx_defconfig
arm pxa3xx_defconfig
sh alldefconfig
nios2 10m50_defconfig
powerpc ppa8548_defconfig
openrisc alldefconfig
sh sh7785lcr_defconfig
riscv nommu_k210_defconfig
arm cns3420vb_defconfig
sparc64 defconfig
m68k mac_defconfig
arm multi_v5_defconfig
arm ixp4xx_defconfig
powerpc mpc866_ads_defconfig
sh kfr2r09_defconfig
powerpc mpc834x_itx_defconfig
sh rsk7269_defconfig
arc nsim_700_defconfig
arm s5pv210_defconfig
arm axm55xx_defconfig
powerpc mpc832x_rdb_defconfig
m68k atari_defconfig
powerpc tqm8560_defconfig
sh sh7710voipgw_defconfig
arm mxs_defconfig
powerpc taishan_defconfig
arm omap2plus_defconfig
arm lpc32xx_defconfig
arm aspeed_g5_defconfig
powerpc cm5200_defconfig
powerpc skiroot_defconfig
arm sunxi_defconfig
arm colibri_pxa300_defconfig
i386 alldefconfig
mips qi_lb60_defconfig
mips tb0226_defconfig
powerpc tqm8541_defconfig
arm ep93xx_defconfig
arm badge4_defconfig
arc nsimosci_hs_defconfig
powerpc linkstation_defconfig
powerpc gamecube_defconfig
powerpc tqm8xx_defconfig
powerpc walnut_defconfig
ia64 tiger_defconfig
xtensa common_defconfig
powerpc akebono_defconfig
arm pxa_defconfig
powerpc holly_defconfig
arm keystone_defconfig
xtensa audio_kc705_defconfig
powerpc g5_defconfig
powerpc katmai_defconfig
arm neponset_defconfig
arm integrator_defconfig
powerpc kilauea_defconfig
arm imx_v4_v5_defconfig
arm sama7_defconfig
powerpc powernv_defconfig
arm orion5x_defconfig
arm zeus_defconfig
arm vf610m4_defconfig
arm multi_v7_defconfig
mips workpad_defconfig
sh espt_defconfig
arm footbridge_defconfig
powerpc acadia_defconfig
sh sh7724_generic_defconfig
powerpc socrates_defconfig
sh se7712_defconfig
arm stm32_defconfig
sh se7780_defconfig
xtensa generic_kc705_defconfig
arm ezx_defconfig
sh microdev_defconfig
powerpc canyonlands_defconfig
arm jornada720_defconfig
powerpc ge_imp3a_defconfig
m68k apollo_defconfig
h8300 edosk2674_defconfig
sh titan_defconfig
sh secureedge5410_defconfig
powerpc ppc64_defconfig
m68k multi_defconfig
arc nsimosci_hs_smp_defconfig
arm lpd270_defconfig
arm oxnas_v6_defconfig
powerpc mpc836x_mds_defconfig
sh polaris_defconfig
powerpc mgcoge_defconfig
arm s3c6400_defconfig
sh se7721_defconfig
powerpc chrp32_defconfig
mips mtx1_defconfig
sh r7785rp_defconfig
arm lubbock_defconfig
mips mpc30x_defconfig
powerpc sequoia_defconfig
sparc64 alldefconfig
powerpc ppc40x_defconfig
s390 zfcpdump_defconfig
sh sh7757lcr_defconfig
um x86_64_defconfig
arm qcom_defconfig
powerpc mpc8272_ads_defconfig
arm mvebu_v5_defconfig
arm mps2_defconfig
sh se7705_defconfig
m68k q40_defconfig
arm cm_x300_defconfig
powerpc amigaone_defconfig
powerpc mpc83xx_defconfig
m68k sun3_defconfig
sh ul2_defconfig
arm vt8500_v6_v7_defconfig
i386 allyesconfig
arc haps_hs_smp_defconfig
m68k m5307c3_defconfig
arc haps_hs_defconfig
arm moxart_defconfig
h8300 h8300h-sim_defconfig
powerpc mpc512x_defconfig
arm aspeed_g4_defconfig
sparc alldefconfig
powerpc warp_defconfig
microblaze defconfig
sh apsh4a3a_defconfig
sh migor_defconfig
powerpc pq2fads_defconfig
powerpc mpc832x_mds_defconfig
powerpc currituck_defconfig
sh rsk7201_defconfig
arm h5000_defconfig
powerpc tqm8548_defconfig
arm randconfig-c002-20211207
arm randconfig-c002-20211205
arm randconfig-c002-20211206
arm randconfig-c002-20211203
ia64 allmodconfig
ia64 defconfig
ia64 allyesconfig
m68k allmodconfig
m68k defconfig
m68k allyesconfig
nds32 allnoconfig
nds32 defconfig
nios2 allyesconfig
csky defconfig
alpha defconfig
alpha allyesconfig
xtensa allyesconfig
h8300 allyesconfig
arc defconfig
sh allmodconfig
parisc defconfig
s390 allmodconfig
parisc allyesconfig
sparc allyesconfig
sparc defconfig
i386 defconfig
i386 debian-10.3-kselftests
i386 debian-10.3
mips allyesconfig
mips allmodconfig
powerpc allyesconfig
powerpc allmodconfig
powerpc allnoconfig
x86_64 randconfig-a006-20211203
x86_64 randconfig-a005-20211203
x86_64 randconfig-a001-20211203
x86_64 randconfig-a002-20211203
x86_64 randconfig-a004-20211203
x86_64 randconfig-a003-20211203
x86_64 randconfig-a006-20211207
x86_64 randconfig-a005-20211207
x86_64 randconfig-a001-20211207
x86_64 randconfig-a002-20211207
x86_64 randconfig-a004-20211207
x86_64 randconfig-a003-20211207
x86_64 randconfig-a006-20211205
x86_64 randconfig-a005-20211205
x86_64 randconfig-a001-20211205
x86_64 randconfig-a002-20211205
x86_64 randconfig-a004-20211205
x86_64 randconfig-a003-20211205
i386 randconfig-a001-20211205
i386 randconfig-a005-20211205
i386 randconfig-a003-20211205
i386 randconfig-a002-20211205
i386 randconfig-a006-20211205
i386 randconfig-a004-20211205
i386 randconfig-a001-20211203
i386 randconfig-a005-20211203
i386 randconfig-a002-20211203
i386 randconfig-a003-20211203
i386 randconfig-a006-20211203
i386 randconfig-a004-20211203
i386 randconfig-a002-20211207
i386 randconfig-a003-20211207
i386 randconfig-a004-20211207
i386 randconfig-a001-20211207
i386 randconfig-a005-20211207
i386 randconfig-a006-20211207
x86_64 randconfig-a016-20211206
x86_64 randconfig-a011-20211206
x86_64 randconfig-a013-20211206
x86_64 randconfig-a014-20211206
x86_64 randconfig-a012-20211206
x86_64 randconfig-a015-20211206
i386 randconfig-a016-20211206
i386 randconfig-a013-20211206
i386 randconfig-a011-20211206
i386 randconfig-a014-20211206
i386 randconfig-a012-20211206
i386 randconfig-a015-20211206
i386 randconfig-a013-20211204
i386 randconfig-a016-20211204
i386 randconfig-a011-20211204
i386 randconfig-a014-20211204
i386 randconfig-a012-20211204
i386 randconfig-a015-20211204
arc randconfig-r043-20211207
riscv allyesconfig
riscv nommu_virt_defconfig
riscv allnoconfig
riscv defconfig
riscv rv32_defconfig
riscv allmodconfig
um i386_defconfig
x86_64 rhel-8.3-kselftests
x86_64 defconfig
x86_64 rhel-8.3
x86_64 rhel-8.3-func
x86_64 kexec
clang tested configs:
x86_64 randconfig-c007-20211205
arm randconfig-c002-20211205
riscv randconfig-c006-20211205
mips randconfig-c004-20211205
i386 randconfig-c001-20211205
powerpc randconfig-c003-20211205
s390 randconfig-c005-20211205
x86_64 randconfig-a006-20211206
x86_64 randconfig-a005-20211206
x86_64 randconfig-a001-20211206
x86_64 randconfig-a002-20211206
x86_64 randconfig-a004-20211206
x86_64 randconfig-a003-20211206
x86_64 randconfig-a006-20211204
x86_64 randconfig-a005-20211204
x86_64 randconfig-a001-20211204
x86_64 randconfig-a002-20211204
x86_64 randconfig-a004-20211204
x86_64 randconfig-a003-20211204
i386 randconfig-a001-20211206
i386 randconfig-a005-20211206
i386 randconfig-a002-20211206
i386 randconfig-a003-20211206
i386 randconfig-a006-20211206
i386 randconfig-a004-20211206
x86_64 randconfig-a016-20211203
x86_64 randconfig-a011-20211203
x86_64 randconfig-a013-20211203
x86_64 randconfig-a014-20211203
x86_64 randconfig-a015-20211203
x86_64 randconfig-a012-20211203
x86_64 randconfig-a016-20211205
x86_64 randconfig-a011-20211205
x86_64 randconfig-a013-20211205
x86_64 randconfig-a015-20211205
x86_64 randconfig-a012-20211205
x86_64 randconfig-a014-20211205
i386 randconfig-a016-20211203
i386 randconfig-a013-20211203
i386 randconfig-a011-20211203
i386 randconfig-a014-20211203
i386 randconfig-a012-20211203
i386 randconfig-a015-20211203
i386 randconfig-a013-20211205
i386 randconfig-a016-20211205
i386 randconfig-a011-20211205
i386 randconfig-a014-20211205
i386 randconfig-a012-20211205
i386 randconfig-a015-20211205
i386 randconfig-a013-20211207
i386 randconfig-a011-20211207
i386 randconfig-a012-20211207
i386 randconfig-a016-20211207
i386 randconfig-a015-20211207
i386 randconfig-a014-20211207
hexagon randconfig-r045-20211203
s390 randconfig-r044-20211203
hexagon randconfig-r041-20211203
riscv randconfig-r042-20211203
hexagon randconfig-r045-20211206
hexagon randconfig-r041-20211206
hexagon randconfig-r045-20211204
hexagon randconfig-r041-20211204
hexagon randconfig-r045-20211205
s390 randconfig-r044-20211205
riscv randconfig-r042-20211205
hexagon randconfig-r041-20211205
hexagon randconfig-r045-20211207
s390 randconfig-r044-20211207
hexagon randconfig-r041-20211207
riscv randconfig-r042-20211207
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
^ permalink raw reply
* linux-next: manual merge of the bitmap tree with the powerpc tree
From: Stephen Rothwell @ 2021-12-08 5:31 UTC (permalink / raw)
To: Yury Norov, Michael Ellerman, PowerPC
Cc: Linux Next Mailing List, Linux Kernel Mailing List,
Nicholas Piggin
[-- Attachment #1: Type: text/plain, Size: 836 bytes --]
Hi all,
Today's linux-next merge of the bitmap tree got a conflict in:
arch/powerpc/include/asm/cputhreads.h
between commit:
b350111bf7b3 ("powerpc: remove cpu_online_cores_map function")
from the powerpc tree and commit:
4e258d05437b ("cpumask: replace cpumask_next_* with cpumask_first_* where appropriate")
from the bitmap tree.
I fixed it up (the former removed the code updated by the latter, so I
just used that) and can carry the fix as necessary. This is now fixed
as far as linux-next is concerned, but any non trivial conflicts should
be mentioned to your upstream maintainer when your tree is submitted for
merging. You may also want to consider cooperating with the maintainer
of the conflicting tree to minimise any particularly complex conflicts.
--
Cheers,
Stephen Rothwell
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Re: [PATCH V2 1/2] tools/perf: Include global and local variants for p_stage_cyc sort key
From: Nageswara Sastry @ 2021-12-08 3:51 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo, Athira Rajeev
Cc: maddy, linux-perf-users, jolsa, kjain, namhyung, linuxppc-dev
In-Reply-To: <Ya91LXxp13Nz3JyC@kernel.org>
On 07/12/21 8:22 pm, Arnaldo Carvalho de Melo wrote:
> Em Fri, Dec 03, 2021 at 07:50:37AM +0530, Athira Rajeev escreveu:
>> Sort key p_stage_cyc is used to present the latency
>> cycles spend in pipeline stages. perf tool has local
>> p_stage_cyc sort key to display this info. There is no
>> global variant available for this sort key. local variant
>> shows latency in a sinlge sample, whereas, global value
>> will be useful to present the total latency (sum of
>> latencies) in the hist entry. It represents latency
>> number multiplied by the number of samples.
>>
>> Add global (p_stage_cyc) and local variant
>> (local_p_stage_cyc) for this sort key. Use the
>> local_p_stage_cyc as default option for "mem" sort mode.
>> Also add this to list of dynamic sort keys and made the
>> "dynamic_headers" and "arch_specific_sort_keys" as static.
>>
>> Signed-off-by: Athira Rajeev <atrajeev@linux.vnet.ibm.com>
>> Reported-by: Namhyung Kim <namhyung@kernel.org>
>
> I got this for v1, does it stand for v2?
>
> Tested-by: Nageswara R Sastry <rnsastry@linux.ibm.com>
Tested with v2 also.
Tested-by: Nageswara R Sastry <rnsastry@linux.ibm.com>
>
>> ---
>> Changelog:
>> v1 -> v2:
>> Addressed review comments from Jiri by making the
>> "dynamic_headers" and "arch_specific_sort_keys"
>> as static.
>>
>> tools/perf/util/hist.c | 4 +++-
>> tools/perf/util/hist.h | 3 ++-
>> tools/perf/util/sort.c | 34 +++++++++++++++++++++++++---------
>> tools/perf/util/sort.h | 3 ++-
>> 4 files changed, 32 insertions(+), 12 deletions(-)
>>
>> diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
>> index b776465e04ef..0a8033b09e28 100644
>> --- a/tools/perf/util/hist.c
>> +++ b/tools/perf/util/hist.c
>> @@ -211,7 +211,9 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
>> hists__new_col_len(hists, HISTC_MEM_BLOCKED, 10);
>> hists__new_col_len(hists, HISTC_LOCAL_INS_LAT, 13);
>> hists__new_col_len(hists, HISTC_GLOBAL_INS_LAT, 13);
>> - hists__new_col_len(hists, HISTC_P_STAGE_CYC, 13);
>> + hists__new_col_len(hists, HISTC_LOCAL_P_STAGE_CYC, 13);
>> + hists__new_col_len(hists, HISTC_GLOBAL_P_STAGE_CYC, 13);
>> +
>> if (symbol_conf.nanosecs)
>> hists__new_col_len(hists, HISTC_TIME, 16);
>> else
>> diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
>> index 621f35ae1efa..2a15e22fb89c 100644
>> --- a/tools/perf/util/hist.h
>> +++ b/tools/perf/util/hist.h
>> @@ -75,7 +75,8 @@ enum hist_column {
>> HISTC_MEM_BLOCKED,
>> HISTC_LOCAL_INS_LAT,
>> HISTC_GLOBAL_INS_LAT,
>> - HISTC_P_STAGE_CYC,
>> + HISTC_LOCAL_P_STAGE_CYC,
>> + HISTC_GLOBAL_P_STAGE_CYC,
>> HISTC_NR_COLS, /* Last entry */
>> };
>>
>> diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
>> index a111065b484e..e417e47f51b9 100644
>> --- a/tools/perf/util/sort.c
>> +++ b/tools/perf/util/sort.c
>> @@ -37,7 +37,7 @@ const char default_parent_pattern[] = "^sys_|^do_page_fault";
>> const char *parent_pattern = default_parent_pattern;
>> const char *default_sort_order = "comm,dso,symbol";
>> const char default_branch_sort_order[] = "comm,dso_from,symbol_from,symbol_to,cycles";
>> -const char default_mem_sort_order[] = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked,blocked,local_ins_lat,p_stage_cyc";
>> +const char default_mem_sort_order[] = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked,blocked,local_ins_lat,local_p_stage_cyc";
>> const char default_top_sort_order[] = "dso,symbol";
>> const char default_diff_sort_order[] = "dso,symbol";
>> const char default_tracepoint_sort_order[] = "trace";
>> @@ -46,8 +46,8 @@ const char *field_order;
>> regex_t ignore_callees_regex;
>> int have_ignore_callees = 0;
>> enum sort_mode sort__mode = SORT_MODE__NORMAL;
>> -const char *dynamic_headers[] = {"local_ins_lat", "p_stage_cyc"};
>> -const char *arch_specific_sort_keys[] = {"p_stage_cyc"};
>> +static const char *const dynamic_headers[] = {"local_ins_lat", "ins_lat", "local_p_stage_cyc", "p_stage_cyc"};
>> +static const char *const arch_specific_sort_keys[] = {"local_p_stage_cyc", "p_stage_cyc"};
>>
>> /*
>> * Replaces all occurrences of a char used with the:
>> @@ -1392,22 +1392,37 @@ struct sort_entry sort_global_ins_lat = {
>> };
>>
>> static int64_t
>> -sort__global_p_stage_cyc_cmp(struct hist_entry *left, struct hist_entry *right)
>> +sort__p_stage_cyc_cmp(struct hist_entry *left, struct hist_entry *right)
>> {
>> return left->p_stage_cyc - right->p_stage_cyc;
>> }
>>
>> +static int hist_entry__global_p_stage_cyc_snprintf(struct hist_entry *he, char *bf,
>> + size_t size, unsigned int width)
>> +{
>> + return repsep_snprintf(bf, size, "%-*u", width,
>> + he->p_stage_cyc * he->stat.nr_events);
>> +}
>> +
>> +
>> static int hist_entry__p_stage_cyc_snprintf(struct hist_entry *he, char *bf,
>> size_t size, unsigned int width)
>> {
>> return repsep_snprintf(bf, size, "%-*u", width, he->p_stage_cyc);
>> }
>>
>> -struct sort_entry sort_p_stage_cyc = {
>> - .se_header = "Pipeline Stage Cycle",
>> - .se_cmp = sort__global_p_stage_cyc_cmp,
>> +struct sort_entry sort_local_p_stage_cyc = {
>> + .se_header = "Local Pipeline Stage Cycle",
>> + .se_cmp = sort__p_stage_cyc_cmp,
>> .se_snprintf = hist_entry__p_stage_cyc_snprintf,
>> - .se_width_idx = HISTC_P_STAGE_CYC,
>> + .se_width_idx = HISTC_LOCAL_P_STAGE_CYC,
>> +};
>> +
>> +struct sort_entry sort_global_p_stage_cyc = {
>> + .se_header = "Pipeline Stage Cycle",
>> + .se_cmp = sort__p_stage_cyc_cmp,
>> + .se_snprintf = hist_entry__global_p_stage_cyc_snprintf,
>> + .se_width_idx = HISTC_GLOBAL_P_STAGE_CYC,
>> };
>>
>> struct sort_entry sort_mem_daddr_sym = {
>> @@ -1858,7 +1873,8 @@ static struct sort_dimension common_sort_dimensions[] = {
>> DIM(SORT_CODE_PAGE_SIZE, "code_page_size", sort_code_page_size),
>> DIM(SORT_LOCAL_INS_LAT, "local_ins_lat", sort_local_ins_lat),
>> DIM(SORT_GLOBAL_INS_LAT, "ins_lat", sort_global_ins_lat),
>> - DIM(SORT_PIPELINE_STAGE_CYC, "p_stage_cyc", sort_p_stage_cyc),
>> + DIM(SORT_LOCAL_PIPELINE_STAGE_CYC, "local_p_stage_cyc", sort_local_p_stage_cyc),
>> + DIM(SORT_GLOBAL_PIPELINE_STAGE_CYC, "p_stage_cyc", sort_global_p_stage_cyc),
>> };
>>
>> #undef DIM
>> diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
>> index 7b7145501933..f994261888e1 100644
>> --- a/tools/perf/util/sort.h
>> +++ b/tools/perf/util/sort.h
>> @@ -235,7 +235,8 @@ enum sort_type {
>> SORT_CODE_PAGE_SIZE,
>> SORT_LOCAL_INS_LAT,
>> SORT_GLOBAL_INS_LAT,
>> - SORT_PIPELINE_STAGE_CYC,
>> + SORT_LOCAL_PIPELINE_STAGE_CYC,
>> + SORT_GLOBAL_PIPELINE_STAGE_CYC,
>>
>> /* branch stack specific sort keys */
>> __SORT_BRANCH_STACK,
>> --
>> 2.33.0
>
--
Thanks and Regards
R.Nageswara Sastry
^ permalink raw reply
* [powerpc:next-test] BUILD SUCCESS 27918f696e421df5b71d65d416a621bcd5c5fee2
From: kernel test robot @ 2021-12-08 2:20 UTC (permalink / raw)
To: Michael Ellerman; +Cc: linuxppc-dev
tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git next-test
branch HEAD: 27918f696e421df5b71d65d416a621bcd5c5fee2 mpe hash fixups
elapsed time: 732m
configs tested: 144
configs skipped: 3
The following configs have been built successfully.
More configs may be tested in the coming days.
gcc tested configs:
arm defconfig
arm64 allyesconfig
arm64 defconfig
arm allyesconfig
arm allmodconfig
i386 randconfig-c001-20211207
m68k alldefconfig
arc tb10x_defconfig
arm tegra_defconfig
powerpc mpc837x_rdb_defconfig
h8300 edosk2674_defconfig
mips rs90_defconfig
mips maltasmvp_defconfig
h8300 allyesconfig
mips tb0287_defconfig
sh defconfig
powerpc mvme5100_defconfig
sh shmin_defconfig
mips bcm63xx_defconfig
sh se7705_defconfig
mips xway_defconfig
powerpc cm5200_defconfig
sparc64 defconfig
powerpc wii_defconfig
powerpc motionpro_defconfig
parisc alldefconfig
arm h3600_defconfig
mips loongson3_defconfig
sh sh7785lcr_32bit_defconfig
mips ip22_defconfig
arm omap1_defconfig
powerpc holly_defconfig
arm pxa255-idp_defconfig
sh rts7751r2dplus_defconfig
mips workpad_defconfig
sh espt_defconfig
arm footbridge_defconfig
powerpc acadia_defconfig
sh sh7710voipgw_defconfig
sh se7721_defconfig
arm mvebu_v7_defconfig
riscv nommu_k210_sdcard_defconfig
sh ecovec24_defconfig
arm orion5x_defconfig
sh se7780_defconfig
powerpc tqm8xx_defconfig
mips db1xxx_defconfig
parisc generic-64bit_defconfig
sparc64 alldefconfig
arm mv78xx0_defconfig
mips ath79_defconfig
arm pcm027_defconfig
m68k sun3x_defconfig
m68k m5272c3_defconfig
powerpc powernv_defconfig
arc axs103_smp_defconfig
mips cu1000-neo_defconfig
arm cerfcube_defconfig
arm colibri_pxa270_defconfig
powerpc ppa8548_defconfig
m68k q40_defconfig
nds32 allnoconfig
nios2 allyesconfig
powerpc tqm8548_defconfig
sh sh7757lcr_defconfig
sh kfr2r09-romimage_defconfig
arm at91_dt_defconfig
sparc defconfig
mips rbtx49xx_defconfig
xtensa nommu_kc705_defconfig
arm randconfig-c002-20211207
ia64 allmodconfig
ia64 defconfig
ia64 allyesconfig
m68k allmodconfig
m68k defconfig
m68k allyesconfig
nios2 defconfig
arc allyesconfig
nds32 defconfig
csky defconfig
alpha defconfig
alpha allyesconfig
xtensa allyesconfig
arc defconfig
sh allmodconfig
parisc defconfig
s390 allyesconfig
s390 allmodconfig
parisc allyesconfig
s390 defconfig
i386 allyesconfig
sparc allyesconfig
i386 defconfig
i386 debian-10.3-kselftests
i386 debian-10.3
mips allyesconfig
mips allmodconfig
powerpc allyesconfig
powerpc allmodconfig
powerpc allnoconfig
i386 randconfig-a001-20211207
i386 randconfig-a005-20211207
i386 randconfig-a002-20211207
i386 randconfig-a003-20211207
i386 randconfig-a006-20211207
i386 randconfig-a004-20211207
x86_64 randconfig-a006-20211207
x86_64 randconfig-a005-20211207
x86_64 randconfig-a001-20211207
x86_64 randconfig-a002-20211207
x86_64 randconfig-a004-20211207
x86_64 randconfig-a003-20211207
riscv nommu_k210_defconfig
riscv allyesconfig
riscv nommu_virt_defconfig
riscv allnoconfig
riscv defconfig
riscv rv32_defconfig
riscv allmodconfig
um x86_64_defconfig
um i386_defconfig
x86_64 allyesconfig
x86_64 rhel-8.3-kselftests
x86_64 defconfig
x86_64 rhel-8.3
x86_64 rhel-8.3-func
x86_64 kexec
clang tested configs:
x86_64 randconfig-a016-20211207
x86_64 randconfig-a011-20211207
x86_64 randconfig-a013-20211207
x86_64 randconfig-a014-20211207
x86_64 randconfig-a015-20211207
x86_64 randconfig-a012-20211207
i386 randconfig-a016-20211207
i386 randconfig-a013-20211207
i386 randconfig-a011-20211207
i386 randconfig-a014-20211207
i386 randconfig-a012-20211207
i386 randconfig-a015-20211207
hexagon randconfig-r045-20211207
s390 randconfig-r044-20211207
riscv randconfig-r042-20211207
hexagon randconfig-r041-20211207
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
^ permalink raw reply
* [powerpc:topic/ppc-kvm] BUILD SUCCESS 792020907b11c6f9246c21977cab3bad985ae4b6
From: kernel test robot @ 2021-12-08 2:20 UTC (permalink / raw)
To: Michael Ellerman; +Cc: linuxppc-dev
tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git topic/ppc-kvm
branch HEAD: 792020907b11c6f9246c21977cab3bad985ae4b6 KVM: PPC: Book3S: Suppress failed alloc warning in H_COPY_TOFROM_GUEST
elapsed time: 6508m
configs tested: 441
configs skipped: 4
The following configs have been built successfully.
More configs may be tested in the coming days.
gcc tested configs:
arm defconfig
arm64 allyesconfig
arm64 defconfig
arm allyesconfig
arm allmodconfig
mips randconfig-c004-20211203
i386 randconfig-c001-20211203
i386 randconfig-c001-20211206
i386 randconfig-c001-20211207
arm shannon_defconfig
powerpc pq2fads_defconfig
powerpc gamecube_defconfig
powerpc ppc40x_defconfig
arm integrator_defconfig
arm axm55xx_defconfig
sh microdev_defconfig
mips loongson1c_defconfig
s390 allmodconfig
sh sh7710voipgw_defconfig
powerpc iss476-smp_defconfig
xtensa generic_kc705_defconfig
nds32 defconfig
mips pic32mzda_defconfig
arm64 alldefconfig
powerpc g5_defconfig
m68k alldefconfig
arc tb10x_defconfig
arm tegra_defconfig
powerpc mpc837x_rdb_defconfig
csky defconfig
sh se7750_defconfig
powerpc chrp32_defconfig
sh urquell_defconfig
sh se7751_defconfig
um i386_defconfig
mips gpr_defconfig
powerpc adder875_defconfig
m68k m5208evb_defconfig
powerpc arches_defconfig
s390 allyesconfig
powerpc mpc8540_ads_defconfig
mips fuloong2e_defconfig
sh edosk7760_defconfig
powerpc tqm8555_defconfig
openrisc or1ksim_defconfig
powerpc powernv_defconfig
m68k amiga_defconfig
powerpc fsp2_defconfig
ia64 zx1_defconfig
m68k allyesconfig
arc axs101_defconfig
m68k m5407c3_defconfig
mips maltaup_defconfig
sparc sparc64_defconfig
mips vocore2_defconfig
arm clps711x_defconfig
arc allyesconfig
sh hp6xx_defconfig
mips ath79_defconfig
arm eseries_pxa_defconfig
arm bcm2835_defconfig
m68k m5307c3_defconfig
arm sama5_defconfig
sh ul2_defconfig
mips workpad_defconfig
m68k apollo_defconfig
m68k atari_defconfig
arm multi_v4t_defconfig
xtensa nommu_kc705_defconfig
h8300 allyesconfig
h8300 edosk2674_defconfig
mips rs90_defconfig
mips maltasmvp_defconfig
nds32 alldefconfig
powerpc redwood_defconfig
sh sdk7786_defconfig
arm h5000_defconfig
powerpc mpc7448_hpc2_defconfig
powerpc ppa8548_defconfig
powerpc mpc866_ads_defconfig
sh kfr2r09_defconfig
mips mtx1_defconfig
nios2 defconfig
sparc allyesconfig
powerpc klondike_defconfig
arm rpc_defconfig
sh se7619_defconfig
powerpc kmeter1_defconfig
mips malta_kvm_defconfig
riscv nommu_virt_defconfig
powerpc taishan_defconfig
arm iop32x_defconfig
arm mv78xx0_defconfig
arc nsimosci_hs_defconfig
mips tb0287_defconfig
sh defconfig
powerpc mvme5100_defconfig
sh shmin_defconfig
mips bcm63xx_defconfig
mips cu1830-neo_defconfig
powerpc mpc834x_itx_defconfig
sh rsk7269_defconfig
mips jmr3927_defconfig
arc nsim_700_defconfig
arm s5pv210_defconfig
arm mxs_defconfig
powerpc tqm8560_defconfig
powerpc ps3_defconfig
arm keystone_defconfig
ia64 gensparse_defconfig
arm mps2_defconfig
sh se7705_defconfig
mips xway_defconfig
powerpc cm5200_defconfig
sparc64 defconfig
powerpc wii_defconfig
um x86_64_defconfig
arm xcep_defconfig
powerpc holly_defconfig
arm colibri_pxa300_defconfig
i386 alldefconfig
mips qi_lb60_defconfig
mips tb0226_defconfig
powerpc tqm8541_defconfig
arm ep93xx_defconfig
m68k mac_defconfig
arm badge4_defconfig
sh se7724_defconfig
mips allmodconfig
sh sh7785lcr_defconfig
powerpc64 defconfig
arm stm32_defconfig
arm palmz72_defconfig
sh sh7785lcr_32bit_defconfig
mips bmips_be_defconfig
arm sunxi_defconfig
xtensa cadence_csp_defconfig
arm h3600_defconfig
arm simpad_defconfig
powerpc linkstation_defconfig
powerpc asp8347_defconfig
mips maltaup_xpa_defconfig
mips e55_defconfig
powerpc akebono_defconfig
mips malta_defconfig
i386 defconfig
arm viper_defconfig
riscv nommu_k210_defconfig
powerpc cell_defconfig
arc haps_hs_defconfig
sh se7712_defconfig
arm assabet_defconfig
powerpc eiger_defconfig
sh apsh4ad0a_defconfig
arm lpc32xx_defconfig
h8300 h8300h-sim_defconfig
sh rts7751r2dplus_defconfig
powerpc motionpro_defconfig
parisc alldefconfig
mips loongson3_defconfig
mips ip22_defconfig
arm shmobile_defconfig
powerpc mpc8313_rdb_defconfig
arm gemini_defconfig
powerpc mpc83xx_defconfig
powerpc katmai_defconfig
arm neponset_defconfig
powerpc kilauea_defconfig
arm imx_v4_v5_defconfig
mips tb0219_defconfig
arm sama7_defconfig
arm omap1_defconfig
arm pxa255-idp_defconfig
powerpc mpc836x_rdk_defconfig
arm at91_dt_defconfig
mips rt305x_defconfig
sh migor_defconfig
arm spear13xx_defconfig
arm zeus_defconfig
sh alldefconfig
arm vf610m4_defconfig
arm multi_v7_defconfig
sh espt_defconfig
arm footbridge_defconfig
powerpc acadia_defconfig
sh se7721_defconfig
powerpc canyonlands_defconfig
arm jornada720_defconfig
sparc alldefconfig
powerpc stx_gp3_defconfig
arm mvebu_v7_defconfig
riscv nommu_k210_sdcard_defconfig
sh ecovec24_defconfig
arm orion5x_defconfig
sh se7780_defconfig
arc nsimosci_hs_smp_defconfig
arm lpd270_defconfig
arm oxnas_v6_defconfig
powerpc mpc836x_mds_defconfig
alpha alldefconfig
powerpc ppc64e_defconfig
m68k bvme6000_defconfig
powerpc ge_imp3a_defconfig
powerpc microwatt_defconfig
arm pxa910_defconfig
sh r7785rp_defconfig
arm vexpress_defconfig
i386 allyesconfig
mips db1xxx_defconfig
arc hsdk_defconfig
s390 defconfig
arm omap2plus_defconfig
arc axs103_defconfig
arm lubbock_defconfig
mips mpc30x_defconfig
arc axs103_smp_defconfig
powerpc ep8248e_defconfig
parisc generic-64bit_defconfig
microblaze defconfig
powerpc mpc8272_ads_defconfig
xtensa common_defconfig
h8300 h8s-sim_defconfig
openrisc or1klitex_defconfig
m68k m5249evb_defconfig
m68k m5275evb_defconfig
powerpc mpc85xx_cds_defconfig
arm corgi_defconfig
sh sh7724_generic_defconfig
powerpc mpc834x_itxgp_defconfig
powerpc tqm8xx_defconfig
sparc64 alldefconfig
sh ap325rxa_defconfig
arm socfpga_defconfig
mips rm200_defconfig
h8300 defconfig
s390 zfcpdump_defconfig
openrisc alldefconfig
mips ath25_defconfig
sh sh7757lcr_defconfig
sh se7206_defconfig
m68k mvme16x_defconfig
sh rts7751r2d1_defconfig
arc defconfig
ia64 generic_defconfig
powerpc tqm8548_defconfig
h8300 alldefconfig
mips cu1000-neo_defconfig
powerpc pmac32_defconfig
arm pcm027_defconfig
m68k sun3x_defconfig
m68k m5272c3_defconfig
arm mvebu_v5_defconfig
sparc sparc32_defconfig
arm cns3420vb_defconfig
arc nsimosci_defconfig
mips decstation_defconfig
arm cerfcube_defconfig
arm colibri_pxa270_defconfig
arm ezx_defconfig
arm qcom_defconfig
sh se7722_defconfig
arm moxart_defconfig
m68k q40_defconfig
nds32 allnoconfig
nios2 allyesconfig
mips bigsur_defconfig
riscv rv32_defconfig
arm cm_x300_defconfig
powerpc amigaone_defconfig
m68k sun3_defconfig
sh kfr2r09-romimage_defconfig
sparc defconfig
mips rbtx49xx_defconfig
powerpc ep88xc_defconfig
powerpc pasemi_defconfig
powerpc mpc8560_ads_defconfig
arm aspeed_g4_defconfig
powerpc warp_defconfig
sh apsh4a3a_defconfig
sh sh2007_defconfig
microblaze mmu_defconfig
arm spear6xx_defconfig
arc alldefconfig
powerpc icon_defconfig
powerpc xes_mpc85xx_defconfig
arc haps_hs_smp_defconfig
powerpc mpc512x_defconfig
arm randconfig-c002-20211207
arm randconfig-c002-20211203
arm randconfig-c002-20211205
arm randconfig-c002-20211204
ia64 allmodconfig
ia64 defconfig
ia64 allyesconfig
m68k allmodconfig
m68k defconfig
alpha defconfig
alpha allyesconfig
xtensa allyesconfig
sh allmodconfig
parisc defconfig
parisc allyesconfig
i386 debian-10.3-kselftests
i386 debian-10.3
mips allyesconfig
powerpc allyesconfig
powerpc allmodconfig
powerpc allnoconfig
x86_64 randconfig-a006-20211203
x86_64 randconfig-a005-20211203
x86_64 randconfig-a001-20211203
x86_64 randconfig-a002-20211203
x86_64 randconfig-a004-20211203
x86_64 randconfig-a003-20211203
x86_64 randconfig-a006-20211207
x86_64 randconfig-a005-20211207
x86_64 randconfig-a001-20211207
x86_64 randconfig-a002-20211207
x86_64 randconfig-a004-20211207
x86_64 randconfig-a003-20211207
i386 randconfig-a001-20211203
i386 randconfig-a005-20211203
i386 randconfig-a002-20211203
i386 randconfig-a003-20211203
i386 randconfig-a006-20211203
i386 randconfig-a004-20211203
i386 randconfig-a001-20211207
i386 randconfig-a005-20211207
i386 randconfig-a002-20211207
i386 randconfig-a003-20211207
i386 randconfig-a006-20211207
i386 randconfig-a004-20211207
i386 randconfig-a001-20211205
i386 randconfig-a005-20211205
i386 randconfig-a003-20211205
i386 randconfig-a002-20211205
i386 randconfig-a006-20211205
i386 randconfig-a004-20211205
x86_64 randconfig-a016-20211208
x86_64 randconfig-a011-20211208
x86_64 randconfig-a013-20211208
x86_64 randconfig-a012-20211208
x86_64 randconfig-a015-20211208
x86_64 randconfig-a014-20211208
x86_64 randconfig-a016-20211206
x86_64 randconfig-a011-20211206
x86_64 randconfig-a013-20211206
x86_64 randconfig-a014-20211206
x86_64 randconfig-a012-20211206
x86_64 randconfig-a015-20211206
i386 randconfig-a013-20211204
i386 randconfig-a016-20211204
i386 randconfig-a011-20211204
i386 randconfig-a014-20211204
i386 randconfig-a012-20211204
i386 randconfig-a015-20211204
riscv allyesconfig
riscv allnoconfig
riscv defconfig
riscv allmodconfig
x86_64 rhel-8.3-kselftests
x86_64 allyesconfig
x86_64 defconfig
x86_64 rhel-8.3
x86_64 rhel-8.3-func
x86_64 kexec
clang tested configs:
x86_64 randconfig-c007-20211206
arm randconfig-c002-20211206
riscv randconfig-c006-20211206
mips randconfig-c004-20211206
i386 randconfig-c001-20211206
powerpc randconfig-c003-20211206
s390 randconfig-c005-20211206
x86_64 randconfig-c007-20211207
arm randconfig-c002-20211207
riscv randconfig-c006-20211207
mips randconfig-c004-20211207
i386 randconfig-c001-20211207
powerpc randconfig-c003-20211207
s390 randconfig-c005-20211207
arm randconfig-c002-20211203
x86_64 randconfig-c007-20211203
riscv randconfig-c006-20211203
mips randconfig-c004-20211203
i386 randconfig-c001-20211203
powerpc randconfig-c003-20211203
s390 randconfig-c005-20211203
x86_64 randconfig-c007-20211205
arm randconfig-c002-20211205
riscv randconfig-c006-20211205
mips randconfig-c004-20211205
i386 randconfig-c001-20211205
powerpc randconfig-c003-20211205
s390 randconfig-c005-20211205
i386 randconfig-a001-20211206
i386 randconfig-a005-20211206
i386 randconfig-a002-20211206
i386 randconfig-a003-20211206
i386 randconfig-a006-20211206
i386 randconfig-a004-20211206
x86_64 randconfig-a016-20211207
x86_64 randconfig-a011-20211207
x86_64 randconfig-a013-20211207
x86_64 randconfig-a014-20211207
x86_64 randconfig-a015-20211207
x86_64 randconfig-a012-20211207
x86_64 randconfig-a016-20211203
x86_64 randconfig-a011-20211203
x86_64 randconfig-a013-20211203
x86_64 randconfig-a014-20211203
x86_64 randconfig-a015-20211203
x86_64 randconfig-a012-20211203
i386 randconfig-a016-20211203
i386 randconfig-a013-20211203
i386 randconfig-a011-20211203
i386 randconfig-a014-20211203
i386 randconfig-a012-20211203
i386 randconfig-a015-20211203
i386 randconfig-a013-20211205
i386 randconfig-a016-20211205
i386 randconfig-a011-20211205
i386 randconfig-a014-20211205
i386 randconfig-a012-20211205
i386 randconfig-a015-20211205
i386 randconfig-a016-20211207
i386 randconfig-a013-20211207
i386 randconfig-a011-20211207
i386 randconfig-a014-20211207
i386 randconfig-a012-20211207
i386 randconfig-a015-20211207
x86_64 randconfig-a006-20211204
x86_64 randconfig-a005-20211204
x86_64 randconfig-a001-20211204
x86_64 randconfig-a002-20211204
x86_64 randconfig-a004-20211204
x86_64 randconfig-a003-20211204
hexagon randconfig-r045-20211203
s390 randconfig-r044-20211203
hexagon randconfig-r041-20211203
riscv randconfig-r042-20211203
hexagon randconfig-r045-20211207
s390 randconfig-r044-20211207
riscv randconfig-r042-20211207
hexagon randconfig-r041-20211207
hexagon randconfig-r045-20211204
hexagon randconfig-r041-20211204
hexagon randconfig-r045-20211206
hexagon randconfig-r041-20211206
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
^ permalink raw reply
* [powerpc:next] BUILD SUCCESS 2a2ac8a7018b953cd23d770ebd28f8e1ea365df4
From: kernel test robot @ 2021-12-08 2:20 UTC (permalink / raw)
To: Michael Ellerman; +Cc: linuxppc-dev
tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git next
branch HEAD: 2a2ac8a7018b953cd23d770ebd28f8e1ea365df4 powerpc/xive: Fix compile when !CONFIG_PPC_POWERNV.
elapsed time: 732m
configs tested: 144
configs skipped: 3
The following configs have been built successfully.
More configs may be tested in the coming days.
gcc tested configs:
arm defconfig
arm64 allyesconfig
arm64 defconfig
arm allyesconfig
arm allmodconfig
i386 randconfig-c001-20211207
m68k alldefconfig
arc tb10x_defconfig
arm tegra_defconfig
powerpc mpc837x_rdb_defconfig
h8300 edosk2674_defconfig
mips rs90_defconfig
mips maltasmvp_defconfig
h8300 allyesconfig
mips tb0287_defconfig
sh defconfig
powerpc mvme5100_defconfig
sh shmin_defconfig
mips bcm63xx_defconfig
sh se7705_defconfig
mips xway_defconfig
powerpc cm5200_defconfig
sparc64 defconfig
powerpc wii_defconfig
powerpc motionpro_defconfig
parisc alldefconfig
arm h3600_defconfig
mips loongson3_defconfig
sh sh7785lcr_32bit_defconfig
mips ip22_defconfig
arm omap1_defconfig
powerpc holly_defconfig
arm pxa255-idp_defconfig
sh rts7751r2dplus_defconfig
mips workpad_defconfig
sh espt_defconfig
arm footbridge_defconfig
powerpc acadia_defconfig
sh sh7710voipgw_defconfig
sh se7721_defconfig
arm mvebu_v7_defconfig
riscv nommu_k210_sdcard_defconfig
sh ecovec24_defconfig
arm orion5x_defconfig
sh se7780_defconfig
powerpc tqm8xx_defconfig
mips db1xxx_defconfig
parisc generic-64bit_defconfig
sparc64 alldefconfig
arm mv78xx0_defconfig
mips ath79_defconfig
arm pcm027_defconfig
m68k sun3x_defconfig
m68k m5272c3_defconfig
powerpc powernv_defconfig
arc axs103_smp_defconfig
mips cu1000-neo_defconfig
arm cerfcube_defconfig
arm colibri_pxa270_defconfig
powerpc ppa8548_defconfig
m68k q40_defconfig
nds32 allnoconfig
nios2 allyesconfig
powerpc tqm8548_defconfig
sh sh7757lcr_defconfig
sh kfr2r09-romimage_defconfig
arm at91_dt_defconfig
sparc defconfig
mips rbtx49xx_defconfig
xtensa nommu_kc705_defconfig
arm randconfig-c002-20211207
ia64 allmodconfig
ia64 defconfig
ia64 allyesconfig
m68k allmodconfig
m68k defconfig
m68k allyesconfig
nios2 defconfig
arc allyesconfig
nds32 defconfig
csky defconfig
alpha defconfig
alpha allyesconfig
xtensa allyesconfig
arc defconfig
sh allmodconfig
parisc defconfig
s390 allyesconfig
s390 allmodconfig
parisc allyesconfig
s390 defconfig
i386 allyesconfig
sparc allyesconfig
i386 defconfig
i386 debian-10.3-kselftests
i386 debian-10.3
mips allyesconfig
mips allmodconfig
powerpc allyesconfig
powerpc allmodconfig
powerpc allnoconfig
i386 randconfig-a001-20211207
i386 randconfig-a005-20211207
i386 randconfig-a002-20211207
i386 randconfig-a003-20211207
i386 randconfig-a006-20211207
i386 randconfig-a004-20211207
x86_64 randconfig-a006-20211207
x86_64 randconfig-a005-20211207
x86_64 randconfig-a001-20211207
x86_64 randconfig-a002-20211207
x86_64 randconfig-a004-20211207
x86_64 randconfig-a003-20211207
riscv nommu_k210_defconfig
riscv allyesconfig
riscv nommu_virt_defconfig
riscv allnoconfig
riscv defconfig
riscv rv32_defconfig
riscv allmodconfig
um x86_64_defconfig
um i386_defconfig
x86_64 allyesconfig
x86_64 rhel-8.3-kselftests
x86_64 defconfig
x86_64 rhel-8.3
x86_64 rhel-8.3-func
x86_64 kexec
clang tested configs:
x86_64 randconfig-a016-20211207
x86_64 randconfig-a011-20211207
x86_64 randconfig-a013-20211207
x86_64 randconfig-a014-20211207
x86_64 randconfig-a015-20211207
x86_64 randconfig-a012-20211207
i386 randconfig-a016-20211207
i386 randconfig-a013-20211207
i386 randconfig-a011-20211207
i386 randconfig-a014-20211207
i386 randconfig-a012-20211207
i386 randconfig-a015-20211207
hexagon randconfig-r045-20211207
s390 randconfig-r044-20211207
riscv randconfig-r042-20211207
hexagon randconfig-r041-20211207
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
^ permalink raw reply
* Re: [PATCH] powerpc/module_64: Fix livepatching for RO modules
From: Russell Currey @ 2021-12-08 1:51 UTC (permalink / raw)
To: Joe Lawrence, linuxppc-dev; +Cc: live-patching, jniethe5, naveen.n.rao
In-Reply-To: <d9d9ef2d-4aaa-7d8b-d15e-0452a355c5cf@redhat.com>
On Tue, 2021-12-07 at 09:44 -0500, Joe Lawrence wrote:
> On 11/23/21 3:15 AM, Russell Currey wrote:
>
> [[ cc += livepatching list ]]
>
> Hi Russell,
>
> Thanks for writing a minimal fix for stable / backporting. As I
> mentioned on the github issue [1], this avoided the crashes I
> reported
> here and over on kpatch github [2]. I wasn't sure if this is the
> final
> version for stable, but feel free to add my:
>
> Tested-by: Joe Lawrence <joe.lawrence@redhat.com>
Thanks Joe, as per the discussions on GitHub I think we're fine to use
this patch for a fix for stable (unless there's new issues found or
additional community feedback etc).
>
> [1] https://github.com/linuxppc/issues/issues/375
> [2] https://github.com/dynup/kpatch/issues/1228
>
^ permalink raw reply
* Re: [patch V2 23/23] PCI/MSI: Move descriptor counting on allocation fail to the legacy code
From: Bjorn Helgaas @ 2021-12-07 21:02 UTC (permalink / raw)
To: Thomas Gleixner
Cc: linux-hyperv, linux-mips, Paul Mackerras, sparclinux, Wei Liu,
Ashok Raj, x86, Christian Borntraeger, Megha Dey, Jason Gunthorpe,
linux-pci, xen-devel, ath11k, Kevin Tian, Heiko Carstens,
Alex Williamson, Cedric Le Goater, Kalle Valo, Juergen Gross,
Thomas Bogendoerfer, Greg Kroah-Hartman, LKML, Marc Zygnier,
linuxppc-dev
In-Reply-To: <20211206210225.101336873@linutronix.de>
On Mon, Dec 06, 2021 at 11:28:00PM +0100, Thomas Gleixner wrote:
> The irqdomain code already returns the information. Move the loop to the
> legacy code.
>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> Tested-by: Juergen Gross <jgross@suse.com>
> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
> ---
> drivers/pci/msi/legacy.c | 20 +++++++++++++++++++-
> drivers/pci/msi/msi.c | 19 +------------------
> 2 files changed, 20 insertions(+), 19 deletions(-)
>
> --- a/drivers/pci/msi/legacy.c
> +++ b/drivers/pci/msi/legacy.c
> @@ -50,9 +50,27 @@ void __weak arch_teardown_msi_irqs(struc
> }
> }
>
> +static int pci_msi_setup_check_result(struct pci_dev *dev, int type, int ret)
> +{
> + struct msi_desc *entry;
> + int avail = 0;
> +
> + if (type != PCI_CAP_ID_MSIX || ret >= 0)
> + return ret;
> +
> + /* Scan the MSI descriptors for successfully allocated ones. */
> + for_each_pci_msi_entry(entry, dev) {
> + if (entry->irq != 0)
> + avail++;
> + }
> + return avail ? avail : ret;
> +}
> +
> int pci_msi_legacy_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
> {
> - return arch_setup_msi_irqs(dev, nvec, type);
> + int ret = arch_setup_msi_irqs(dev, nvec, type);
> +
> + return pci_msi_setup_check_result(dev, type, ret);
> }
>
> void pci_msi_legacy_teardown_msi_irqs(struct pci_dev *dev)
> --- a/drivers/pci/msi/msi.c
> +++ b/drivers/pci/msi/msi.c
> @@ -609,7 +609,7 @@ static int msix_capability_init(struct p
>
> ret = pci_msi_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSIX);
> if (ret)
> - goto out_avail;
> + goto out_free;
>
> /* Check if all MSI entries honor device restrictions */
> ret = msi_verify_entries(dev);
> @@ -634,23 +634,6 @@ static int msix_capability_init(struct p
> pcibios_free_irq(dev);
> return 0;
>
> -out_avail:
> - if (ret < 0) {
> - /*
> - * If we had some success, report the number of IRQs
> - * we succeeded in setting up.
> - */
> - struct msi_desc *entry;
> - int avail = 0;
> -
> - for_each_pci_msi_entry(entry, dev) {
> - if (entry->irq != 0)
> - avail++;
> - }
> - if (avail != 0)
> - ret = avail;
> - }
> -
> out_free:
> free_msi_irqs(dev);
>
>
^ permalink raw reply
* Re: [patch V2 22/23] genirq/msi: Handle PCI/MSI allocation fail in core code
From: Bjorn Helgaas @ 2021-12-07 21:02 UTC (permalink / raw)
To: Thomas Gleixner
Cc: linux-hyperv, linux-mips, Paul Mackerras, sparclinux, Wei Liu,
Ashok Raj, x86, Christian Borntraeger, Megha Dey, Jason Gunthorpe,
linux-pci, xen-devel, ath11k, Kevin Tian, Heiko Carstens,
Alex Williamson, Cedric Le Goater, Kalle Valo, Juergen Gross,
Thomas Bogendoerfer, Greg Kroah-Hartman, LKML, Marc Zygnier,
linuxppc-dev
In-Reply-To: <20211206210225.046615302@linutronix.de>
On Mon, Dec 06, 2021 at 11:27:59PM +0100, Thomas Gleixner wrote:
> Get rid of yet another irqdomain callback and let the core code return the
> already available information of how many descriptors could be allocated.
>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> Tested-by: Juergen Gross <jgross@suse.com>
> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Acked-by: Bjorn Helgaas <bhelgaas@google.com> # PCI
> ---
> drivers/pci/msi/irqdomain.c | 13 -------------
> include/linux/msi.h | 5 +----
> kernel/irq/msi.c | 29 +++++++++++++++++++++++++----
> 3 files changed, 26 insertions(+), 21 deletions(-)
>
> --- a/drivers/pci/msi/irqdomain.c
> +++ b/drivers/pci/msi/irqdomain.c
> @@ -95,16 +95,6 @@ static int pci_msi_domain_check_cap(stru
> return 0;
> }
>
> -static int pci_msi_domain_handle_error(struct irq_domain *domain,
> - struct msi_desc *desc, int error)
> -{
> - /* Special handling to support __pci_enable_msi_range() */
> - if (pci_msi_desc_is_multi_msi(desc) && error == -ENOSPC)
> - return 1;
> -
> - return error;
> -}
> -
> static void pci_msi_domain_set_desc(msi_alloc_info_t *arg,
> struct msi_desc *desc)
> {
> @@ -115,7 +105,6 @@ static void pci_msi_domain_set_desc(msi_
> static struct msi_domain_ops pci_msi_domain_ops_default = {
> .set_desc = pci_msi_domain_set_desc,
> .msi_check = pci_msi_domain_check_cap,
> - .handle_error = pci_msi_domain_handle_error,
> };
>
> static void pci_msi_domain_update_dom_ops(struct msi_domain_info *info)
> @@ -129,8 +118,6 @@ static void pci_msi_domain_update_dom_op
> ops->set_desc = pci_msi_domain_set_desc;
> if (ops->msi_check == NULL)
> ops->msi_check = pci_msi_domain_check_cap;
> - if (ops->handle_error == NULL)
> - ops->handle_error = pci_msi_domain_handle_error;
> }
> }
>
> --- a/include/linux/msi.h
> +++ b/include/linux/msi.h
> @@ -286,7 +286,6 @@ struct msi_domain_info;
> * @msi_check: Callback for verification of the domain/info/dev data
> * @msi_prepare: Prepare the allocation of the interrupts in the domain
> * @set_desc: Set the msi descriptor for an interrupt
> - * @handle_error: Optional error handler if the allocation fails
> * @domain_alloc_irqs: Optional function to override the default allocation
> * function.
> * @domain_free_irqs: Optional function to override the default free
> @@ -295,7 +294,7 @@ struct msi_domain_info;
> * @get_hwirq, @msi_init and @msi_free are callbacks used by the underlying
> * irqdomain.
> *
> - * @msi_check, @msi_prepare, @handle_error and @set_desc are callbacks used by
> + * @msi_check, @msi_prepare and @set_desc are callbacks used by
> * msi_domain_alloc/free_irqs().
> *
> * @domain_alloc_irqs, @domain_free_irqs can be used to override the
> @@ -332,8 +331,6 @@ struct msi_domain_ops {
> msi_alloc_info_t *arg);
> void (*set_desc)(msi_alloc_info_t *arg,
> struct msi_desc *desc);
> - int (*handle_error)(struct irq_domain *domain,
> - struct msi_desc *desc, int error);
> int (*domain_alloc_irqs)(struct irq_domain *domain,
> struct device *dev, int nvec);
> void (*domain_free_irqs)(struct irq_domain *domain,
> --- a/kernel/irq/msi.c
> +++ b/kernel/irq/msi.c
> @@ -538,6 +538,27 @@ static bool msi_check_reservation_mode(s
> return desc->pci.msi_attrib.is_msix || desc->pci.msi_attrib.can_mask;
> }
>
> +static int msi_handle_pci_fail(struct irq_domain *domain, struct msi_desc *desc,
> + int allocated)
> +{
> + switch(domain->bus_token) {
> + case DOMAIN_BUS_PCI_MSI:
> + case DOMAIN_BUS_VMD_MSI:
> + if (IS_ENABLED(CONFIG_PCI_MSI))
> + break;
> + fallthrough;
> + default:
> + return -ENOSPC;
> + }
> +
> + /* Let a failed PCI multi MSI allocation retry */
> + if (desc->nvec_used > 1)
> + return 1;
> +
> + /* If there was a successful allocation let the caller know */
> + return allocated ? allocated : -ENOSPC;
> +}
> +
> int __msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
> int nvec)
> {
> @@ -546,6 +567,7 @@ int __msi_domain_alloc_irqs(struct irq_d
> struct irq_data *irq_data;
> struct msi_desc *desc;
> msi_alloc_info_t arg = { };
> + int allocated = 0;
> int i, ret, virq;
> bool can_reserve;
>
> @@ -560,16 +582,15 @@ int __msi_domain_alloc_irqs(struct irq_d
> dev_to_node(dev), &arg, false,
> desc->affinity);
> if (virq < 0) {
> - ret = -ENOSPC;
> - if (ops->handle_error)
> - ret = ops->handle_error(domain, desc, ret);
> - return ret;
> + ret = msi_handle_pci_fail(domain, desc, allocated);
> + goto cleanup;
> }
>
> for (i = 0; i < desc->nvec_used; i++) {
> irq_set_msi_desc_off(virq, i, desc);
> irq_debugfs_copy_devname(virq + i, dev);
> }
> + allocated++;
> }
>
> can_reserve = msi_check_reservation_mode(domain, info, dev);
>
^ permalink raw reply
* Re: [patch V2 21/23] PCI/MSI: Make pci_msi_domain_check_cap() static
From: Bjorn Helgaas @ 2021-12-07 21:01 UTC (permalink / raw)
To: Thomas Gleixner
Cc: linux-hyperv, linux-mips, Paul Mackerras, sparclinux, Wei Liu,
Ashok Raj, x86, Christian Borntraeger, Megha Dey, Jason Gunthorpe,
linux-pci, xen-devel, ath11k, Kevin Tian, Heiko Carstens,
Alex Williamson, Cedric Le Goater, Kalle Valo, Juergen Gross,
Thomas Bogendoerfer, Greg Kroah-Hartman, LKML, Marc Zygnier,
linuxppc-dev
In-Reply-To: <20211206210224.980989243@linutronix.de>
On Mon, Dec 06, 2021 at 11:27:57PM +0100, Thomas Gleixner wrote:
> No users outside of that file.
>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> Tested-by: Juergen Gross <jgross@suse.com>
> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
> ---
> drivers/pci/msi/irqdomain.c | 5 +++--
> include/linux/msi.h | 2 --
> 2 files changed, 3 insertions(+), 4 deletions(-)
>
> --- a/drivers/pci/msi/irqdomain.c
> +++ b/drivers/pci/msi/irqdomain.c
> @@ -79,8 +79,9 @@ static inline bool pci_msi_desc_is_multi
> * 1 if Multi MSI is requested, but the domain does not support it
> * -ENOTSUPP otherwise
> */
> -int pci_msi_domain_check_cap(struct irq_domain *domain,
> - struct msi_domain_info *info, struct device *dev)
> +static int pci_msi_domain_check_cap(struct irq_domain *domain,
> + struct msi_domain_info *info,
> + struct device *dev)
> {
> struct msi_desc *desc = first_pci_msi_entry(to_pci_dev(dev));
>
> --- a/include/linux/msi.h
> +++ b/include/linux/msi.h
> @@ -439,8 +439,6 @@ void *platform_msi_get_host_data(struct
> struct irq_domain *pci_msi_create_irq_domain(struct fwnode_handle *fwnode,
> struct msi_domain_info *info,
> struct irq_domain *parent);
> -int pci_msi_domain_check_cap(struct irq_domain *domain,
> - struct msi_domain_info *info, struct device *dev);
> u32 pci_msi_domain_get_msi_rid(struct irq_domain *domain, struct pci_dev *pdev);
> struct irq_domain *pci_msi_get_device_domain(struct pci_dev *pdev);
> bool pci_dev_has_special_msi_domain(struct pci_dev *pdev);
>
^ permalink raw reply
* Re: [patch V2 20/23] PCI/MSI: Move msi_lock to struct pci_dev
From: Bjorn Helgaas @ 2021-12-07 21:01 UTC (permalink / raw)
To: Thomas Gleixner
Cc: linux-hyperv, linux-mips, Paul Mackerras, sparclinux, Wei Liu,
Ashok Raj, x86, Christian Borntraeger, Megha Dey, Jason Gunthorpe,
linux-pci, xen-devel, ath11k, Kevin Tian, Heiko Carstens,
Alex Williamson, Cedric Le Goater, Kalle Valo, Juergen Gross,
Thomas Bogendoerfer, Greg Kroah-Hartman, LKML, Marc Zygnier,
linuxppc-dev
In-Reply-To: <20211206210224.925241961@linutronix.de>
On Mon, Dec 06, 2021 at 11:27:56PM +0100, Thomas Gleixner wrote:
> It's only required for PCI/MSI. So no point in having it in every struct
> device.
>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
> ---
> V2: New patch
> ---
> drivers/base/core.c | 1 -
> drivers/pci/msi/msi.c | 2 +-
> drivers/pci/probe.c | 4 +++-
> include/linux/device.h | 2 --
> include/linux/pci.h | 1 +
> 5 files changed, 5 insertions(+), 5 deletions(-)
>
> --- a/drivers/base/core.c
> +++ b/drivers/base/core.c
> @@ -2875,7 +2875,6 @@ void device_initialize(struct device *de
> device_pm_init(dev);
> set_dev_node(dev, NUMA_NO_NODE);
> #ifdef CONFIG_GENERIC_MSI_IRQ
> - raw_spin_lock_init(&dev->msi_lock);
> INIT_LIST_HEAD(&dev->msi_list);
> #endif
> INIT_LIST_HEAD(&dev->links.consumers);
> --- a/drivers/pci/msi/msi.c
> +++ b/drivers/pci/msi/msi.c
> @@ -18,7 +18,7 @@ int pci_msi_ignore_mask;
>
> static noinline void pci_msi_update_mask(struct msi_desc *desc, u32 clear, u32 set)
> {
> - raw_spinlock_t *lock = &desc->dev->msi_lock;
> + raw_spinlock_t *lock = &to_pci_dev(desc->dev)->msi_lock;
> unsigned long flags;
>
> if (!desc->pci.msi_attrib.can_mask)
> --- a/drivers/pci/probe.c
> +++ b/drivers/pci/probe.c
> @@ -2311,7 +2311,9 @@ struct pci_dev *pci_alloc_dev(struct pci
> INIT_LIST_HEAD(&dev->bus_list);
> dev->dev.type = &pci_dev_type;
> dev->bus = pci_bus_get(bus);
> -
> +#ifdef CONFIG_PCI_MSI
> + raw_spin_lock_init(&dev->msi_lock);
> +#endif
> return dev;
> }
> EXPORT_SYMBOL(pci_alloc_dev);
> --- a/include/linux/device.h
> +++ b/include/linux/device.h
> @@ -407,7 +407,6 @@ struct dev_links_info {
> * @em_pd: device's energy model performance domain
> * @pins: For device pin management.
> * See Documentation/driver-api/pin-control.rst for details.
> - * @msi_lock: Lock to protect MSI mask cache and mask register
> * @msi_list: Hosts MSI descriptors
> * @msi_domain: The generic MSI domain this device is using.
> * @numa_node: NUMA node this device is close to.
> @@ -508,7 +507,6 @@ struct device {
> struct dev_pin_info *pins;
> #endif
> #ifdef CONFIG_GENERIC_MSI_IRQ
> - raw_spinlock_t msi_lock;
> struct list_head msi_list;
> #endif
> #ifdef CONFIG_DMA_OPS
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -474,6 +474,7 @@ struct pci_dev {
> #endif
> #ifdef CONFIG_PCI_MSI
> void __iomem *msix_base;
> + raw_spinlock_t msi_lock;
> const struct attribute_group **msi_irq_groups;
> #endif
> struct pci_vpd vpd;
>
^ permalink raw reply
* Re: [patch V2 19/23] PCI/MSI: Sanitize MSIX table map handling
From: Bjorn Helgaas @ 2021-12-07 21:01 UTC (permalink / raw)
To: Thomas Gleixner
Cc: linux-hyperv, linux-mips, Paul Mackerras, sparclinux, Wei Liu,
Ashok Raj, x86, Christian Borntraeger, Megha Dey, Jason Gunthorpe,
linux-pci, xen-devel, ath11k, Kevin Tian, Heiko Carstens,
Alex Williamson, Cedric Le Goater, Kalle Valo, Juergen Gross,
Thomas Bogendoerfer, Greg Kroah-Hartman, LKML, Marc Zygnier,
linuxppc-dev
In-Reply-To: <20211206210224.871651518@linutronix.de>
On Mon, Dec 06, 2021 at 11:27:54PM +0100, Thomas Gleixner wrote:
> Unmapping the MSIX base mapping in the loops which allocate/free MSI
> desciptors is daft and in the way of allowing runtime expansion of MSI-X
> descriptors.
s/MSIX/MSI-X/ (subject and first use in commit log)
s/desciptors/descriptors/
> Store the mapping in struct pci_dev and free it after freeing the MSI-X
> descriptors.
>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> Tested-by: Juergen Gross <jgross@suse.com>
> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
> ---
> drivers/pci/msi/msi.c | 18 ++++++++----------
> include/linux/pci.h | 1 +
> 2 files changed, 9 insertions(+), 10 deletions(-)
>
> --- a/drivers/pci/msi/msi.c
> +++ b/drivers/pci/msi/msi.c
> @@ -241,14 +241,14 @@ static void free_msi_irqs(struct pci_dev
> pci_msi_teardown_msi_irqs(dev);
>
> list_for_each_entry_safe(entry, tmp, msi_list, list) {
> - if (entry->pci.msi_attrib.is_msix) {
> - if (list_is_last(&entry->list, msi_list))
> - iounmap(entry->pci.mask_base);
> - }
> -
> list_del(&entry->list);
> free_msi_entry(entry);
> }
> +
> + if (dev->msix_base) {
> + iounmap(dev->msix_base);
> + dev->msix_base = NULL;
> + }
> }
>
> static void pci_intx_for_msi(struct pci_dev *dev, int enable)
> @@ -501,10 +501,6 @@ static int msix_setup_entries(struct pci
> for (i = 0, curmsk = masks; i < nvec; i++) {
> entry = alloc_msi_entry(&dev->dev, 1, curmsk);
> if (!entry) {
> - if (!i)
> - iounmap(base);
> - else
> - free_msi_irqs(dev);
> /* No enough memory. Don't try again */
> ret = -ENOMEM;
> goto out;
> @@ -602,12 +598,14 @@ static int msix_capability_init(struct p
> goto out_disable;
> }
>
> + dev->msix_base = base;
> +
> /* Ensure that all table entries are masked. */
> msix_mask_all(base, tsize);
>
> ret = msix_setup_entries(dev, base, entries, nvec, affd);
> if (ret)
> - goto out_disable;
> + goto out_free;
>
> ret = pci_msi_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSIX);
> if (ret)
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -473,6 +473,7 @@ struct pci_dev {
> u8 ptm_granularity;
> #endif
> #ifdef CONFIG_PCI_MSI
> + void __iomem *msix_base;
> const struct attribute_group **msi_irq_groups;
> #endif
> struct pci_vpd vpd;
>
^ permalink raw reply
* Re: [patch V2 18/23] PCI/MSI: Split out irqdomain code
From: Bjorn Helgaas @ 2021-12-07 21:00 UTC (permalink / raw)
To: Thomas Gleixner
Cc: linux-hyperv, linux-mips, Paul Mackerras, sparclinux, Wei Liu,
Ashok Raj, x86, Christian Borntraeger, Megha Dey, Jason Gunthorpe,
linux-pci, xen-devel, ath11k, Kevin Tian, Heiko Carstens,
Alex Williamson, Cedric Le Goater, Kalle Valo, Juergen Gross,
Thomas Bogendoerfer, Greg Kroah-Hartman, LKML, Marc Zygnier,
linuxppc-dev
In-Reply-To: <20211206210224.817754783@linutronix.de>
On Mon, Dec 06, 2021 at 11:27:52PM +0100, Thomas Gleixner wrote:
> Move the irqdomain specific code into it's own file.
s/it's/its/
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> Tested-by: Juergen Gross <jgross@suse.com>
> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
> ---
> drivers/pci/msi/Makefile | 1
> drivers/pci/msi/irqdomain.c | 279 ++++++++++++++++++++++++++++++++++++++
> drivers/pci/msi/legacy.c | 13 +
> drivers/pci/msi/msi.c | 319 +-------------------------------------------
> drivers/pci/msi/msi.h | 39 +++++
> include/linux/msi.h | 11 -
> 6 files changed, 340 insertions(+), 322 deletions(-)
>
> --- a/drivers/pci/msi/Makefile
> +++ b/drivers/pci/msi/Makefile
> @@ -3,4 +3,5 @@
> # Makefile for the PCI/MSI
> obj-$(CONFIG_PCI) += pcidev_msi.o
> obj-$(CONFIG_PCI_MSI) += msi.o
> +obj-$(CONFIG_PCI_MSI_IRQ_DOMAIN) += irqdomain.o
> obj-$(CONFIG_PCI_MSI_ARCH_FALLBACKS) += legacy.o
> --- /dev/null
> +++ b/drivers/pci/msi/irqdomain.c
> @@ -0,0 +1,279 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * PCI Message Signaled Interrupt (MSI) - irqdomain support
> + */
> +#include <linux/acpi_iort.h>
> +#include <linux/irqdomain.h>
> +#include <linux/of_irq.h>
> +
> +#include "msi.h"
> +
> +int pci_msi_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
> +{
> + struct irq_domain *domain;
> +
> + domain = dev_get_msi_domain(&dev->dev);
> + if (domain && irq_domain_is_hierarchy(domain))
> + return msi_domain_alloc_irqs(domain, &dev->dev, nvec);
> +
> + return pci_msi_legacy_setup_msi_irqs(dev, nvec, type);
> +}
> +
> +void pci_msi_teardown_msi_irqs(struct pci_dev *dev)
> +{
> + struct irq_domain *domain;
> +
> + domain = dev_get_msi_domain(&dev->dev);
> + if (domain && irq_domain_is_hierarchy(domain))
> + msi_domain_free_irqs(domain, &dev->dev);
> + else
> + pci_msi_legacy_teardown_msi_irqs(dev);
> +}
> +
> +/**
> + * pci_msi_domain_write_msg - Helper to write MSI message to PCI config space
> + * @irq_data: Pointer to interrupt data of the MSI interrupt
> + * @msg: Pointer to the message
> + */
> +static void pci_msi_domain_write_msg(struct irq_data *irq_data, struct msi_msg *msg)
> +{
> + struct msi_desc *desc = irq_data_get_msi_desc(irq_data);
> +
> + /*
> + * For MSI-X desc->irq is always equal to irq_data->irq. For
> + * MSI only the first interrupt of MULTI MSI passes the test.
> + */
> + if (desc->irq == irq_data->irq)
> + __pci_write_msi_msg(desc, msg);
> +}
> +
> +/**
> + * pci_msi_domain_calc_hwirq - Generate a unique ID for an MSI source
> + * @desc: Pointer to the MSI descriptor
> + *
> + * The ID number is only used within the irqdomain.
> + */
> +static irq_hw_number_t pci_msi_domain_calc_hwirq(struct msi_desc *desc)
> +{
> + struct pci_dev *dev = msi_desc_to_pci_dev(desc);
> +
> + return (irq_hw_number_t)desc->pci.msi_attrib.entry_nr |
> + pci_dev_id(dev) << 11 |
> + (pci_domain_nr(dev->bus) & 0xFFFFFFFF) << 27;
> +}
> +
> +static inline bool pci_msi_desc_is_multi_msi(struct msi_desc *desc)
> +{
> + return !desc->pci.msi_attrib.is_msix && desc->nvec_used > 1;
> +}
> +
> +/**
> + * pci_msi_domain_check_cap - Verify that @domain supports the capabilities
> + * for @dev
> + * @domain: The interrupt domain to check
> + * @info: The domain info for verification
> + * @dev: The device to check
> + *
> + * Returns:
> + * 0 if the functionality is supported
> + * 1 if Multi MSI is requested, but the domain does not support it
> + * -ENOTSUPP otherwise
> + */
> +int pci_msi_domain_check_cap(struct irq_domain *domain,
> + struct msi_domain_info *info, struct device *dev)
> +{
> + struct msi_desc *desc = first_pci_msi_entry(to_pci_dev(dev));
> +
> + /* Special handling to support __pci_enable_msi_range() */
> + if (pci_msi_desc_is_multi_msi(desc) &&
> + !(info->flags & MSI_FLAG_MULTI_PCI_MSI))
> + return 1;
> + else if (desc->pci.msi_attrib.is_msix && !(info->flags & MSI_FLAG_PCI_MSIX))
> + return -ENOTSUPP;
> +
> + return 0;
> +}
> +
> +static int pci_msi_domain_handle_error(struct irq_domain *domain,
> + struct msi_desc *desc, int error)
> +{
> + /* Special handling to support __pci_enable_msi_range() */
> + if (pci_msi_desc_is_multi_msi(desc) && error == -ENOSPC)
> + return 1;
> +
> + return error;
> +}
> +
> +static void pci_msi_domain_set_desc(msi_alloc_info_t *arg,
> + struct msi_desc *desc)
> +{
> + arg->desc = desc;
> + arg->hwirq = pci_msi_domain_calc_hwirq(desc);
> +}
> +
> +static struct msi_domain_ops pci_msi_domain_ops_default = {
> + .set_desc = pci_msi_domain_set_desc,
> + .msi_check = pci_msi_domain_check_cap,
> + .handle_error = pci_msi_domain_handle_error,
> +};
> +
> +static void pci_msi_domain_update_dom_ops(struct msi_domain_info *info)
> +{
> + struct msi_domain_ops *ops = info->ops;
> +
> + if (ops == NULL) {
> + info->ops = &pci_msi_domain_ops_default;
> + } else {
> + if (ops->set_desc == NULL)
> + ops->set_desc = pci_msi_domain_set_desc;
> + if (ops->msi_check == NULL)
> + ops->msi_check = pci_msi_domain_check_cap;
> + if (ops->handle_error == NULL)
> + ops->handle_error = pci_msi_domain_handle_error;
> + }
> +}
> +
> +static void pci_msi_domain_update_chip_ops(struct msi_domain_info *info)
> +{
> + struct irq_chip *chip = info->chip;
> +
> + BUG_ON(!chip);
> + if (!chip->irq_write_msi_msg)
> + chip->irq_write_msi_msg = pci_msi_domain_write_msg;
> + if (!chip->irq_mask)
> + chip->irq_mask = pci_msi_mask_irq;
> + if (!chip->irq_unmask)
> + chip->irq_unmask = pci_msi_unmask_irq;
> +}
> +
> +/**
> + * pci_msi_create_irq_domain - Create a MSI interrupt domain
> + * @fwnode: Optional fwnode of the interrupt controller
> + * @info: MSI domain info
> + * @parent: Parent irq domain
> + *
> + * Updates the domain and chip ops and creates a MSI interrupt domain.
> + *
> + * Returns:
> + * A domain pointer or NULL in case of failure.
> + */
> +struct irq_domain *pci_msi_create_irq_domain(struct fwnode_handle *fwnode,
> + struct msi_domain_info *info,
> + struct irq_domain *parent)
> +{
> + struct irq_domain *domain;
> +
> + if (WARN_ON(info->flags & MSI_FLAG_LEVEL_CAPABLE))
> + info->flags &= ~MSI_FLAG_LEVEL_CAPABLE;
> +
> + if (info->flags & MSI_FLAG_USE_DEF_DOM_OPS)
> + pci_msi_domain_update_dom_ops(info);
> + if (info->flags & MSI_FLAG_USE_DEF_CHIP_OPS)
> + pci_msi_domain_update_chip_ops(info);
> +
> + info->flags |= MSI_FLAG_ACTIVATE_EARLY;
> + if (IS_ENABLED(CONFIG_GENERIC_IRQ_RESERVATION_MODE))
> + info->flags |= MSI_FLAG_MUST_REACTIVATE;
> +
> + /* PCI-MSI is oneshot-safe */
> + info->chip->flags |= IRQCHIP_ONESHOT_SAFE;
> +
> + domain = msi_create_irq_domain(fwnode, info, parent);
> + if (!domain)
> + return NULL;
> +
> + irq_domain_update_bus_token(domain, DOMAIN_BUS_PCI_MSI);
> + return domain;
> +}
> +EXPORT_SYMBOL_GPL(pci_msi_create_irq_domain);
> +
> +/*
> + * Users of the generic MSI infrastructure expect a device to have a single ID,
> + * so with DMA aliases we have to pick the least-worst compromise. Devices with
> + * DMA phantom functions tend to still emit MSIs from the real function number,
> + * so we ignore those and only consider topological aliases where either the
> + * alias device or RID appears on a different bus number. We also make the
> + * reasonable assumption that bridges are walked in an upstream direction (so
> + * the last one seen wins), and the much braver assumption that the most likely
> + * case is that of PCI->PCIe so we should always use the alias RID. This echoes
> + * the logic from intel_irq_remapping's set_msi_sid(), which presumably works
> + * well enough in practice; in the face of the horrible PCIe<->PCI-X conditions
> + * for taking ownership all we can really do is close our eyes and hope...
> + */
> +static int get_msi_id_cb(struct pci_dev *pdev, u16 alias, void *data)
> +{
> + u32 *pa = data;
> + u8 bus = PCI_BUS_NUM(*pa);
> +
> + if (pdev->bus->number != bus || PCI_BUS_NUM(alias) != bus)
> + *pa = alias;
> +
> + return 0;
> +}
> +
> +/**
> + * pci_msi_domain_get_msi_rid - Get the MSI requester id (RID)
> + * @domain: The interrupt domain
> + * @pdev: The PCI device.
> + *
> + * The RID for a device is formed from the alias, with a firmware
> + * supplied mapping applied
> + *
> + * Returns: The RID.
> + */
> +u32 pci_msi_domain_get_msi_rid(struct irq_domain *domain, struct pci_dev *pdev)
> +{
> + struct device_node *of_node;
> + u32 rid = pci_dev_id(pdev);
> +
> + pci_for_each_dma_alias(pdev, get_msi_id_cb, &rid);
> +
> + of_node = irq_domain_get_of_node(domain);
> + rid = of_node ? of_msi_map_id(&pdev->dev, of_node, rid) :
> + iort_msi_map_id(&pdev->dev, rid);
> +
> + return rid;
> +}
> +
> +/**
> + * pci_msi_get_device_domain - Get the MSI domain for a given PCI device
> + * @pdev: The PCI device
> + *
> + * Use the firmware data to find a device-specific MSI domain
> + * (i.e. not one that is set as a default).
> + *
> + * Returns: The corresponding MSI domain or NULL if none has been found.
> + */
> +struct irq_domain *pci_msi_get_device_domain(struct pci_dev *pdev)
> +{
> + struct irq_domain *dom;
> + u32 rid = pci_dev_id(pdev);
> +
> + pci_for_each_dma_alias(pdev, get_msi_id_cb, &rid);
> + dom = of_msi_map_get_device_domain(&pdev->dev, rid, DOMAIN_BUS_PCI_MSI);
> + if (!dom)
> + dom = iort_get_device_domain(&pdev->dev, rid,
> + DOMAIN_BUS_PCI_MSI);
> + return dom;
> +}
> +
> +/**
> + * pci_dev_has_special_msi_domain - Check whether the device is handled by
> + * a non-standard PCI-MSI domain
> + * @pdev: The PCI device to check.
> + *
> + * Returns: True if the device irqdomain or the bus irqdomain is
> + * non-standard PCI/MSI.
> + */
> +bool pci_dev_has_special_msi_domain(struct pci_dev *pdev)
> +{
> + struct irq_domain *dom = dev_get_msi_domain(&pdev->dev);
> +
> + if (!dom)
> + dom = dev_get_msi_domain(&pdev->bus->dev);
> +
> + if (!dom)
> + return true;
> +
> + return dom->bus_token != DOMAIN_BUS_PCI_MSI;
> +}
> --- a/drivers/pci/msi/legacy.c
> +++ b/drivers/pci/msi/legacy.c
> @@ -4,8 +4,7 @@
> *
> * Legacy architecture specific setup and teardown mechanism.
> */
> -#include <linux/msi.h>
> -#include <linux/pci.h>
> +#include "msi.h"
>
> /* Arch hooks */
> int __weak arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
> @@ -50,3 +49,13 @@ void __weak arch_teardown_msi_irqs(struc
> }
> }
> }
> +
> +int pci_msi_legacy_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
> +{
> + return arch_setup_msi_irqs(dev, nvec, type);
> +}
> +
> +void pci_msi_legacy_teardown_msi_irqs(struct pci_dev *dev)
> +{
> + arch_teardown_msi_irqs(dev);
> +}
> --- a/drivers/pci/msi/msi.c
> +++ b/drivers/pci/msi/msi.c
> @@ -6,64 +6,16 @@
> * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
> * Copyright (C) 2016 Christoph Hellwig.
> */
> -
> -#include <linux/acpi_iort.h>
> #include <linux/err.h>
> #include <linux/export.h>
> #include <linux/irq.h>
> -#include <linux/irqdomain.h>
> -#include <linux/msi.h>
> -#include <linux/of_irq.h>
> -#include <linux/pci.h>
>
> #include "../pci.h"
> +#include "msi.h"
>
> static int pci_msi_enable = 1;
> int pci_msi_ignore_mask;
>
> -#define msix_table_size(flags) ((flags & PCI_MSIX_FLAGS_QSIZE) + 1)
> -
> -#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN
> -static int pci_msi_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
> -{
> - struct irq_domain *domain;
> -
> - domain = dev_get_msi_domain(&dev->dev);
> - if (domain && irq_domain_is_hierarchy(domain))
> - return msi_domain_alloc_irqs(domain, &dev->dev, nvec);
> -
> - return arch_setup_msi_irqs(dev, nvec, type);
> -}
> -
> -static void pci_msi_teardown_msi_irqs(struct pci_dev *dev)
> -{
> - struct irq_domain *domain;
> -
> - domain = dev_get_msi_domain(&dev->dev);
> - if (domain && irq_domain_is_hierarchy(domain))
> - msi_domain_free_irqs(domain, &dev->dev);
> - else
> - arch_teardown_msi_irqs(dev);
> -}
> -#else
> -#define pci_msi_setup_msi_irqs arch_setup_msi_irqs
> -#define pci_msi_teardown_msi_irqs arch_teardown_msi_irqs
> -#endif
> -
> -/*
> - * PCI 2.3 does not specify mask bits for each MSI interrupt. Attempting to
> - * mask all MSI interrupts by clearing the MSI enable bit does not work
> - * reliably as devices without an INTx disable bit will then generate a
> - * level IRQ which will never be cleared.
> - */
> -static inline __attribute_const__ u32 msi_multi_mask(struct msi_desc *desc)
> -{
> - /* Don't shift by >= width of type */
> - if (desc->pci.msi_attrib.multi_cap >= 5)
> - return 0xffffffff;
> - return (1 << (1 << desc->pci.msi_attrib.multi_cap)) - 1;
> -}
> -
> static noinline void pci_msi_update_mask(struct msi_desc *desc, u32 clear, u32 set)
> {
> raw_spinlock_t *lock = &desc->dev->msi_lock;
> @@ -903,23 +855,6 @@ void pci_disable_msix(struct pci_dev *de
> }
> EXPORT_SYMBOL(pci_disable_msix);
>
> -void pci_no_msi(void)
> -{
> - pci_msi_enable = 0;
> -}
> -
> -/**
> - * pci_msi_enabled - is MSI enabled?
> - *
> - * Returns true if MSI has not been disabled by the command-line option
> - * pci=nomsi.
> - **/
> -int pci_msi_enabled(void)
> -{
> - return pci_msi_enable;
> -}
> -EXPORT_SYMBOL(pci_msi_enabled);
> -
> static int __pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec,
> struct irq_affinity *affd)
> {
> @@ -1195,253 +1130,19 @@ struct pci_dev *msi_desc_to_pci_dev(stru
> }
> EXPORT_SYMBOL(msi_desc_to_pci_dev);
>
> -#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN
> -/**
> - * pci_msi_domain_write_msg - Helper to write MSI message to PCI config space
> - * @irq_data: Pointer to interrupt data of the MSI interrupt
> - * @msg: Pointer to the message
> - */
> -static void pci_msi_domain_write_msg(struct irq_data *irq_data, struct msi_msg *msg)
> -{
> - struct msi_desc *desc = irq_data_get_msi_desc(irq_data);
> -
> - /*
> - * For MSI-X desc->irq is always equal to irq_data->irq. For
> - * MSI only the first interrupt of MULTI MSI passes the test.
> - */
> - if (desc->irq == irq_data->irq)
> - __pci_write_msi_msg(desc, msg);
> -}
> -
> -/**
> - * pci_msi_domain_calc_hwirq - Generate a unique ID for an MSI source
> - * @desc: Pointer to the MSI descriptor
> - *
> - * The ID number is only used within the irqdomain.
> - */
> -static irq_hw_number_t pci_msi_domain_calc_hwirq(struct msi_desc *desc)
> -{
> - struct pci_dev *dev = msi_desc_to_pci_dev(desc);
> -
> - return (irq_hw_number_t)desc->pci.msi_attrib.entry_nr |
> - pci_dev_id(dev) << 11 |
> - (pci_domain_nr(dev->bus) & 0xFFFFFFFF) << 27;
> -}
> -
> -static inline bool pci_msi_desc_is_multi_msi(struct msi_desc *desc)
> -{
> - return !desc->pci.msi_attrib.is_msix && desc->nvec_used > 1;
> -}
> -
> -/**
> - * pci_msi_domain_check_cap - Verify that @domain supports the capabilities
> - * for @dev
> - * @domain: The interrupt domain to check
> - * @info: The domain info for verification
> - * @dev: The device to check
> - *
> - * Returns:
> - * 0 if the functionality is supported
> - * 1 if Multi MSI is requested, but the domain does not support it
> - * -ENOTSUPP otherwise
> - */
> -int pci_msi_domain_check_cap(struct irq_domain *domain,
> - struct msi_domain_info *info, struct device *dev)
> -{
> - struct msi_desc *desc = first_pci_msi_entry(to_pci_dev(dev));
> -
> - /* Special handling to support __pci_enable_msi_range() */
> - if (pci_msi_desc_is_multi_msi(desc) &&
> - !(info->flags & MSI_FLAG_MULTI_PCI_MSI))
> - return 1;
> - else if (desc->pci.msi_attrib.is_msix && !(info->flags & MSI_FLAG_PCI_MSIX))
> - return -ENOTSUPP;
> -
> - return 0;
> -}
> -
> -static int pci_msi_domain_handle_error(struct irq_domain *domain,
> - struct msi_desc *desc, int error)
> -{
> - /* Special handling to support __pci_enable_msi_range() */
> - if (pci_msi_desc_is_multi_msi(desc) && error == -ENOSPC)
> - return 1;
> -
> - return error;
> -}
> -
> -static void pci_msi_domain_set_desc(msi_alloc_info_t *arg,
> - struct msi_desc *desc)
> -{
> - arg->desc = desc;
> - arg->hwirq = pci_msi_domain_calc_hwirq(desc);
> -}
> -
> -static struct msi_domain_ops pci_msi_domain_ops_default = {
> - .set_desc = pci_msi_domain_set_desc,
> - .msi_check = pci_msi_domain_check_cap,
> - .handle_error = pci_msi_domain_handle_error,
> -};
> -
> -static void pci_msi_domain_update_dom_ops(struct msi_domain_info *info)
> -{
> - struct msi_domain_ops *ops = info->ops;
> -
> - if (ops == NULL) {
> - info->ops = &pci_msi_domain_ops_default;
> - } else {
> - if (ops->set_desc == NULL)
> - ops->set_desc = pci_msi_domain_set_desc;
> - if (ops->msi_check == NULL)
> - ops->msi_check = pci_msi_domain_check_cap;
> - if (ops->handle_error == NULL)
> - ops->handle_error = pci_msi_domain_handle_error;
> - }
> -}
> -
> -static void pci_msi_domain_update_chip_ops(struct msi_domain_info *info)
> -{
> - struct irq_chip *chip = info->chip;
> -
> - BUG_ON(!chip);
> - if (!chip->irq_write_msi_msg)
> - chip->irq_write_msi_msg = pci_msi_domain_write_msg;
> - if (!chip->irq_mask)
> - chip->irq_mask = pci_msi_mask_irq;
> - if (!chip->irq_unmask)
> - chip->irq_unmask = pci_msi_unmask_irq;
> -}
> -
> -/**
> - * pci_msi_create_irq_domain - Create a MSI interrupt domain
> - * @fwnode: Optional fwnode of the interrupt controller
> - * @info: MSI domain info
> - * @parent: Parent irq domain
> - *
> - * Updates the domain and chip ops and creates a MSI interrupt domain.
> - *
> - * Returns:
> - * A domain pointer or NULL in case of failure.
> - */
> -struct irq_domain *pci_msi_create_irq_domain(struct fwnode_handle *fwnode,
> - struct msi_domain_info *info,
> - struct irq_domain *parent)
> -{
> - struct irq_domain *domain;
> -
> - if (WARN_ON(info->flags & MSI_FLAG_LEVEL_CAPABLE))
> - info->flags &= ~MSI_FLAG_LEVEL_CAPABLE;
> -
> - if (info->flags & MSI_FLAG_USE_DEF_DOM_OPS)
> - pci_msi_domain_update_dom_ops(info);
> - if (info->flags & MSI_FLAG_USE_DEF_CHIP_OPS)
> - pci_msi_domain_update_chip_ops(info);
> -
> - info->flags |= MSI_FLAG_ACTIVATE_EARLY;
> - if (IS_ENABLED(CONFIG_GENERIC_IRQ_RESERVATION_MODE))
> - info->flags |= MSI_FLAG_MUST_REACTIVATE;
> -
> - /* PCI-MSI is oneshot-safe */
> - info->chip->flags |= IRQCHIP_ONESHOT_SAFE;
> -
> - domain = msi_create_irq_domain(fwnode, info, parent);
> - if (!domain)
> - return NULL;
> -
> - irq_domain_update_bus_token(domain, DOMAIN_BUS_PCI_MSI);
> - return domain;
> -}
> -EXPORT_SYMBOL_GPL(pci_msi_create_irq_domain);
> -
> -/*
> - * Users of the generic MSI infrastructure expect a device to have a single ID,
> - * so with DMA aliases we have to pick the least-worst compromise. Devices with
> - * DMA phantom functions tend to still emit MSIs from the real function number,
> - * so we ignore those and only consider topological aliases where either the
> - * alias device or RID appears on a different bus number. We also make the
> - * reasonable assumption that bridges are walked in an upstream direction (so
> - * the last one seen wins), and the much braver assumption that the most likely
> - * case is that of PCI->PCIe so we should always use the alias RID. This echoes
> - * the logic from intel_irq_remapping's set_msi_sid(), which presumably works
> - * well enough in practice; in the face of the horrible PCIe<->PCI-X conditions
> - * for taking ownership all we can really do is close our eyes and hope...
> - */
> -static int get_msi_id_cb(struct pci_dev *pdev, u16 alias, void *data)
> -{
> - u32 *pa = data;
> - u8 bus = PCI_BUS_NUM(*pa);
> -
> - if (pdev->bus->number != bus || PCI_BUS_NUM(alias) != bus)
> - *pa = alias;
> -
> - return 0;
> -}
> -
> -/**
> - * pci_msi_domain_get_msi_rid - Get the MSI requester id (RID)
> - * @domain: The interrupt domain
> - * @pdev: The PCI device.
> - *
> - * The RID for a device is formed from the alias, with a firmware
> - * supplied mapping applied
> - *
> - * Returns: The RID.
> - */
> -u32 pci_msi_domain_get_msi_rid(struct irq_domain *domain, struct pci_dev *pdev)
> -{
> - struct device_node *of_node;
> - u32 rid = pci_dev_id(pdev);
> -
> - pci_for_each_dma_alias(pdev, get_msi_id_cb, &rid);
> -
> - of_node = irq_domain_get_of_node(domain);
> - rid = of_node ? of_msi_map_id(&pdev->dev, of_node, rid) :
> - iort_msi_map_id(&pdev->dev, rid);
> -
> - return rid;
> -}
> -
> -/**
> - * pci_msi_get_device_domain - Get the MSI domain for a given PCI device
> - * @pdev: The PCI device
> - *
> - * Use the firmware data to find a device-specific MSI domain
> - * (i.e. not one that is set as a default).
> - *
> - * Returns: The corresponding MSI domain or NULL if none has been found.
> - */
> -struct irq_domain *pci_msi_get_device_domain(struct pci_dev *pdev)
> +void pci_no_msi(void)
> {
> - struct irq_domain *dom;
> - u32 rid = pci_dev_id(pdev);
> -
> - pci_for_each_dma_alias(pdev, get_msi_id_cb, &rid);
> - dom = of_msi_map_get_device_domain(&pdev->dev, rid, DOMAIN_BUS_PCI_MSI);
> - if (!dom)
> - dom = iort_get_device_domain(&pdev->dev, rid,
> - DOMAIN_BUS_PCI_MSI);
> - return dom;
> + pci_msi_enable = 0;
> }
>
> /**
> - * pci_dev_has_special_msi_domain - Check whether the device is handled by
> - * a non-standard PCI-MSI domain
> - * @pdev: The PCI device to check.
> + * pci_msi_enabled - is MSI enabled?
> *
> - * Returns: True if the device irqdomain or the bus irqdomain is
> - * non-standard PCI/MSI.
> - */
> -bool pci_dev_has_special_msi_domain(struct pci_dev *pdev)
> + * Returns true if MSI has not been disabled by the command-line option
> + * pci=nomsi.
> + **/
> +int pci_msi_enabled(void)
> {
> - struct irq_domain *dom = dev_get_msi_domain(&pdev->dev);
> -
> - if (!dom)
> - dom = dev_get_msi_domain(&pdev->bus->dev);
> -
> - if (!dom)
> - return true;
> -
> - return dom->bus_token != DOMAIN_BUS_PCI_MSI;
> + return pci_msi_enable;
> }
> -
> -#endif /* CONFIG_PCI_MSI_IRQ_DOMAIN */
> +EXPORT_SYMBOL(pci_msi_enabled);
> --- /dev/null
> +++ b/drivers/pci/msi/msi.h
> @@ -0,0 +1,39 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +
> +#include <linux/pci.h>
> +#include <linux/msi.h>
> +
> +#define msix_table_size(flags) ((flags & PCI_MSIX_FLAGS_QSIZE) + 1)
> +
> +extern int pci_msi_setup_msi_irqs(struct pci_dev *dev, int nvec, int type);
> +extern void pci_msi_teardown_msi_irqs(struct pci_dev *dev);
> +
> +#ifdef CONFIG_PCI_MSI_ARCH_FALLBACKS
> +extern int pci_msi_legacy_setup_msi_irqs(struct pci_dev *dev, int nvec, int type);
> +extern void pci_msi_legacy_teardown_msi_irqs(struct pci_dev *dev);
> +#else
> +static inline int pci_msi_legacy_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
> +{
> + WARN_ON_ONCE(1);
> + return -ENODEV;
> +}
> +
> +static inline void pci_msi_legacy_teardown_msi_irqs(struct pci_dev *dev)
> +{
> + WARN_ON_ONCE(1);
> +}
> +#endif
> +
> +/*
> + * PCI 2.3 does not specify mask bits for each MSI interrupt. Attempting to
> + * mask all MSI interrupts by clearing the MSI enable bit does not work
> + * reliably as devices without an INTx disable bit will then generate a
> + * level IRQ which will never be cleared.
> + */
> +static inline __attribute_const__ u32 msi_multi_mask(struct msi_desc *desc)
> +{
> + /* Don't shift by >= width of type */
> + if (desc->pci.msi_attrib.multi_cap >= 5)
> + return 0xffffffff;
> + return (1 << (1 << desc->pci.msi_attrib.multi_cap)) - 1;
> +}
> --- a/include/linux/msi.h
> +++ b/include/linux/msi.h
> @@ -259,17 +259,6 @@ int arch_setup_msi_irq(struct pci_dev *d
> void arch_teardown_msi_irq(unsigned int irq);
> int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type);
> void arch_teardown_msi_irqs(struct pci_dev *dev);
> -#else
> -static inline int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
> -{
> - WARN_ON_ONCE(1);
> - return -ENODEV;
> -}
> -
> -static inline void arch_teardown_msi_irqs(struct pci_dev *dev)
> -{
> - WARN_ON_ONCE(1);
> -}
> #endif
>
> /*
>
^ permalink raw reply
* Re: [patch V2 17/23] PCI/MSI: Split out !IRQDOMAIN code
From: Bjorn Helgaas @ 2021-12-07 20:59 UTC (permalink / raw)
To: Thomas Gleixner
Cc: linux-hyperv, linux-mips, Paul Mackerras, sparclinux, Wei Liu,
Ashok Raj, x86, Christian Borntraeger, Megha Dey, Jason Gunthorpe,
linux-pci, xen-devel, ath11k, Kevin Tian, Heiko Carstens,
Alex Williamson, Cedric Le Goater, Kalle Valo, Juergen Gross,
Thomas Bogendoerfer, Greg Kroah-Hartman, LKML, Marc Zygnier,
linuxppc-dev
In-Reply-To: <20211206210224.763574089@linutronix.de>
On Mon, Dec 06, 2021 at 11:27:51PM +0100, Thomas Gleixner wrote:
> Split out the non irqdomain code into its own file.
>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> Tested-by: Juergen Gross <jgross@suse.com>
> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
> ---
> V2: Add proper includes and fix variable name - Cedric
> ---
> drivers/pci/msi/Makefile | 5 ++--
> drivers/pci/msi/legacy.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++
> drivers/pci/msi/msi.c | 46 -----------------------------------------
> 3 files changed, 55 insertions(+), 48 deletions(-)
>
> --- a/drivers/pci/msi/Makefile
> +++ b/drivers/pci/msi/Makefile
> @@ -1,5 +1,6 @@
> # SPDX-License-Identifier: GPL-2.0
> #
> # Makefile for the PCI/MSI
> -obj-$(CONFIG_PCI) += pcidev_msi.o
> -obj-$(CONFIG_PCI_MSI) += msi.o
> +obj-$(CONFIG_PCI) += pcidev_msi.o
> +obj-$(CONFIG_PCI_MSI) += msi.o
> +obj-$(CONFIG_PCI_MSI_ARCH_FALLBACKS) += legacy.o
> --- /dev/null
> +++ b/drivers/pci/msi/legacy.c
> @@ -0,0 +1,52 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * PCI Message Signaled Interrupt (MSI).
> + *
> + * Legacy architecture specific setup and teardown mechanism.
> + */
> +#include <linux/msi.h>
> +#include <linux/pci.h>
> +
> +/* Arch hooks */
> +int __weak arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
> +{
> + return -EINVAL;
> +}
> +
> +void __weak arch_teardown_msi_irq(unsigned int irq)
> +{
> +}
> +
> +int __weak arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
> +{
> + struct msi_desc *desc;
> + int ret;
> +
> + /*
> + * If an architecture wants to support multiple MSI, it needs to
> + * override arch_setup_msi_irqs()
> + */
> + if (type == PCI_CAP_ID_MSI && nvec > 1)
> + return 1;
> +
> + for_each_pci_msi_entry(desc, dev) {
> + ret = arch_setup_msi_irq(dev, desc);
> + if (ret)
> + return ret < 0 ? ret : -ENOSPC;
> + }
> +
> + return 0;
> +}
> +
> +void __weak arch_teardown_msi_irqs(struct pci_dev *dev)
> +{
> + struct msi_desc *desc;
> + int i;
> +
> + for_each_pci_msi_entry(desc, dev) {
> + if (desc->irq) {
> + for (i = 0; i < desc->nvec_used; i++)
> + arch_teardown_msi_irq(desc->irq + i);
> + }
> + }
> +}
> --- a/drivers/pci/msi/msi.c
> +++ b/drivers/pci/msi/msi.c
> @@ -50,52 +50,6 @@ static void pci_msi_teardown_msi_irqs(st
> #define pci_msi_teardown_msi_irqs arch_teardown_msi_irqs
> #endif
>
> -#ifdef CONFIG_PCI_MSI_ARCH_FALLBACKS
> -/* Arch hooks */
> -int __weak arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
> -{
> - return -EINVAL;
> -}
> -
> -void __weak arch_teardown_msi_irq(unsigned int irq)
> -{
> -}
> -
> -int __weak arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
> -{
> - struct msi_desc *entry;
> - int ret;
> -
> - /*
> - * If an architecture wants to support multiple MSI, it needs to
> - * override arch_setup_msi_irqs()
> - */
> - if (type == PCI_CAP_ID_MSI && nvec > 1)
> - return 1;
> -
> - for_each_pci_msi_entry(entry, dev) {
> - ret = arch_setup_msi_irq(dev, entry);
> - if (ret < 0)
> - return ret;
> - if (ret > 0)
> - return -ENOSPC;
> - }
> -
> - return 0;
> -}
> -
> -void __weak arch_teardown_msi_irqs(struct pci_dev *dev)
> -{
> - int i;
> - struct msi_desc *entry;
> -
> - for_each_pci_msi_entry(entry, dev)
> - if (entry->irq)
> - for (i = 0; i < entry->nvec_used; i++)
> - arch_teardown_msi_irq(entry->irq + i);
> -}
> -#endif /* CONFIG_PCI_MSI_ARCH_FALLBACKS */
> -
> /*
> * PCI 2.3 does not specify mask bits for each MSI interrupt. Attempting to
> * mask all MSI interrupts by clearing the MSI enable bit does not work
>
^ permalink raw reply
* Re: [patch V2 16/23] PCI/MSI: Split out CONFIG_PCI_MSI independent part
From: Bjorn Helgaas @ 2021-12-07 20:58 UTC (permalink / raw)
To: Thomas Gleixner
Cc: linux-hyperv, linux-mips, Paul Mackerras, sparclinux, Wei Liu,
Ashok Raj, x86, Christian Borntraeger, Megha Dey, Jason Gunthorpe,
linux-pci, xen-devel, ath11k, Kevin Tian, Heiko Carstens,
Alex Williamson, Cedric Le Goater, Kalle Valo, Juergen Gross,
Thomas Bogendoerfer, Greg Kroah-Hartman, LKML, Marc Zygnier,
linuxppc-dev
In-Reply-To: <20211206210224.710137730@linutronix.de>
On Mon, Dec 06, 2021 at 11:27:49PM +0100, Thomas Gleixner wrote:
> These functions are required even when CONFIG_PCI_MSI is not set. Move them
> to their own file.
>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> Tested-by: Juergen Gross <jgross@suse.com>
> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
> ---
> drivers/pci/msi/Makefile | 3 ++-
> drivers/pci/msi/msi.c | 39 ---------------------------------------
> drivers/pci/msi/pcidev_msi.c | 43 +++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 45 insertions(+), 40 deletions(-)
>
> --- a/drivers/pci/msi/Makefile
> +++ b/drivers/pci/msi/Makefile
> @@ -1,4 +1,5 @@
> # SPDX-License-Identifier: GPL-2.0
> #
> # Makefile for the PCI/MSI
> -obj-$(CONFIG_PCI) += msi.o
> +obj-$(CONFIG_PCI) += pcidev_msi.o
> +obj-$(CONFIG_PCI_MSI) += msi.o
> --- a/drivers/pci/msi/msi.c
> +++ b/drivers/pci/msi/msi.c
> @@ -18,8 +18,6 @@
>
> #include "../pci.h"
>
> -#ifdef CONFIG_PCI_MSI
> -
> static int pci_msi_enable = 1;
> int pci_msi_ignore_mask;
>
> @@ -1493,40 +1491,3 @@ bool pci_dev_has_special_msi_domain(stru
> }
>
> #endif /* CONFIG_PCI_MSI_IRQ_DOMAIN */
> -#endif /* CONFIG_PCI_MSI */
> -
> -void pci_msi_init(struct pci_dev *dev)
> -{
> - u16 ctrl;
> -
> - /*
> - * Disable the MSI hardware to avoid screaming interrupts
> - * during boot. This is the power on reset default so
> - * usually this should be a noop.
> - */
> - dev->msi_cap = pci_find_capability(dev, PCI_CAP_ID_MSI);
> - if (!dev->msi_cap)
> - return;
> -
> - pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &ctrl);
> - if (ctrl & PCI_MSI_FLAGS_ENABLE)
> - pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS,
> - ctrl & ~PCI_MSI_FLAGS_ENABLE);
> -
> - if (!(ctrl & PCI_MSI_FLAGS_64BIT))
> - dev->no_64bit_msi = 1;
> -}
> -
> -void pci_msix_init(struct pci_dev *dev)
> -{
> - u16 ctrl;
> -
> - dev->msix_cap = pci_find_capability(dev, PCI_CAP_ID_MSIX);
> - if (!dev->msix_cap)
> - return;
> -
> - pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &ctrl);
> - if (ctrl & PCI_MSIX_FLAGS_ENABLE)
> - pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS,
> - ctrl & ~PCI_MSIX_FLAGS_ENABLE);
> -}
> --- /dev/null
> +++ b/drivers/pci/msi/pcidev_msi.c
> @@ -0,0 +1,43 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * MSI[X} related functions which are available unconditionally.
> + */
> +#include "../pci.h"
> +
> +/*
> + * Disable the MSI[X] hardware to avoid screaming interrupts during boot.
> + * This is the power on reset default so usually this should be a noop.
> + */
> +
> +void pci_msi_init(struct pci_dev *dev)
> +{
> + u16 ctrl;
> +
> + dev->msi_cap = pci_find_capability(dev, PCI_CAP_ID_MSI);
> + if (!dev->msi_cap)
> + return;
> +
> + pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &ctrl);
> + if (ctrl & PCI_MSI_FLAGS_ENABLE) {
> + pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS,
> + ctrl & ~PCI_MSI_FLAGS_ENABLE);
> + }
> +
> + if (!(ctrl & PCI_MSI_FLAGS_64BIT))
> + dev->no_64bit_msi = 1;
> +}
> +
> +void pci_msix_init(struct pci_dev *dev)
> +{
> + u16 ctrl;
> +
> + dev->msix_cap = pci_find_capability(dev, PCI_CAP_ID_MSIX);
> + if (!dev->msix_cap)
> + return;
> +
> + pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &ctrl);
> + if (ctrl & PCI_MSIX_FLAGS_ENABLE) {
> + pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS,
> + ctrl & ~PCI_MSIX_FLAGS_ENABLE);
> + }
> +}
>
^ permalink raw reply
* Re: [patch V2 15/23] PCI/MSI: Move code into a separate directory
From: Bjorn Helgaas @ 2021-12-07 20:57 UTC (permalink / raw)
To: Thomas Gleixner
Cc: linux-hyperv, linux-mips, Paul Mackerras, sparclinux, Wei Liu,
Ashok Raj, x86, Christian Borntraeger, Megha Dey, Jason Gunthorpe,
linux-pci, xen-devel, ath11k, Kevin Tian, Heiko Carstens,
Alex Williamson, Cedric Le Goater, Kalle Valo, Juergen Gross,
Thomas Bogendoerfer, Greg Kroah-Hartman, LKML, Marc Zygnier,
linuxppc-dev
In-Reply-To: <20211206210224.655043033@linutronix.de>
On Mon, Dec 06, 2021 at 11:27:47PM +0100, Thomas Gleixner wrote:
> msi.c is getting larger and really could do with a splitup. Move it into
> it's own directory to prepare for that.
s/it's/its/
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> Tested-by: Juergen Gross <jgross@suse.com>
> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
> ---
> Documentation/driver-api/pci/pci.rst | 2
> drivers/pci/Makefile | 3
> drivers/pci/msi.c | 1532 -----------------------------------
> drivers/pci/msi/Makefile | 4
> drivers/pci/msi/msi.c | 1532 +++++++++++++++++++++++++++++++++++
> 5 files changed, 1539 insertions(+), 1534 deletions(-)
>
> --- a/Documentation/driver-api/pci/pci.rst
> +++ b/Documentation/driver-api/pci/pci.rst
> @@ -13,7 +13,7 @@ PCI Support Library
> .. kernel-doc:: drivers/pci/search.c
> :export:
>
> -.. kernel-doc:: drivers/pci/msi.c
> +.. kernel-doc:: drivers/pci/msi/msi.c
> :export:
>
> .. kernel-doc:: drivers/pci/bus.c
> --- a/drivers/pci/Makefile
> +++ b/drivers/pci/Makefile
> @@ -5,8 +5,9 @@
> obj-$(CONFIG_PCI) += access.o bus.o probe.o host-bridge.o \
> remove.o pci.o pci-driver.o search.o \
> pci-sysfs.o rom.o setup-res.o irq.o vpd.o \
> - setup-bus.o vc.o mmap.o setup-irq.o msi.o
> + setup-bus.o vc.o mmap.o setup-irq.o
>
> +obj-$(CONFIG_PCI) += msi/
> obj-$(CONFIG_PCI) += pcie/
>
> ifdef CONFIG_PCI
> --- a/drivers/pci/msi.c
> +++ /dev/null
> @@ -1,1532 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0
> -/*
> - * PCI Message Signaled Interrupt (MSI)
> - *
> - * Copyright (C) 2003-2004 Intel
> - * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
> - * Copyright (C) 2016 Christoph Hellwig.
> - */
> -
> -#include <linux/acpi_iort.h>
> -#include <linux/err.h>
> -#include <linux/export.h>
> -#include <linux/irq.h>
> -#include <linux/irqdomain.h>
> -#include <linux/msi.h>
> -#include <linux/of_irq.h>
> -#include <linux/pci.h>
> -
> -#include "pci.h"
> -
> -#ifdef CONFIG_PCI_MSI
> -
> -static int pci_msi_enable = 1;
> -int pci_msi_ignore_mask;
> -
> -#define msix_table_size(flags) ((flags & PCI_MSIX_FLAGS_QSIZE) + 1)
> -
> -#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN
> -static int pci_msi_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
> -{
> - struct irq_domain *domain;
> -
> - domain = dev_get_msi_domain(&dev->dev);
> - if (domain && irq_domain_is_hierarchy(domain))
> - return msi_domain_alloc_irqs(domain, &dev->dev, nvec);
> -
> - return arch_setup_msi_irqs(dev, nvec, type);
> -}
> -
> -static void pci_msi_teardown_msi_irqs(struct pci_dev *dev)
> -{
> - struct irq_domain *domain;
> -
> - domain = dev_get_msi_domain(&dev->dev);
> - if (domain && irq_domain_is_hierarchy(domain))
> - msi_domain_free_irqs(domain, &dev->dev);
> - else
> - arch_teardown_msi_irqs(dev);
> -}
> -#else
> -#define pci_msi_setup_msi_irqs arch_setup_msi_irqs
> -#define pci_msi_teardown_msi_irqs arch_teardown_msi_irqs
> -#endif
> -
> -#ifdef CONFIG_PCI_MSI_ARCH_FALLBACKS
> -/* Arch hooks */
> -int __weak arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
> -{
> - return -EINVAL;
> -}
> -
> -void __weak arch_teardown_msi_irq(unsigned int irq)
> -{
> -}
> -
> -int __weak arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
> -{
> - struct msi_desc *entry;
> - int ret;
> -
> - /*
> - * If an architecture wants to support multiple MSI, it needs to
> - * override arch_setup_msi_irqs()
> - */
> - if (type == PCI_CAP_ID_MSI && nvec > 1)
> - return 1;
> -
> - for_each_pci_msi_entry(entry, dev) {
> - ret = arch_setup_msi_irq(dev, entry);
> - if (ret < 0)
> - return ret;
> - if (ret > 0)
> - return -ENOSPC;
> - }
> -
> - return 0;
> -}
> -
> -void __weak arch_teardown_msi_irqs(struct pci_dev *dev)
> -{
> - int i;
> - struct msi_desc *entry;
> -
> - for_each_pci_msi_entry(entry, dev)
> - if (entry->irq)
> - for (i = 0; i < entry->nvec_used; i++)
> - arch_teardown_msi_irq(entry->irq + i);
> -}
> -#endif /* CONFIG_PCI_MSI_ARCH_FALLBACKS */
> -
> -/*
> - * PCI 2.3 does not specify mask bits for each MSI interrupt. Attempting to
> - * mask all MSI interrupts by clearing the MSI enable bit does not work
> - * reliably as devices without an INTx disable bit will then generate a
> - * level IRQ which will never be cleared.
> - */
> -static inline __attribute_const__ u32 msi_multi_mask(struct msi_desc *desc)
> -{
> - /* Don't shift by >= width of type */
> - if (desc->pci.msi_attrib.multi_cap >= 5)
> - return 0xffffffff;
> - return (1 << (1 << desc->pci.msi_attrib.multi_cap)) - 1;
> -}
> -
> -static noinline void pci_msi_update_mask(struct msi_desc *desc, u32 clear, u32 set)
> -{
> - raw_spinlock_t *lock = &desc->dev->msi_lock;
> - unsigned long flags;
> -
> - if (!desc->pci.msi_attrib.can_mask)
> - return;
> -
> - raw_spin_lock_irqsave(lock, flags);
> - desc->pci.msi_mask &= ~clear;
> - desc->pci.msi_mask |= set;
> - pci_write_config_dword(msi_desc_to_pci_dev(desc), desc->pci.mask_pos,
> - desc->pci.msi_mask);
> - raw_spin_unlock_irqrestore(lock, flags);
> -}
> -
> -static inline void pci_msi_mask(struct msi_desc *desc, u32 mask)
> -{
> - pci_msi_update_mask(desc, 0, mask);
> -}
> -
> -static inline void pci_msi_unmask(struct msi_desc *desc, u32 mask)
> -{
> - pci_msi_update_mask(desc, mask, 0);
> -}
> -
> -static inline void __iomem *pci_msix_desc_addr(struct msi_desc *desc)
> -{
> - return desc->pci.mask_base + desc->pci.msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE;
> -}
> -
> -/*
> - * This internal function does not flush PCI writes to the device. All
> - * users must ensure that they read from the device before either assuming
> - * that the device state is up to date, or returning out of this file.
> - * It does not affect the msi_desc::msix_ctrl cache either. Use with care!
> - */
> -static void pci_msix_write_vector_ctrl(struct msi_desc *desc, u32 ctrl)
> -{
> - void __iomem *desc_addr = pci_msix_desc_addr(desc);
> -
> - if (desc->pci.msi_attrib.can_mask)
> - writel(ctrl, desc_addr + PCI_MSIX_ENTRY_VECTOR_CTRL);
> -}
> -
> -static inline void pci_msix_mask(struct msi_desc *desc)
> -{
> - desc->pci.msix_ctrl |= PCI_MSIX_ENTRY_CTRL_MASKBIT;
> - pci_msix_write_vector_ctrl(desc, desc->pci.msix_ctrl);
> - /* Flush write to device */
> - readl(desc->pci.mask_base);
> -}
> -
> -static inline void pci_msix_unmask(struct msi_desc *desc)
> -{
> - desc->pci.msix_ctrl &= ~PCI_MSIX_ENTRY_CTRL_MASKBIT;
> - pci_msix_write_vector_ctrl(desc, desc->pci.msix_ctrl);
> -}
> -
> -static void __pci_msi_mask_desc(struct msi_desc *desc, u32 mask)
> -{
> - if (desc->pci.msi_attrib.is_msix)
> - pci_msix_mask(desc);
> - else
> - pci_msi_mask(desc, mask);
> -}
> -
> -static void __pci_msi_unmask_desc(struct msi_desc *desc, u32 mask)
> -{
> - if (desc->pci.msi_attrib.is_msix)
> - pci_msix_unmask(desc);
> - else
> - pci_msi_unmask(desc, mask);
> -}
> -
> -/**
> - * pci_msi_mask_irq - Generic IRQ chip callback to mask PCI/MSI interrupts
> - * @data: pointer to irqdata associated to that interrupt
> - */
> -void pci_msi_mask_irq(struct irq_data *data)
> -{
> - struct msi_desc *desc = irq_data_get_msi_desc(data);
> -
> - __pci_msi_mask_desc(desc, BIT(data->irq - desc->irq));
> -}
> -EXPORT_SYMBOL_GPL(pci_msi_mask_irq);
> -
> -/**
> - * pci_msi_unmask_irq - Generic IRQ chip callback to unmask PCI/MSI interrupts
> - * @data: pointer to irqdata associated to that interrupt
> - */
> -void pci_msi_unmask_irq(struct irq_data *data)
> -{
> - struct msi_desc *desc = irq_data_get_msi_desc(data);
> -
> - __pci_msi_unmask_desc(desc, BIT(data->irq - desc->irq));
> -}
> -EXPORT_SYMBOL_GPL(pci_msi_unmask_irq);
> -
> -void __pci_read_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
> -{
> - struct pci_dev *dev = msi_desc_to_pci_dev(entry);
> -
> - BUG_ON(dev->current_state != PCI_D0);
> -
> - if (entry->pci.msi_attrib.is_msix) {
> - void __iomem *base = pci_msix_desc_addr(entry);
> -
> - if (WARN_ON_ONCE(entry->pci.msi_attrib.is_virtual))
> - return;
> -
> - msg->address_lo = readl(base + PCI_MSIX_ENTRY_LOWER_ADDR);
> - msg->address_hi = readl(base + PCI_MSIX_ENTRY_UPPER_ADDR);
> - msg->data = readl(base + PCI_MSIX_ENTRY_DATA);
> - } else {
> - int pos = dev->msi_cap;
> - u16 data;
> -
> - pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_LO,
> - &msg->address_lo);
> - if (entry->pci.msi_attrib.is_64) {
> - pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_HI,
> - &msg->address_hi);
> - pci_read_config_word(dev, pos + PCI_MSI_DATA_64, &data);
> - } else {
> - msg->address_hi = 0;
> - pci_read_config_word(dev, pos + PCI_MSI_DATA_32, &data);
> - }
> - msg->data = data;
> - }
> -}
> -
> -void __pci_write_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
> -{
> - struct pci_dev *dev = msi_desc_to_pci_dev(entry);
> -
> - if (dev->current_state != PCI_D0 || pci_dev_is_disconnected(dev)) {
> - /* Don't touch the hardware now */
> - } else if (entry->pci.msi_attrib.is_msix) {
> - void __iomem *base = pci_msix_desc_addr(entry);
> - u32 ctrl = entry->pci.msix_ctrl;
> - bool unmasked = !(ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT);
> -
> - if (entry->pci.msi_attrib.is_virtual)
> - goto skip;
> -
> - /*
> - * The specification mandates that the entry is masked
> - * when the message is modified:
> - *
> - * "If software changes the Address or Data value of an
> - * entry while the entry is unmasked, the result is
> - * undefined."
> - */
> - if (unmasked)
> - pci_msix_write_vector_ctrl(entry, ctrl | PCI_MSIX_ENTRY_CTRL_MASKBIT);
> -
> - writel(msg->address_lo, base + PCI_MSIX_ENTRY_LOWER_ADDR);
> - writel(msg->address_hi, base + PCI_MSIX_ENTRY_UPPER_ADDR);
> - writel(msg->data, base + PCI_MSIX_ENTRY_DATA);
> -
> - if (unmasked)
> - pci_msix_write_vector_ctrl(entry, ctrl);
> -
> - /* Ensure that the writes are visible in the device */
> - readl(base + PCI_MSIX_ENTRY_DATA);
> - } else {
> - int pos = dev->msi_cap;
> - u16 msgctl;
> -
> - pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &msgctl);
> - msgctl &= ~PCI_MSI_FLAGS_QSIZE;
> - msgctl |= entry->pci.msi_attrib.multiple << 4;
> - pci_write_config_word(dev, pos + PCI_MSI_FLAGS, msgctl);
> -
> - pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_LO,
> - msg->address_lo);
> - if (entry->pci.msi_attrib.is_64) {
> - pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_HI,
> - msg->address_hi);
> - pci_write_config_word(dev, pos + PCI_MSI_DATA_64,
> - msg->data);
> - } else {
> - pci_write_config_word(dev, pos + PCI_MSI_DATA_32,
> - msg->data);
> - }
> - /* Ensure that the writes are visible in the device */
> - pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &msgctl);
> - }
> -
> -skip:
> - entry->msg = *msg;
> -
> - if (entry->write_msi_msg)
> - entry->write_msi_msg(entry, entry->write_msi_msg_data);
> -
> -}
> -
> -void pci_write_msi_msg(unsigned int irq, struct msi_msg *msg)
> -{
> - struct msi_desc *entry = irq_get_msi_desc(irq);
> -
> - __pci_write_msi_msg(entry, msg);
> -}
> -EXPORT_SYMBOL_GPL(pci_write_msi_msg);
> -
> -static void free_msi_irqs(struct pci_dev *dev)
> -{
> - struct list_head *msi_list = dev_to_msi_list(&dev->dev);
> - struct msi_desc *entry, *tmp;
> - int i;
> -
> - for_each_pci_msi_entry(entry, dev)
> - if (entry->irq)
> - for (i = 0; i < entry->nvec_used; i++)
> - BUG_ON(irq_has_action(entry->irq + i));
> -
> - if (dev->msi_irq_groups) {
> - msi_destroy_sysfs(&dev->dev, dev->msi_irq_groups);
> - dev->msi_irq_groups = NULL;
> - }
> -
> - pci_msi_teardown_msi_irqs(dev);
> -
> - list_for_each_entry_safe(entry, tmp, msi_list, list) {
> - if (entry->pci.msi_attrib.is_msix) {
> - if (list_is_last(&entry->list, msi_list))
> - iounmap(entry->pci.mask_base);
> - }
> -
> - list_del(&entry->list);
> - free_msi_entry(entry);
> - }
> -}
> -
> -static void pci_intx_for_msi(struct pci_dev *dev, int enable)
> -{
> - if (!(dev->dev_flags & PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG))
> - pci_intx(dev, enable);
> -}
> -
> -static void pci_msi_set_enable(struct pci_dev *dev, int enable)
> -{
> - u16 control;
> -
> - pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);
> - control &= ~PCI_MSI_FLAGS_ENABLE;
> - if (enable)
> - control |= PCI_MSI_FLAGS_ENABLE;
> - pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control);
> -}
> -
> -/*
> - * Architecture override returns true when the PCI MSI message should be
> - * written by the generic restore function.
> - */
> -bool __weak arch_restore_msi_irqs(struct pci_dev *dev)
> -{
> - return true;
> -}
> -
> -static void __pci_restore_msi_state(struct pci_dev *dev)
> -{
> - struct msi_desc *entry;
> - u16 control;
> -
> - if (!dev->msi_enabled)
> - return;
> -
> - entry = irq_get_msi_desc(dev->irq);
> -
> - pci_intx_for_msi(dev, 0);
> - pci_msi_set_enable(dev, 0);
> - if (arch_restore_msi_irqs(dev))
> - __pci_write_msi_msg(entry, &entry->msg);
> -
> - pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);
> - pci_msi_update_mask(entry, 0, 0);
> - control &= ~PCI_MSI_FLAGS_QSIZE;
> - control |= (entry->pci.msi_attrib.multiple << 4) | PCI_MSI_FLAGS_ENABLE;
> - pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control);
> -}
> -
> -static void pci_msix_clear_and_set_ctrl(struct pci_dev *dev, u16 clear, u16 set)
> -{
> - u16 ctrl;
> -
> - pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &ctrl);
> - ctrl &= ~clear;
> - ctrl |= set;
> - pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, ctrl);
> -}
> -
> -static void __pci_restore_msix_state(struct pci_dev *dev)
> -{
> - struct msi_desc *entry;
> - bool write_msg;
> -
> - if (!dev->msix_enabled)
> - return;
> - BUG_ON(list_empty(dev_to_msi_list(&dev->dev)));
> -
> - /* route the table */
> - pci_intx_for_msi(dev, 0);
> - pci_msix_clear_and_set_ctrl(dev, 0,
> - PCI_MSIX_FLAGS_ENABLE | PCI_MSIX_FLAGS_MASKALL);
> -
> - write_msg = arch_restore_msi_irqs(dev);
> -
> - for_each_pci_msi_entry(entry, dev) {
> - if (write_msg)
> - __pci_write_msi_msg(entry, &entry->msg);
> - pci_msix_write_vector_ctrl(entry, entry->pci.msix_ctrl);
> - }
> -
> - pci_msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_MASKALL, 0);
> -}
> -
> -void pci_restore_msi_state(struct pci_dev *dev)
> -{
> - __pci_restore_msi_state(dev);
> - __pci_restore_msix_state(dev);
> -}
> -EXPORT_SYMBOL_GPL(pci_restore_msi_state);
> -
> -static struct msi_desc *
> -msi_setup_entry(struct pci_dev *dev, int nvec, struct irq_affinity *affd)
> -{
> - struct irq_affinity_desc *masks = NULL;
> - struct msi_desc *entry;
> - u16 control;
> -
> - if (affd)
> - masks = irq_create_affinity_masks(nvec, affd);
> -
> - /* MSI Entry Initialization */
> - entry = alloc_msi_entry(&dev->dev, nvec, masks);
> - if (!entry)
> - goto out;
> -
> - pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);
> - /* Lies, damned lies, and MSIs */
> - if (dev->dev_flags & PCI_DEV_FLAGS_HAS_MSI_MASKING)
> - control |= PCI_MSI_FLAGS_MASKBIT;
> -
> - entry->pci.msi_attrib.is_msix = 0;
> - entry->pci.msi_attrib.is_64 = !!(control & PCI_MSI_FLAGS_64BIT);
> - entry->pci.msi_attrib.is_virtual = 0;
> - entry->pci.msi_attrib.entry_nr = 0;
> - entry->pci.msi_attrib.can_mask = !pci_msi_ignore_mask &&
> - !!(control & PCI_MSI_FLAGS_MASKBIT);
> - entry->pci.msi_attrib.default_irq = dev->irq; /* Save IOAPIC IRQ */
> - entry->pci.msi_attrib.multi_cap = (control & PCI_MSI_FLAGS_QMASK) >> 1;
> - entry->pci.msi_attrib.multiple = ilog2(__roundup_pow_of_two(nvec));
> -
> - if (control & PCI_MSI_FLAGS_64BIT)
> - entry->pci.mask_pos = dev->msi_cap + PCI_MSI_MASK_64;
> - else
> - entry->pci.mask_pos = dev->msi_cap + PCI_MSI_MASK_32;
> -
> - /* Save the initial mask status */
> - if (entry->pci.msi_attrib.can_mask)
> - pci_read_config_dword(dev, entry->pci.mask_pos, &entry->pci.msi_mask);
> -
> -out:
> - kfree(masks);
> - return entry;
> -}
> -
> -static int msi_verify_entries(struct pci_dev *dev)
> -{
> - struct msi_desc *entry;
> -
> - if (!dev->no_64bit_msi)
> - return 0;
> -
> - for_each_pci_msi_entry(entry, dev) {
> - if (entry->msg.address_hi) {
> - pci_err(dev, "arch assigned 64-bit MSI address %#x%08x but device only supports 32 bits\n",
> - entry->msg.address_hi, entry->msg.address_lo);
> - return -EIO;
> - }
> - }
> - return 0;
> -}
> -
> -/**
> - * msi_capability_init - configure device's MSI capability structure
> - * @dev: pointer to the pci_dev data structure of MSI device function
> - * @nvec: number of interrupts to allocate
> - * @affd: description of automatic IRQ affinity assignments (may be %NULL)
> - *
> - * Setup the MSI capability structure of the device with the requested
> - * number of interrupts. A return value of zero indicates the successful
> - * setup of an entry with the new MSI IRQ. A negative return value indicates
> - * an error, and a positive return value indicates the number of interrupts
> - * which could have been allocated.
> - */
> -static int msi_capability_init(struct pci_dev *dev, int nvec,
> - struct irq_affinity *affd)
> -{
> - const struct attribute_group **groups;
> - struct msi_desc *entry;
> - int ret;
> -
> - pci_msi_set_enable(dev, 0); /* Disable MSI during set up */
> -
> - entry = msi_setup_entry(dev, nvec, affd);
> - if (!entry)
> - return -ENOMEM;
> -
> - /* All MSIs are unmasked by default; mask them all */
> - pci_msi_mask(entry, msi_multi_mask(entry));
> -
> - list_add_tail(&entry->list, dev_to_msi_list(&dev->dev));
> -
> - /* Configure MSI capability structure */
> - ret = pci_msi_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSI);
> - if (ret)
> - goto err;
> -
> - ret = msi_verify_entries(dev);
> - if (ret)
> - goto err;
> -
> - groups = msi_populate_sysfs(&dev->dev);
> - if (IS_ERR(groups)) {
> - ret = PTR_ERR(groups);
> - goto err;
> - }
> -
> - dev->msi_irq_groups = groups;
> -
> - /* Set MSI enabled bits */
> - pci_intx_for_msi(dev, 0);
> - pci_msi_set_enable(dev, 1);
> - dev->msi_enabled = 1;
> -
> - pcibios_free_irq(dev);
> - dev->irq = entry->irq;
> - return 0;
> -
> -err:
> - pci_msi_unmask(entry, msi_multi_mask(entry));
> - free_msi_irqs(dev);
> - return ret;
> -}
> -
> -static void __iomem *msix_map_region(struct pci_dev *dev,
> - unsigned int nr_entries)
> -{
> - resource_size_t phys_addr;
> - u32 table_offset;
> - unsigned long flags;
> - u8 bir;
> -
> - pci_read_config_dword(dev, dev->msix_cap + PCI_MSIX_TABLE,
> - &table_offset);
> - bir = (u8)(table_offset & PCI_MSIX_TABLE_BIR);
> - flags = pci_resource_flags(dev, bir);
> - if (!flags || (flags & IORESOURCE_UNSET))
> - return NULL;
> -
> - table_offset &= PCI_MSIX_TABLE_OFFSET;
> - phys_addr = pci_resource_start(dev, bir) + table_offset;
> -
> - return ioremap(phys_addr, nr_entries * PCI_MSIX_ENTRY_SIZE);
> -}
> -
> -static int msix_setup_entries(struct pci_dev *dev, void __iomem *base,
> - struct msix_entry *entries, int nvec,
> - struct irq_affinity *affd)
> -{
> - struct irq_affinity_desc *curmsk, *masks = NULL;
> - struct msi_desc *entry;
> - void __iomem *addr;
> - int ret, i;
> - int vec_count = pci_msix_vec_count(dev);
> -
> - if (affd)
> - masks = irq_create_affinity_masks(nvec, affd);
> -
> - for (i = 0, curmsk = masks; i < nvec; i++) {
> - entry = alloc_msi_entry(&dev->dev, 1, curmsk);
> - if (!entry) {
> - if (!i)
> - iounmap(base);
> - else
> - free_msi_irqs(dev);
> - /* No enough memory. Don't try again */
> - ret = -ENOMEM;
> - goto out;
> - }
> -
> - entry->pci.msi_attrib.is_msix = 1;
> - entry->pci.msi_attrib.is_64 = 1;
> -
> - if (entries)
> - entry->pci.msi_attrib.entry_nr = entries[i].entry;
> - else
> - entry->pci.msi_attrib.entry_nr = i;
> -
> - entry->pci.msi_attrib.is_virtual =
> - entry->pci.msi_attrib.entry_nr >= vec_count;
> -
> - entry->pci.msi_attrib.can_mask = !pci_msi_ignore_mask &&
> - !entry->pci.msi_attrib.is_virtual;
> -
> - entry->pci.msi_attrib.default_irq = dev->irq;
> - entry->pci.mask_base = base;
> -
> - if (entry->pci.msi_attrib.can_mask) {
> - addr = pci_msix_desc_addr(entry);
> - entry->pci.msix_ctrl = readl(addr + PCI_MSIX_ENTRY_VECTOR_CTRL);
> - }
> -
> - list_add_tail(&entry->list, dev_to_msi_list(&dev->dev));
> - if (masks)
> - curmsk++;
> - }
> - ret = 0;
> -out:
> - kfree(masks);
> - return ret;
> -}
> -
> -static void msix_update_entries(struct pci_dev *dev, struct msix_entry *entries)
> -{
> - struct msi_desc *entry;
> -
> - if (entries) {
> - for_each_pci_msi_entry(entry, dev) {
> - entries->vector = entry->irq;
> - entries++;
> - }
> - }
> -}
> -
> -static void msix_mask_all(void __iomem *base, int tsize)
> -{
> - u32 ctrl = PCI_MSIX_ENTRY_CTRL_MASKBIT;
> - int i;
> -
> - if (pci_msi_ignore_mask)
> - return;
> -
> - for (i = 0; i < tsize; i++, base += PCI_MSIX_ENTRY_SIZE)
> - writel(ctrl, base + PCI_MSIX_ENTRY_VECTOR_CTRL);
> -}
> -
> -/**
> - * msix_capability_init - configure device's MSI-X capability
> - * @dev: pointer to the pci_dev data structure of MSI-X device function
> - * @entries: pointer to an array of struct msix_entry entries
> - * @nvec: number of @entries
> - * @affd: Optional pointer to enable automatic affinity assignment
> - *
> - * Setup the MSI-X capability structure of device function with a
> - * single MSI-X IRQ. A return of zero indicates the successful setup of
> - * requested MSI-X entries with allocated IRQs or non-zero for otherwise.
> - **/
> -static int msix_capability_init(struct pci_dev *dev, struct msix_entry *entries,
> - int nvec, struct irq_affinity *affd)
> -{
> - const struct attribute_group **groups;
> - void __iomem *base;
> - int ret, tsize;
> - u16 control;
> -
> - /*
> - * Some devices require MSI-X to be enabled before the MSI-X
> - * registers can be accessed. Mask all the vectors to prevent
> - * interrupts coming in before they're fully set up.
> - */
> - pci_msix_clear_and_set_ctrl(dev, 0, PCI_MSIX_FLAGS_MASKALL |
> - PCI_MSIX_FLAGS_ENABLE);
> -
> - pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &control);
> - /* Request & Map MSI-X table region */
> - tsize = msix_table_size(control);
> - base = msix_map_region(dev, tsize);
> - if (!base) {
> - ret = -ENOMEM;
> - goto out_disable;
> - }
> -
> - /* Ensure that all table entries are masked. */
> - msix_mask_all(base, tsize);
> -
> - ret = msix_setup_entries(dev, base, entries, nvec, affd);
> - if (ret)
> - goto out_disable;
> -
> - ret = pci_msi_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSIX);
> - if (ret)
> - goto out_avail;
> -
> - /* Check if all MSI entries honor device restrictions */
> - ret = msi_verify_entries(dev);
> - if (ret)
> - goto out_free;
> -
> - msix_update_entries(dev, entries);
> -
> - groups = msi_populate_sysfs(&dev->dev);
> - if (IS_ERR(groups)) {
> - ret = PTR_ERR(groups);
> - goto out_free;
> - }
> -
> - dev->msi_irq_groups = groups;
> -
> - /* Set MSI-X enabled bits and unmask the function */
> - pci_intx_for_msi(dev, 0);
> - dev->msix_enabled = 1;
> - pci_msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_MASKALL, 0);
> -
> - pcibios_free_irq(dev);
> - return 0;
> -
> -out_avail:
> - if (ret < 0) {
> - /*
> - * If we had some success, report the number of IRQs
> - * we succeeded in setting up.
> - */
> - struct msi_desc *entry;
> - int avail = 0;
> -
> - for_each_pci_msi_entry(entry, dev) {
> - if (entry->irq != 0)
> - avail++;
> - }
> - if (avail != 0)
> - ret = avail;
> - }
> -
> -out_free:
> - free_msi_irqs(dev);
> -
> -out_disable:
> - pci_msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_ENABLE, 0);
> -
> - return ret;
> -}
> -
> -/**
> - * pci_msi_supported - check whether MSI may be enabled on a device
> - * @dev: pointer to the pci_dev data structure of MSI device function
> - * @nvec: how many MSIs have been requested?
> - *
> - * Look at global flags, the device itself, and its parent buses
> - * to determine if MSI/-X are supported for the device. If MSI/-X is
> - * supported return 1, else return 0.
> - **/
> -static int pci_msi_supported(struct pci_dev *dev, int nvec)
> -{
> - struct pci_bus *bus;
> -
> - /* MSI must be globally enabled and supported by the device */
> - if (!pci_msi_enable)
> - return 0;
> -
> - if (!dev || dev->no_msi)
> - return 0;
> -
> - /*
> - * You can't ask to have 0 or less MSIs configured.
> - * a) it's stupid ..
> - * b) the list manipulation code assumes nvec >= 1.
> - */
> - if (nvec < 1)
> - return 0;
> -
> - /*
> - * Any bridge which does NOT route MSI transactions from its
> - * secondary bus to its primary bus must set NO_MSI flag on
> - * the secondary pci_bus.
> - *
> - * The NO_MSI flag can either be set directly by:
> - * - arch-specific PCI host bus controller drivers (deprecated)
> - * - quirks for specific PCI bridges
> - *
> - * or indirectly by platform-specific PCI host bridge drivers by
> - * advertising the 'msi_domain' property, which results in
> - * the NO_MSI flag when no MSI domain is found for this bridge
> - * at probe time.
> - */
> - for (bus = dev->bus; bus; bus = bus->parent)
> - if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI)
> - return 0;
> -
> - return 1;
> -}
> -
> -/**
> - * pci_msi_vec_count - Return the number of MSI vectors a device can send
> - * @dev: device to report about
> - *
> - * This function returns the number of MSI vectors a device requested via
> - * Multiple Message Capable register. It returns a negative errno if the
> - * device is not capable sending MSI interrupts. Otherwise, the call succeeds
> - * and returns a power of two, up to a maximum of 2^5 (32), according to the
> - * MSI specification.
> - **/
> -int pci_msi_vec_count(struct pci_dev *dev)
> -{
> - int ret;
> - u16 msgctl;
> -
> - if (!dev->msi_cap)
> - return -EINVAL;
> -
> - pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &msgctl);
> - ret = 1 << ((msgctl & PCI_MSI_FLAGS_QMASK) >> 1);
> -
> - return ret;
> -}
> -EXPORT_SYMBOL(pci_msi_vec_count);
> -
> -static void pci_msi_shutdown(struct pci_dev *dev)
> -{
> - struct msi_desc *desc;
> -
> - if (!pci_msi_enable || !dev || !dev->msi_enabled)
> - return;
> -
> - BUG_ON(list_empty(dev_to_msi_list(&dev->dev)));
> - desc = first_pci_msi_entry(dev);
> -
> - pci_msi_set_enable(dev, 0);
> - pci_intx_for_msi(dev, 1);
> - dev->msi_enabled = 0;
> -
> - /* Return the device with MSI unmasked as initial states */
> - pci_msi_unmask(desc, msi_multi_mask(desc));
> -
> - /* Restore dev->irq to its default pin-assertion IRQ */
> - dev->irq = desc->pci.msi_attrib.default_irq;
> - pcibios_alloc_irq(dev);
> -}
> -
> -void pci_disable_msi(struct pci_dev *dev)
> -{
> - if (!pci_msi_enable || !dev || !dev->msi_enabled)
> - return;
> -
> - pci_msi_shutdown(dev);
> - free_msi_irqs(dev);
> -}
> -EXPORT_SYMBOL(pci_disable_msi);
> -
> -/**
> - * pci_msix_vec_count - return the number of device's MSI-X table entries
> - * @dev: pointer to the pci_dev data structure of MSI-X device function
> - * This function returns the number of device's MSI-X table entries and
> - * therefore the number of MSI-X vectors device is capable of sending.
> - * It returns a negative errno if the device is not capable of sending MSI-X
> - * interrupts.
> - **/
> -int pci_msix_vec_count(struct pci_dev *dev)
> -{
> - u16 control;
> -
> - if (!dev->msix_cap)
> - return -EINVAL;
> -
> - pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &control);
> - return msix_table_size(control);
> -}
> -EXPORT_SYMBOL(pci_msix_vec_count);
> -
> -static int __pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries,
> - int nvec, struct irq_affinity *affd, int flags)
> -{
> - int nr_entries;
> - int i, j;
> -
> - if (!pci_msi_supported(dev, nvec) || dev->current_state != PCI_D0)
> - return -EINVAL;
> -
> - nr_entries = pci_msix_vec_count(dev);
> - if (nr_entries < 0)
> - return nr_entries;
> - if (nvec > nr_entries && !(flags & PCI_IRQ_VIRTUAL))
> - return nr_entries;
> -
> - if (entries) {
> - /* Check for any invalid entries */
> - for (i = 0; i < nvec; i++) {
> - if (entries[i].entry >= nr_entries)
> - return -EINVAL; /* invalid entry */
> - for (j = i + 1; j < nvec; j++) {
> - if (entries[i].entry == entries[j].entry)
> - return -EINVAL; /* duplicate entry */
> - }
> - }
> - }
> -
> - /* Check whether driver already requested for MSI IRQ */
> - if (dev->msi_enabled) {
> - pci_info(dev, "can't enable MSI-X (MSI IRQ already assigned)\n");
> - return -EINVAL;
> - }
> - return msix_capability_init(dev, entries, nvec, affd);
> -}
> -
> -static void pci_msix_shutdown(struct pci_dev *dev)
> -{
> - struct msi_desc *entry;
> -
> - if (!pci_msi_enable || !dev || !dev->msix_enabled)
> - return;
> -
> - if (pci_dev_is_disconnected(dev)) {
> - dev->msix_enabled = 0;
> - return;
> - }
> -
> - /* Return the device with MSI-X masked as initial states */
> - for_each_pci_msi_entry(entry, dev)
> - pci_msix_mask(entry);
> -
> - pci_msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_ENABLE, 0);
> - pci_intx_for_msi(dev, 1);
> - dev->msix_enabled = 0;
> - pcibios_alloc_irq(dev);
> -}
> -
> -void pci_disable_msix(struct pci_dev *dev)
> -{
> - if (!pci_msi_enable || !dev || !dev->msix_enabled)
> - return;
> -
> - pci_msix_shutdown(dev);
> - free_msi_irqs(dev);
> -}
> -EXPORT_SYMBOL(pci_disable_msix);
> -
> -void pci_no_msi(void)
> -{
> - pci_msi_enable = 0;
> -}
> -
> -/**
> - * pci_msi_enabled - is MSI enabled?
> - *
> - * Returns true if MSI has not been disabled by the command-line option
> - * pci=nomsi.
> - **/
> -int pci_msi_enabled(void)
> -{
> - return pci_msi_enable;
> -}
> -EXPORT_SYMBOL(pci_msi_enabled);
> -
> -static int __pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec,
> - struct irq_affinity *affd)
> -{
> - int nvec;
> - int rc;
> -
> - if (!pci_msi_supported(dev, minvec) || dev->current_state != PCI_D0)
> - return -EINVAL;
> -
> - /* Check whether driver already requested MSI-X IRQs */
> - if (dev->msix_enabled) {
> - pci_info(dev, "can't enable MSI (MSI-X already enabled)\n");
> - return -EINVAL;
> - }
> -
> - if (maxvec < minvec)
> - return -ERANGE;
> -
> - if (WARN_ON_ONCE(dev->msi_enabled))
> - return -EINVAL;
> -
> - nvec = pci_msi_vec_count(dev);
> - if (nvec < 0)
> - return nvec;
> - if (nvec < minvec)
> - return -ENOSPC;
> -
> - if (nvec > maxvec)
> - nvec = maxvec;
> -
> - for (;;) {
> - if (affd) {
> - nvec = irq_calc_affinity_vectors(minvec, nvec, affd);
> - if (nvec < minvec)
> - return -ENOSPC;
> - }
> -
> - rc = msi_capability_init(dev, nvec, affd);
> - if (rc == 0)
> - return nvec;
> -
> - if (rc < 0)
> - return rc;
> - if (rc < minvec)
> - return -ENOSPC;
> -
> - nvec = rc;
> - }
> -}
> -
> -/* deprecated, don't use */
> -int pci_enable_msi(struct pci_dev *dev)
> -{
> - int rc = __pci_enable_msi_range(dev, 1, 1, NULL);
> - if (rc < 0)
> - return rc;
> - return 0;
> -}
> -EXPORT_SYMBOL(pci_enable_msi);
> -
> -static int __pci_enable_msix_range(struct pci_dev *dev,
> - struct msix_entry *entries, int minvec,
> - int maxvec, struct irq_affinity *affd,
> - int flags)
> -{
> - int rc, nvec = maxvec;
> -
> - if (maxvec < minvec)
> - return -ERANGE;
> -
> - if (WARN_ON_ONCE(dev->msix_enabled))
> - return -EINVAL;
> -
> - for (;;) {
> - if (affd) {
> - nvec = irq_calc_affinity_vectors(minvec, nvec, affd);
> - if (nvec < minvec)
> - return -ENOSPC;
> - }
> -
> - rc = __pci_enable_msix(dev, entries, nvec, affd, flags);
> - if (rc == 0)
> - return nvec;
> -
> - if (rc < 0)
> - return rc;
> - if (rc < minvec)
> - return -ENOSPC;
> -
> - nvec = rc;
> - }
> -}
> -
> -/**
> - * pci_enable_msix_range - configure device's MSI-X capability structure
> - * @dev: pointer to the pci_dev data structure of MSI-X device function
> - * @entries: pointer to an array of MSI-X entries
> - * @minvec: minimum number of MSI-X IRQs requested
> - * @maxvec: maximum number of MSI-X IRQs requested
> - *
> - * Setup the MSI-X capability structure of device function with a maximum
> - * possible number of interrupts in the range between @minvec and @maxvec
> - * upon its software driver call to request for MSI-X mode enabled on its
> - * hardware device function. It returns a negative errno if an error occurs.
> - * If it succeeds, it returns the actual number of interrupts allocated and
> - * indicates the successful configuration of MSI-X capability structure
> - * with new allocated MSI-X interrupts.
> - **/
> -int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries,
> - int minvec, int maxvec)
> -{
> - return __pci_enable_msix_range(dev, entries, minvec, maxvec, NULL, 0);
> -}
> -EXPORT_SYMBOL(pci_enable_msix_range);
> -
> -/**
> - * pci_alloc_irq_vectors_affinity - allocate multiple IRQs for a device
> - * @dev: PCI device to operate on
> - * @min_vecs: minimum number of vectors required (must be >= 1)
> - * @max_vecs: maximum (desired) number of vectors
> - * @flags: flags or quirks for the allocation
> - * @affd: optional description of the affinity requirements
> - *
> - * Allocate up to @max_vecs interrupt vectors for @dev, using MSI-X or MSI
> - * vectors if available, and fall back to a single legacy vector
> - * if neither is available. Return the number of vectors allocated,
> - * (which might be smaller than @max_vecs) if successful, or a negative
> - * error code on error. If less than @min_vecs interrupt vectors are
> - * available for @dev the function will fail with -ENOSPC.
> - *
> - * To get the Linux IRQ number used for a vector that can be passed to
> - * request_irq() use the pci_irq_vector() helper.
> - */
> -int pci_alloc_irq_vectors_affinity(struct pci_dev *dev, unsigned int min_vecs,
> - unsigned int max_vecs, unsigned int flags,
> - struct irq_affinity *affd)
> -{
> - struct irq_affinity msi_default_affd = {0};
> - int nvecs = -ENOSPC;
> -
> - if (flags & PCI_IRQ_AFFINITY) {
> - if (!affd)
> - affd = &msi_default_affd;
> - } else {
> - if (WARN_ON(affd))
> - affd = NULL;
> - }
> -
> - if (flags & PCI_IRQ_MSIX) {
> - nvecs = __pci_enable_msix_range(dev, NULL, min_vecs, max_vecs,
> - affd, flags);
> - if (nvecs > 0)
> - return nvecs;
> - }
> -
> - if (flags & PCI_IRQ_MSI) {
> - nvecs = __pci_enable_msi_range(dev, min_vecs, max_vecs, affd);
> - if (nvecs > 0)
> - return nvecs;
> - }
> -
> - /* use legacy IRQ if allowed */
> - if (flags & PCI_IRQ_LEGACY) {
> - if (min_vecs == 1 && dev->irq) {
> - /*
> - * Invoke the affinity spreading logic to ensure that
> - * the device driver can adjust queue configuration
> - * for the single interrupt case.
> - */
> - if (affd)
> - irq_create_affinity_masks(1, affd);
> - pci_intx(dev, 1);
> - return 1;
> - }
> - }
> -
> - return nvecs;
> -}
> -EXPORT_SYMBOL(pci_alloc_irq_vectors_affinity);
> -
> -/**
> - * pci_free_irq_vectors - free previously allocated IRQs for a device
> - * @dev: PCI device to operate on
> - *
> - * Undoes the allocations and enabling in pci_alloc_irq_vectors().
> - */
> -void pci_free_irq_vectors(struct pci_dev *dev)
> -{
> - pci_disable_msix(dev);
> - pci_disable_msi(dev);
> -}
> -EXPORT_SYMBOL(pci_free_irq_vectors);
> -
> -/**
> - * pci_irq_vector - return Linux IRQ number of a device vector
> - * @dev: PCI device to operate on
> - * @nr: Interrupt vector index (0-based)
> - *
> - * @nr has the following meanings depending on the interrupt mode:
> - * MSI-X: The index in the MSI-X vector table
> - * MSI: The index of the enabled MSI vectors
> - * INTx: Must be 0
> - *
> - * Return: The Linux interrupt number or -EINVAl if @nr is out of range.
> - */
> -int pci_irq_vector(struct pci_dev *dev, unsigned int nr)
> -{
> - if (dev->msix_enabled) {
> - struct msi_desc *entry;
> -
> - for_each_pci_msi_entry(entry, dev) {
> - if (entry->pci.msi_attrib.entry_nr == nr)
> - return entry->irq;
> - }
> - WARN_ON_ONCE(1);
> - return -EINVAL;
> - }
> -
> - if (dev->msi_enabled) {
> - struct msi_desc *entry = first_pci_msi_entry(dev);
> -
> - if (WARN_ON_ONCE(nr >= entry->nvec_used))
> - return -EINVAL;
> - } else {
> - if (WARN_ON_ONCE(nr > 0))
> - return -EINVAL;
> - }
> -
> - return dev->irq + nr;
> -}
> -EXPORT_SYMBOL(pci_irq_vector);
> -
> -/**
> - * pci_irq_get_affinity - return the affinity of a particular MSI vector
> - * @dev: PCI device to operate on
> - * @nr: device-relative interrupt vector index (0-based).
> - *
> - * @nr has the following meanings depending on the interrupt mode:
> - * MSI-X: The index in the MSI-X vector table
> - * MSI: The index of the enabled MSI vectors
> - * INTx: Must be 0
> - *
> - * Return: A cpumask pointer or NULL if @nr is out of range
> - */
> -const struct cpumask *pci_irq_get_affinity(struct pci_dev *dev, int nr)
> -{
> - if (dev->msix_enabled) {
> - struct msi_desc *entry;
> -
> - for_each_pci_msi_entry(entry, dev) {
> - if (entry->pci.msi_attrib.entry_nr == nr)
> - return &entry->affinity->mask;
> - }
> - WARN_ON_ONCE(1);
> - return NULL;
> - } else if (dev->msi_enabled) {
> - struct msi_desc *entry = first_pci_msi_entry(dev);
> -
> - if (WARN_ON_ONCE(!entry || !entry->affinity ||
> - nr >= entry->nvec_used))
> - return NULL;
> -
> - return &entry->affinity[nr].mask;
> - } else {
> - return cpu_possible_mask;
> - }
> -}
> -EXPORT_SYMBOL(pci_irq_get_affinity);
> -
> -struct pci_dev *msi_desc_to_pci_dev(struct msi_desc *desc)
> -{
> - return to_pci_dev(desc->dev);
> -}
> -EXPORT_SYMBOL(msi_desc_to_pci_dev);
> -
> -#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN
> -/**
> - * pci_msi_domain_write_msg - Helper to write MSI message to PCI config space
> - * @irq_data: Pointer to interrupt data of the MSI interrupt
> - * @msg: Pointer to the message
> - */
> -static void pci_msi_domain_write_msg(struct irq_data *irq_data, struct msi_msg *msg)
> -{
> - struct msi_desc *desc = irq_data_get_msi_desc(irq_data);
> -
> - /*
> - * For MSI-X desc->irq is always equal to irq_data->irq. For
> - * MSI only the first interrupt of MULTI MSI passes the test.
> - */
> - if (desc->irq == irq_data->irq)
> - __pci_write_msi_msg(desc, msg);
> -}
> -
> -/**
> - * pci_msi_domain_calc_hwirq - Generate a unique ID for an MSI source
> - * @desc: Pointer to the MSI descriptor
> - *
> - * The ID number is only used within the irqdomain.
> - */
> -static irq_hw_number_t pci_msi_domain_calc_hwirq(struct msi_desc *desc)
> -{
> - struct pci_dev *dev = msi_desc_to_pci_dev(desc);
> -
> - return (irq_hw_number_t)desc->pci.msi_attrib.entry_nr |
> - pci_dev_id(dev) << 11 |
> - (pci_domain_nr(dev->bus) & 0xFFFFFFFF) << 27;
> -}
> -
> -static inline bool pci_msi_desc_is_multi_msi(struct msi_desc *desc)
> -{
> - return !desc->pci.msi_attrib.is_msix && desc->nvec_used > 1;
> -}
> -
> -/**
> - * pci_msi_domain_check_cap - Verify that @domain supports the capabilities
> - * for @dev
> - * @domain: The interrupt domain to check
> - * @info: The domain info for verification
> - * @dev: The device to check
> - *
> - * Returns:
> - * 0 if the functionality is supported
> - * 1 if Multi MSI is requested, but the domain does not support it
> - * -ENOTSUPP otherwise
> - */
> -int pci_msi_domain_check_cap(struct irq_domain *domain,
> - struct msi_domain_info *info, struct device *dev)
> -{
> - struct msi_desc *desc = first_pci_msi_entry(to_pci_dev(dev));
> -
> - /* Special handling to support __pci_enable_msi_range() */
> - if (pci_msi_desc_is_multi_msi(desc) &&
> - !(info->flags & MSI_FLAG_MULTI_PCI_MSI))
> - return 1;
> - else if (desc->pci.msi_attrib.is_msix && !(info->flags & MSI_FLAG_PCI_MSIX))
> - return -ENOTSUPP;
> -
> - return 0;
> -}
> -
> -static int pci_msi_domain_handle_error(struct irq_domain *domain,
> - struct msi_desc *desc, int error)
> -{
> - /* Special handling to support __pci_enable_msi_range() */
> - if (pci_msi_desc_is_multi_msi(desc) && error == -ENOSPC)
> - return 1;
> -
> - return error;
> -}
> -
> -static void pci_msi_domain_set_desc(msi_alloc_info_t *arg,
> - struct msi_desc *desc)
> -{
> - arg->desc = desc;
> - arg->hwirq = pci_msi_domain_calc_hwirq(desc);
> -}
> -
> -static struct msi_domain_ops pci_msi_domain_ops_default = {
> - .set_desc = pci_msi_domain_set_desc,
> - .msi_check = pci_msi_domain_check_cap,
> - .handle_error = pci_msi_domain_handle_error,
> -};
> -
> -static void pci_msi_domain_update_dom_ops(struct msi_domain_info *info)
> -{
> - struct msi_domain_ops *ops = info->ops;
> -
> - if (ops == NULL) {
> - info->ops = &pci_msi_domain_ops_default;
> - } else {
> - if (ops->set_desc == NULL)
> - ops->set_desc = pci_msi_domain_set_desc;
> - if (ops->msi_check == NULL)
> - ops->msi_check = pci_msi_domain_check_cap;
> - if (ops->handle_error == NULL)
> - ops->handle_error = pci_msi_domain_handle_error;
> - }
> -}
> -
> -static void pci_msi_domain_update_chip_ops(struct msi_domain_info *info)
> -{
> - struct irq_chip *chip = info->chip;
> -
> - BUG_ON(!chip);
> - if (!chip->irq_write_msi_msg)
> - chip->irq_write_msi_msg = pci_msi_domain_write_msg;
> - if (!chip->irq_mask)
> - chip->irq_mask = pci_msi_mask_irq;
> - if (!chip->irq_unmask)
> - chip->irq_unmask = pci_msi_unmask_irq;
> -}
> -
> -/**
> - * pci_msi_create_irq_domain - Create a MSI interrupt domain
> - * @fwnode: Optional fwnode of the interrupt controller
> - * @info: MSI domain info
> - * @parent: Parent irq domain
> - *
> - * Updates the domain and chip ops and creates a MSI interrupt domain.
> - *
> - * Returns:
> - * A domain pointer or NULL in case of failure.
> - */
> -struct irq_domain *pci_msi_create_irq_domain(struct fwnode_handle *fwnode,
> - struct msi_domain_info *info,
> - struct irq_domain *parent)
> -{
> - struct irq_domain *domain;
> -
> - if (WARN_ON(info->flags & MSI_FLAG_LEVEL_CAPABLE))
> - info->flags &= ~MSI_FLAG_LEVEL_CAPABLE;
> -
> - if (info->flags & MSI_FLAG_USE_DEF_DOM_OPS)
> - pci_msi_domain_update_dom_ops(info);
> - if (info->flags & MSI_FLAG_USE_DEF_CHIP_OPS)
> - pci_msi_domain_update_chip_ops(info);
> -
> - info->flags |= MSI_FLAG_ACTIVATE_EARLY;
> - if (IS_ENABLED(CONFIG_GENERIC_IRQ_RESERVATION_MODE))
> - info->flags |= MSI_FLAG_MUST_REACTIVATE;
> -
> - /* PCI-MSI is oneshot-safe */
> - info->chip->flags |= IRQCHIP_ONESHOT_SAFE;
> -
> - domain = msi_create_irq_domain(fwnode, info, parent);
> - if (!domain)
> - return NULL;
> -
> - irq_domain_update_bus_token(domain, DOMAIN_BUS_PCI_MSI);
> - return domain;
> -}
> -EXPORT_SYMBOL_GPL(pci_msi_create_irq_domain);
> -
> -/*
> - * Users of the generic MSI infrastructure expect a device to have a single ID,
> - * so with DMA aliases we have to pick the least-worst compromise. Devices with
> - * DMA phantom functions tend to still emit MSIs from the real function number,
> - * so we ignore those and only consider topological aliases where either the
> - * alias device or RID appears on a different bus number. We also make the
> - * reasonable assumption that bridges are walked in an upstream direction (so
> - * the last one seen wins), and the much braver assumption that the most likely
> - * case is that of PCI->PCIe so we should always use the alias RID. This echoes
> - * the logic from intel_irq_remapping's set_msi_sid(), which presumably works
> - * well enough in practice; in the face of the horrible PCIe<->PCI-X conditions
> - * for taking ownership all we can really do is close our eyes and hope...
> - */
> -static int get_msi_id_cb(struct pci_dev *pdev, u16 alias, void *data)
> -{
> - u32 *pa = data;
> - u8 bus = PCI_BUS_NUM(*pa);
> -
> - if (pdev->bus->number != bus || PCI_BUS_NUM(alias) != bus)
> - *pa = alias;
> -
> - return 0;
> -}
> -
> -/**
> - * pci_msi_domain_get_msi_rid - Get the MSI requester id (RID)
> - * @domain: The interrupt domain
> - * @pdev: The PCI device.
> - *
> - * The RID for a device is formed from the alias, with a firmware
> - * supplied mapping applied
> - *
> - * Returns: The RID.
> - */
> -u32 pci_msi_domain_get_msi_rid(struct irq_domain *domain, struct pci_dev *pdev)
> -{
> - struct device_node *of_node;
> - u32 rid = pci_dev_id(pdev);
> -
> - pci_for_each_dma_alias(pdev, get_msi_id_cb, &rid);
> -
> - of_node = irq_domain_get_of_node(domain);
> - rid = of_node ? of_msi_map_id(&pdev->dev, of_node, rid) :
> - iort_msi_map_id(&pdev->dev, rid);
> -
> - return rid;
> -}
> -
> -/**
> - * pci_msi_get_device_domain - Get the MSI domain for a given PCI device
> - * @pdev: The PCI device
> - *
> - * Use the firmware data to find a device-specific MSI domain
> - * (i.e. not one that is set as a default).
> - *
> - * Returns: The corresponding MSI domain or NULL if none has been found.
> - */
> -struct irq_domain *pci_msi_get_device_domain(struct pci_dev *pdev)
> -{
> - struct irq_domain *dom;
> - u32 rid = pci_dev_id(pdev);
> -
> - pci_for_each_dma_alias(pdev, get_msi_id_cb, &rid);
> - dom = of_msi_map_get_device_domain(&pdev->dev, rid, DOMAIN_BUS_PCI_MSI);
> - if (!dom)
> - dom = iort_get_device_domain(&pdev->dev, rid,
> - DOMAIN_BUS_PCI_MSI);
> - return dom;
> -}
> -
> -/**
> - * pci_dev_has_special_msi_domain - Check whether the device is handled by
> - * a non-standard PCI-MSI domain
> - * @pdev: The PCI device to check.
> - *
> - * Returns: True if the device irqdomain or the bus irqdomain is
> - * non-standard PCI/MSI.
> - */
> -bool pci_dev_has_special_msi_domain(struct pci_dev *pdev)
> -{
> - struct irq_domain *dom = dev_get_msi_domain(&pdev->dev);
> -
> - if (!dom)
> - dom = dev_get_msi_domain(&pdev->bus->dev);
> -
> - if (!dom)
> - return true;
> -
> - return dom->bus_token != DOMAIN_BUS_PCI_MSI;
> -}
> -
> -#endif /* CONFIG_PCI_MSI_IRQ_DOMAIN */
> -#endif /* CONFIG_PCI_MSI */
> -
> -void pci_msi_init(struct pci_dev *dev)
> -{
> - u16 ctrl;
> -
> - /*
> - * Disable the MSI hardware to avoid screaming interrupts
> - * during boot. This is the power on reset default so
> - * usually this should be a noop.
> - */
> - dev->msi_cap = pci_find_capability(dev, PCI_CAP_ID_MSI);
> - if (!dev->msi_cap)
> - return;
> -
> - pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &ctrl);
> - if (ctrl & PCI_MSI_FLAGS_ENABLE)
> - pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS,
> - ctrl & ~PCI_MSI_FLAGS_ENABLE);
> -
> - if (!(ctrl & PCI_MSI_FLAGS_64BIT))
> - dev->no_64bit_msi = 1;
> -}
> -
> -void pci_msix_init(struct pci_dev *dev)
> -{
> - u16 ctrl;
> -
> - dev->msix_cap = pci_find_capability(dev, PCI_CAP_ID_MSIX);
> - if (!dev->msix_cap)
> - return;
> -
> - pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &ctrl);
> - if (ctrl & PCI_MSIX_FLAGS_ENABLE)
> - pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS,
> - ctrl & ~PCI_MSIX_FLAGS_ENABLE);
> -}
> --- /dev/null
> +++ b/drivers/pci/msi/Makefile
> @@ -0,0 +1,4 @@
> +# SPDX-License-Identifier: GPL-2.0
> +#
> +# Makefile for the PCI/MSI
> +obj-$(CONFIG_PCI) += msi.o
> --- /dev/null
> +++ b/drivers/pci/msi/msi.c
> @@ -0,0 +1,1532 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * PCI Message Signaled Interrupt (MSI)
> + *
> + * Copyright (C) 2003-2004 Intel
> + * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
> + * Copyright (C) 2016 Christoph Hellwig.
> + */
> +
> +#include <linux/acpi_iort.h>
> +#include <linux/err.h>
> +#include <linux/export.h>
> +#include <linux/irq.h>
> +#include <linux/irqdomain.h>
> +#include <linux/msi.h>
> +#include <linux/of_irq.h>
> +#include <linux/pci.h>
> +
> +#include "../pci.h"
> +
> +#ifdef CONFIG_PCI_MSI
> +
> +static int pci_msi_enable = 1;
> +int pci_msi_ignore_mask;
> +
> +#define msix_table_size(flags) ((flags & PCI_MSIX_FLAGS_QSIZE) + 1)
> +
> +#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN
> +static int pci_msi_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
> +{
> + struct irq_domain *domain;
> +
> + domain = dev_get_msi_domain(&dev->dev);
> + if (domain && irq_domain_is_hierarchy(domain))
> + return msi_domain_alloc_irqs(domain, &dev->dev, nvec);
> +
> + return arch_setup_msi_irqs(dev, nvec, type);
> +}
> +
> +static void pci_msi_teardown_msi_irqs(struct pci_dev *dev)
> +{
> + struct irq_domain *domain;
> +
> + domain = dev_get_msi_domain(&dev->dev);
> + if (domain && irq_domain_is_hierarchy(domain))
> + msi_domain_free_irqs(domain, &dev->dev);
> + else
> + arch_teardown_msi_irqs(dev);
> +}
> +#else
> +#define pci_msi_setup_msi_irqs arch_setup_msi_irqs
> +#define pci_msi_teardown_msi_irqs arch_teardown_msi_irqs
> +#endif
> +
> +#ifdef CONFIG_PCI_MSI_ARCH_FALLBACKS
> +/* Arch hooks */
> +int __weak arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
> +{
> + return -EINVAL;
> +}
> +
> +void __weak arch_teardown_msi_irq(unsigned int irq)
> +{
> +}
> +
> +int __weak arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
> +{
> + struct msi_desc *entry;
> + int ret;
> +
> + /*
> + * If an architecture wants to support multiple MSI, it needs to
> + * override arch_setup_msi_irqs()
> + */
> + if (type == PCI_CAP_ID_MSI && nvec > 1)
> + return 1;
> +
> + for_each_pci_msi_entry(entry, dev) {
> + ret = arch_setup_msi_irq(dev, entry);
> + if (ret < 0)
> + return ret;
> + if (ret > 0)
> + return -ENOSPC;
> + }
> +
> + return 0;
> +}
> +
> +void __weak arch_teardown_msi_irqs(struct pci_dev *dev)
> +{
> + int i;
> + struct msi_desc *entry;
> +
> + for_each_pci_msi_entry(entry, dev)
> + if (entry->irq)
> + for (i = 0; i < entry->nvec_used; i++)
> + arch_teardown_msi_irq(entry->irq + i);
> +}
> +#endif /* CONFIG_PCI_MSI_ARCH_FALLBACKS */
> +
> +/*
> + * PCI 2.3 does not specify mask bits for each MSI interrupt. Attempting to
> + * mask all MSI interrupts by clearing the MSI enable bit does not work
> + * reliably as devices without an INTx disable bit will then generate a
> + * level IRQ which will never be cleared.
> + */
> +static inline __attribute_const__ u32 msi_multi_mask(struct msi_desc *desc)
> +{
> + /* Don't shift by >= width of type */
> + if (desc->pci.msi_attrib.multi_cap >= 5)
> + return 0xffffffff;
> + return (1 << (1 << desc->pci.msi_attrib.multi_cap)) - 1;
> +}
> +
> +static noinline void pci_msi_update_mask(struct msi_desc *desc, u32 clear, u32 set)
> +{
> + raw_spinlock_t *lock = &desc->dev->msi_lock;
> + unsigned long flags;
> +
> + if (!desc->pci.msi_attrib.can_mask)
> + return;
> +
> + raw_spin_lock_irqsave(lock, flags);
> + desc->pci.msi_mask &= ~clear;
> + desc->pci.msi_mask |= set;
> + pci_write_config_dword(msi_desc_to_pci_dev(desc), desc->pci.mask_pos,
> + desc->pci.msi_mask);
> + raw_spin_unlock_irqrestore(lock, flags);
> +}
> +
> +static inline void pci_msi_mask(struct msi_desc *desc, u32 mask)
> +{
> + pci_msi_update_mask(desc, 0, mask);
> +}
> +
> +static inline void pci_msi_unmask(struct msi_desc *desc, u32 mask)
> +{
> + pci_msi_update_mask(desc, mask, 0);
> +}
> +
> +static inline void __iomem *pci_msix_desc_addr(struct msi_desc *desc)
> +{
> + return desc->pci.mask_base + desc->pci.msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE;
> +}
> +
> +/*
> + * This internal function does not flush PCI writes to the device. All
> + * users must ensure that they read from the device before either assuming
> + * that the device state is up to date, or returning out of this file.
> + * It does not affect the msi_desc::msix_ctrl cache either. Use with care!
> + */
> +static void pci_msix_write_vector_ctrl(struct msi_desc *desc, u32 ctrl)
> +{
> + void __iomem *desc_addr = pci_msix_desc_addr(desc);
> +
> + if (desc->pci.msi_attrib.can_mask)
> + writel(ctrl, desc_addr + PCI_MSIX_ENTRY_VECTOR_CTRL);
> +}
> +
> +static inline void pci_msix_mask(struct msi_desc *desc)
> +{
> + desc->pci.msix_ctrl |= PCI_MSIX_ENTRY_CTRL_MASKBIT;
> + pci_msix_write_vector_ctrl(desc, desc->pci.msix_ctrl);
> + /* Flush write to device */
> + readl(desc->pci.mask_base);
> +}
> +
> +static inline void pci_msix_unmask(struct msi_desc *desc)
> +{
> + desc->pci.msix_ctrl &= ~PCI_MSIX_ENTRY_CTRL_MASKBIT;
> + pci_msix_write_vector_ctrl(desc, desc->pci.msix_ctrl);
> +}
> +
> +static void __pci_msi_mask_desc(struct msi_desc *desc, u32 mask)
> +{
> + if (desc->pci.msi_attrib.is_msix)
> + pci_msix_mask(desc);
> + else
> + pci_msi_mask(desc, mask);
> +}
> +
> +static void __pci_msi_unmask_desc(struct msi_desc *desc, u32 mask)
> +{
> + if (desc->pci.msi_attrib.is_msix)
> + pci_msix_unmask(desc);
> + else
> + pci_msi_unmask(desc, mask);
> +}
> +
> +/**
> + * pci_msi_mask_irq - Generic IRQ chip callback to mask PCI/MSI interrupts
> + * @data: pointer to irqdata associated to that interrupt
> + */
> +void pci_msi_mask_irq(struct irq_data *data)
> +{
> + struct msi_desc *desc = irq_data_get_msi_desc(data);
> +
> + __pci_msi_mask_desc(desc, BIT(data->irq - desc->irq));
> +}
> +EXPORT_SYMBOL_GPL(pci_msi_mask_irq);
> +
> +/**
> + * pci_msi_unmask_irq - Generic IRQ chip callback to unmask PCI/MSI interrupts
> + * @data: pointer to irqdata associated to that interrupt
> + */
> +void pci_msi_unmask_irq(struct irq_data *data)
> +{
> + struct msi_desc *desc = irq_data_get_msi_desc(data);
> +
> + __pci_msi_unmask_desc(desc, BIT(data->irq - desc->irq));
> +}
> +EXPORT_SYMBOL_GPL(pci_msi_unmask_irq);
> +
> +void __pci_read_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
> +{
> + struct pci_dev *dev = msi_desc_to_pci_dev(entry);
> +
> + BUG_ON(dev->current_state != PCI_D0);
> +
> + if (entry->pci.msi_attrib.is_msix) {
> + void __iomem *base = pci_msix_desc_addr(entry);
> +
> + if (WARN_ON_ONCE(entry->pci.msi_attrib.is_virtual))
> + return;
> +
> + msg->address_lo = readl(base + PCI_MSIX_ENTRY_LOWER_ADDR);
> + msg->address_hi = readl(base + PCI_MSIX_ENTRY_UPPER_ADDR);
> + msg->data = readl(base + PCI_MSIX_ENTRY_DATA);
> + } else {
> + int pos = dev->msi_cap;
> + u16 data;
> +
> + pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_LO,
> + &msg->address_lo);
> + if (entry->pci.msi_attrib.is_64) {
> + pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_HI,
> + &msg->address_hi);
> + pci_read_config_word(dev, pos + PCI_MSI_DATA_64, &data);
> + } else {
> + msg->address_hi = 0;
> + pci_read_config_word(dev, pos + PCI_MSI_DATA_32, &data);
> + }
> + msg->data = data;
> + }
> +}
> +
> +void __pci_write_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
> +{
> + struct pci_dev *dev = msi_desc_to_pci_dev(entry);
> +
> + if (dev->current_state != PCI_D0 || pci_dev_is_disconnected(dev)) {
> + /* Don't touch the hardware now */
> + } else if (entry->pci.msi_attrib.is_msix) {
> + void __iomem *base = pci_msix_desc_addr(entry);
> + u32 ctrl = entry->pci.msix_ctrl;
> + bool unmasked = !(ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT);
> +
> + if (entry->pci.msi_attrib.is_virtual)
> + goto skip;
> +
> + /*
> + * The specification mandates that the entry is masked
> + * when the message is modified:
> + *
> + * "If software changes the Address or Data value of an
> + * entry while the entry is unmasked, the result is
> + * undefined."
> + */
> + if (unmasked)
> + pci_msix_write_vector_ctrl(entry, ctrl | PCI_MSIX_ENTRY_CTRL_MASKBIT);
> +
> + writel(msg->address_lo, base + PCI_MSIX_ENTRY_LOWER_ADDR);
> + writel(msg->address_hi, base + PCI_MSIX_ENTRY_UPPER_ADDR);
> + writel(msg->data, base + PCI_MSIX_ENTRY_DATA);
> +
> + if (unmasked)
> + pci_msix_write_vector_ctrl(entry, ctrl);
> +
> + /* Ensure that the writes are visible in the device */
> + readl(base + PCI_MSIX_ENTRY_DATA);
> + } else {
> + int pos = dev->msi_cap;
> + u16 msgctl;
> +
> + pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &msgctl);
> + msgctl &= ~PCI_MSI_FLAGS_QSIZE;
> + msgctl |= entry->pci.msi_attrib.multiple << 4;
> + pci_write_config_word(dev, pos + PCI_MSI_FLAGS, msgctl);
> +
> + pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_LO,
> + msg->address_lo);
> + if (entry->pci.msi_attrib.is_64) {
> + pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_HI,
> + msg->address_hi);
> + pci_write_config_word(dev, pos + PCI_MSI_DATA_64,
> + msg->data);
> + } else {
> + pci_write_config_word(dev, pos + PCI_MSI_DATA_32,
> + msg->data);
> + }
> + /* Ensure that the writes are visible in the device */
> + pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &msgctl);
> + }
> +
> +skip:
> + entry->msg = *msg;
> +
> + if (entry->write_msi_msg)
> + entry->write_msi_msg(entry, entry->write_msi_msg_data);
> +
> +}
> +
> +void pci_write_msi_msg(unsigned int irq, struct msi_msg *msg)
> +{
> + struct msi_desc *entry = irq_get_msi_desc(irq);
> +
> + __pci_write_msi_msg(entry, msg);
> +}
> +EXPORT_SYMBOL_GPL(pci_write_msi_msg);
> +
> +static void free_msi_irqs(struct pci_dev *dev)
> +{
> + struct list_head *msi_list = dev_to_msi_list(&dev->dev);
> + struct msi_desc *entry, *tmp;
> + int i;
> +
> + for_each_pci_msi_entry(entry, dev)
> + if (entry->irq)
> + for (i = 0; i < entry->nvec_used; i++)
> + BUG_ON(irq_has_action(entry->irq + i));
> +
> + if (dev->msi_irq_groups) {
> + msi_destroy_sysfs(&dev->dev, dev->msi_irq_groups);
> + dev->msi_irq_groups = NULL;
> + }
> +
> + pci_msi_teardown_msi_irqs(dev);
> +
> + list_for_each_entry_safe(entry, tmp, msi_list, list) {
> + if (entry->pci.msi_attrib.is_msix) {
> + if (list_is_last(&entry->list, msi_list))
> + iounmap(entry->pci.mask_base);
> + }
> +
> + list_del(&entry->list);
> + free_msi_entry(entry);
> + }
> +}
> +
> +static void pci_intx_for_msi(struct pci_dev *dev, int enable)
> +{
> + if (!(dev->dev_flags & PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG))
> + pci_intx(dev, enable);
> +}
> +
> +static void pci_msi_set_enable(struct pci_dev *dev, int enable)
> +{
> + u16 control;
> +
> + pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);
> + control &= ~PCI_MSI_FLAGS_ENABLE;
> + if (enable)
> + control |= PCI_MSI_FLAGS_ENABLE;
> + pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control);
> +}
> +
> +/*
> + * Architecture override returns true when the PCI MSI message should be
> + * written by the generic restore function.
> + */
> +bool __weak arch_restore_msi_irqs(struct pci_dev *dev)
> +{
> + return true;
> +}
> +
> +static void __pci_restore_msi_state(struct pci_dev *dev)
> +{
> + struct msi_desc *entry;
> + u16 control;
> +
> + if (!dev->msi_enabled)
> + return;
> +
> + entry = irq_get_msi_desc(dev->irq);
> +
> + pci_intx_for_msi(dev, 0);
> + pci_msi_set_enable(dev, 0);
> + if (arch_restore_msi_irqs(dev))
> + __pci_write_msi_msg(entry, &entry->msg);
> +
> + pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);
> + pci_msi_update_mask(entry, 0, 0);
> + control &= ~PCI_MSI_FLAGS_QSIZE;
> + control |= (entry->pci.msi_attrib.multiple << 4) | PCI_MSI_FLAGS_ENABLE;
> + pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control);
> +}
> +
> +static void pci_msix_clear_and_set_ctrl(struct pci_dev *dev, u16 clear, u16 set)
> +{
> + u16 ctrl;
> +
> + pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &ctrl);
> + ctrl &= ~clear;
> + ctrl |= set;
> + pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, ctrl);
> +}
> +
> +static void __pci_restore_msix_state(struct pci_dev *dev)
> +{
> + struct msi_desc *entry;
> + bool write_msg;
> +
> + if (!dev->msix_enabled)
> + return;
> + BUG_ON(list_empty(dev_to_msi_list(&dev->dev)));
> +
> + /* route the table */
> + pci_intx_for_msi(dev, 0);
> + pci_msix_clear_and_set_ctrl(dev, 0,
> + PCI_MSIX_FLAGS_ENABLE | PCI_MSIX_FLAGS_MASKALL);
> +
> + write_msg = arch_restore_msi_irqs(dev);
> +
> + for_each_pci_msi_entry(entry, dev) {
> + if (write_msg)
> + __pci_write_msi_msg(entry, &entry->msg);
> + pci_msix_write_vector_ctrl(entry, entry->pci.msix_ctrl);
> + }
> +
> + pci_msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_MASKALL, 0);
> +}
> +
> +void pci_restore_msi_state(struct pci_dev *dev)
> +{
> + __pci_restore_msi_state(dev);
> + __pci_restore_msix_state(dev);
> +}
> +EXPORT_SYMBOL_GPL(pci_restore_msi_state);
> +
> +static struct msi_desc *
> +msi_setup_entry(struct pci_dev *dev, int nvec, struct irq_affinity *affd)
> +{
> + struct irq_affinity_desc *masks = NULL;
> + struct msi_desc *entry;
> + u16 control;
> +
> + if (affd)
> + masks = irq_create_affinity_masks(nvec, affd);
> +
> + /* MSI Entry Initialization */
> + entry = alloc_msi_entry(&dev->dev, nvec, masks);
> + if (!entry)
> + goto out;
> +
> + pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);
> + /* Lies, damned lies, and MSIs */
> + if (dev->dev_flags & PCI_DEV_FLAGS_HAS_MSI_MASKING)
> + control |= PCI_MSI_FLAGS_MASKBIT;
> +
> + entry->pci.msi_attrib.is_msix = 0;
> + entry->pci.msi_attrib.is_64 = !!(control & PCI_MSI_FLAGS_64BIT);
> + entry->pci.msi_attrib.is_virtual = 0;
> + entry->pci.msi_attrib.entry_nr = 0;
> + entry->pci.msi_attrib.can_mask = !pci_msi_ignore_mask &&
> + !!(control & PCI_MSI_FLAGS_MASKBIT);
> + entry->pci.msi_attrib.default_irq = dev->irq; /* Save IOAPIC IRQ */
> + entry->pci.msi_attrib.multi_cap = (control & PCI_MSI_FLAGS_QMASK) >> 1;
> + entry->pci.msi_attrib.multiple = ilog2(__roundup_pow_of_two(nvec));
> +
> + if (control & PCI_MSI_FLAGS_64BIT)
> + entry->pci.mask_pos = dev->msi_cap + PCI_MSI_MASK_64;
> + else
> + entry->pci.mask_pos = dev->msi_cap + PCI_MSI_MASK_32;
> +
> + /* Save the initial mask status */
> + if (entry->pci.msi_attrib.can_mask)
> + pci_read_config_dword(dev, entry->pci.mask_pos, &entry->pci.msi_mask);
> +
> +out:
> + kfree(masks);
> + return entry;
> +}
> +
> +static int msi_verify_entries(struct pci_dev *dev)
> +{
> + struct msi_desc *entry;
> +
> + if (!dev->no_64bit_msi)
> + return 0;
> +
> + for_each_pci_msi_entry(entry, dev) {
> + if (entry->msg.address_hi) {
> + pci_err(dev, "arch assigned 64-bit MSI address %#x%08x but device only supports 32 bits\n",
> + entry->msg.address_hi, entry->msg.address_lo);
> + return -EIO;
> + }
> + }
> + return 0;
> +}
> +
> +/**
> + * msi_capability_init - configure device's MSI capability structure
> + * @dev: pointer to the pci_dev data structure of MSI device function
> + * @nvec: number of interrupts to allocate
> + * @affd: description of automatic IRQ affinity assignments (may be %NULL)
> + *
> + * Setup the MSI capability structure of the device with the requested
> + * number of interrupts. A return value of zero indicates the successful
> + * setup of an entry with the new MSI IRQ. A negative return value indicates
> + * an error, and a positive return value indicates the number of interrupts
> + * which could have been allocated.
> + */
> +static int msi_capability_init(struct pci_dev *dev, int nvec,
> + struct irq_affinity *affd)
> +{
> + const struct attribute_group **groups;
> + struct msi_desc *entry;
> + int ret;
> +
> + pci_msi_set_enable(dev, 0); /* Disable MSI during set up */
> +
> + entry = msi_setup_entry(dev, nvec, affd);
> + if (!entry)
> + return -ENOMEM;
> +
> + /* All MSIs are unmasked by default; mask them all */
> + pci_msi_mask(entry, msi_multi_mask(entry));
> +
> + list_add_tail(&entry->list, dev_to_msi_list(&dev->dev));
> +
> + /* Configure MSI capability structure */
> + ret = pci_msi_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSI);
> + if (ret)
> + goto err;
> +
> + ret = msi_verify_entries(dev);
> + if (ret)
> + goto err;
> +
> + groups = msi_populate_sysfs(&dev->dev);
> + if (IS_ERR(groups)) {
> + ret = PTR_ERR(groups);
> + goto err;
> + }
> +
> + dev->msi_irq_groups = groups;
> +
> + /* Set MSI enabled bits */
> + pci_intx_for_msi(dev, 0);
> + pci_msi_set_enable(dev, 1);
> + dev->msi_enabled = 1;
> +
> + pcibios_free_irq(dev);
> + dev->irq = entry->irq;
> + return 0;
> +
> +err:
> + pci_msi_unmask(entry, msi_multi_mask(entry));
> + free_msi_irqs(dev);
> + return ret;
> +}
> +
> +static void __iomem *msix_map_region(struct pci_dev *dev,
> + unsigned int nr_entries)
> +{
> + resource_size_t phys_addr;
> + u32 table_offset;
> + unsigned long flags;
> + u8 bir;
> +
> + pci_read_config_dword(dev, dev->msix_cap + PCI_MSIX_TABLE,
> + &table_offset);
> + bir = (u8)(table_offset & PCI_MSIX_TABLE_BIR);
> + flags = pci_resource_flags(dev, bir);
> + if (!flags || (flags & IORESOURCE_UNSET))
> + return NULL;
> +
> + table_offset &= PCI_MSIX_TABLE_OFFSET;
> + phys_addr = pci_resource_start(dev, bir) + table_offset;
> +
> + return ioremap(phys_addr, nr_entries * PCI_MSIX_ENTRY_SIZE);
> +}
> +
> +static int msix_setup_entries(struct pci_dev *dev, void __iomem *base,
> + struct msix_entry *entries, int nvec,
> + struct irq_affinity *affd)
> +{
> + struct irq_affinity_desc *curmsk, *masks = NULL;
> + struct msi_desc *entry;
> + void __iomem *addr;
> + int ret, i;
> + int vec_count = pci_msix_vec_count(dev);
> +
> + if (affd)
> + masks = irq_create_affinity_masks(nvec, affd);
> +
> + for (i = 0, curmsk = masks; i < nvec; i++) {
> + entry = alloc_msi_entry(&dev->dev, 1, curmsk);
> + if (!entry) {
> + if (!i)
> + iounmap(base);
> + else
> + free_msi_irqs(dev);
> + /* No enough memory. Don't try again */
> + ret = -ENOMEM;
> + goto out;
> + }
> +
> + entry->pci.msi_attrib.is_msix = 1;
> + entry->pci.msi_attrib.is_64 = 1;
> +
> + if (entries)
> + entry->pci.msi_attrib.entry_nr = entries[i].entry;
> + else
> + entry->pci.msi_attrib.entry_nr = i;
> +
> + entry->pci.msi_attrib.is_virtual =
> + entry->pci.msi_attrib.entry_nr >= vec_count;
> +
> + entry->pci.msi_attrib.can_mask = !pci_msi_ignore_mask &&
> + !entry->pci.msi_attrib.is_virtual;
> +
> + entry->pci.msi_attrib.default_irq = dev->irq;
> + entry->pci.mask_base = base;
> +
> + if (entry->pci.msi_attrib.can_mask) {
> + addr = pci_msix_desc_addr(entry);
> + entry->pci.msix_ctrl = readl(addr + PCI_MSIX_ENTRY_VECTOR_CTRL);
> + }
> +
> + list_add_tail(&entry->list, dev_to_msi_list(&dev->dev));
> + if (masks)
> + curmsk++;
> + }
> + ret = 0;
> +out:
> + kfree(masks);
> + return ret;
> +}
> +
> +static void msix_update_entries(struct pci_dev *dev, struct msix_entry *entries)
> +{
> + struct msi_desc *entry;
> +
> + if (entries) {
> + for_each_pci_msi_entry(entry, dev) {
> + entries->vector = entry->irq;
> + entries++;
> + }
> + }
> +}
> +
> +static void msix_mask_all(void __iomem *base, int tsize)
> +{
> + u32 ctrl = PCI_MSIX_ENTRY_CTRL_MASKBIT;
> + int i;
> +
> + if (pci_msi_ignore_mask)
> + return;
> +
> + for (i = 0; i < tsize; i++, base += PCI_MSIX_ENTRY_SIZE)
> + writel(ctrl, base + PCI_MSIX_ENTRY_VECTOR_CTRL);
> +}
> +
> +/**
> + * msix_capability_init - configure device's MSI-X capability
> + * @dev: pointer to the pci_dev data structure of MSI-X device function
> + * @entries: pointer to an array of struct msix_entry entries
> + * @nvec: number of @entries
> + * @affd: Optional pointer to enable automatic affinity assignment
> + *
> + * Setup the MSI-X capability structure of device function with a
> + * single MSI-X IRQ. A return of zero indicates the successful setup of
> + * requested MSI-X entries with allocated IRQs or non-zero for otherwise.
> + **/
> +static int msix_capability_init(struct pci_dev *dev, struct msix_entry *entries,
> + int nvec, struct irq_affinity *affd)
> +{
> + const struct attribute_group **groups;
> + void __iomem *base;
> + int ret, tsize;
> + u16 control;
> +
> + /*
> + * Some devices require MSI-X to be enabled before the MSI-X
> + * registers can be accessed. Mask all the vectors to prevent
> + * interrupts coming in before they're fully set up.
> + */
> + pci_msix_clear_and_set_ctrl(dev, 0, PCI_MSIX_FLAGS_MASKALL |
> + PCI_MSIX_FLAGS_ENABLE);
> +
> + pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &control);
> + /* Request & Map MSI-X table region */
> + tsize = msix_table_size(control);
> + base = msix_map_region(dev, tsize);
> + if (!base) {
> + ret = -ENOMEM;
> + goto out_disable;
> + }
> +
> + /* Ensure that all table entries are masked. */
> + msix_mask_all(base, tsize);
> +
> + ret = msix_setup_entries(dev, base, entries, nvec, affd);
> + if (ret)
> + goto out_disable;
> +
> + ret = pci_msi_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSIX);
> + if (ret)
> + goto out_avail;
> +
> + /* Check if all MSI entries honor device restrictions */
> + ret = msi_verify_entries(dev);
> + if (ret)
> + goto out_free;
> +
> + msix_update_entries(dev, entries);
> +
> + groups = msi_populate_sysfs(&dev->dev);
> + if (IS_ERR(groups)) {
> + ret = PTR_ERR(groups);
> + goto out_free;
> + }
> +
> + dev->msi_irq_groups = groups;
> +
> + /* Set MSI-X enabled bits and unmask the function */
> + pci_intx_for_msi(dev, 0);
> + dev->msix_enabled = 1;
> + pci_msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_MASKALL, 0);
> +
> + pcibios_free_irq(dev);
> + return 0;
> +
> +out_avail:
> + if (ret < 0) {
> + /*
> + * If we had some success, report the number of IRQs
> + * we succeeded in setting up.
> + */
> + struct msi_desc *entry;
> + int avail = 0;
> +
> + for_each_pci_msi_entry(entry, dev) {
> + if (entry->irq != 0)
> + avail++;
> + }
> + if (avail != 0)
> + ret = avail;
> + }
> +
> +out_free:
> + free_msi_irqs(dev);
> +
> +out_disable:
> + pci_msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_ENABLE, 0);
> +
> + return ret;
> +}
> +
> +/**
> + * pci_msi_supported - check whether MSI may be enabled on a device
> + * @dev: pointer to the pci_dev data structure of MSI device function
> + * @nvec: how many MSIs have been requested?
> + *
> + * Look at global flags, the device itself, and its parent buses
> + * to determine if MSI/-X are supported for the device. If MSI/-X is
> + * supported return 1, else return 0.
> + **/
> +static int pci_msi_supported(struct pci_dev *dev, int nvec)
> +{
> + struct pci_bus *bus;
> +
> + /* MSI must be globally enabled and supported by the device */
> + if (!pci_msi_enable)
> + return 0;
> +
> + if (!dev || dev->no_msi)
> + return 0;
> +
> + /*
> + * You can't ask to have 0 or less MSIs configured.
> + * a) it's stupid ..
> + * b) the list manipulation code assumes nvec >= 1.
> + */
> + if (nvec < 1)
> + return 0;
> +
> + /*
> + * Any bridge which does NOT route MSI transactions from its
> + * secondary bus to its primary bus must set NO_MSI flag on
> + * the secondary pci_bus.
> + *
> + * The NO_MSI flag can either be set directly by:
> + * - arch-specific PCI host bus controller drivers (deprecated)
> + * - quirks for specific PCI bridges
> + *
> + * or indirectly by platform-specific PCI host bridge drivers by
> + * advertising the 'msi_domain' property, which results in
> + * the NO_MSI flag when no MSI domain is found for this bridge
> + * at probe time.
> + */
> + for (bus = dev->bus; bus; bus = bus->parent)
> + if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI)
> + return 0;
> +
> + return 1;
> +}
> +
> +/**
> + * pci_msi_vec_count - Return the number of MSI vectors a device can send
> + * @dev: device to report about
> + *
> + * This function returns the number of MSI vectors a device requested via
> + * Multiple Message Capable register. It returns a negative errno if the
> + * device is not capable sending MSI interrupts. Otherwise, the call succeeds
> + * and returns a power of two, up to a maximum of 2^5 (32), according to the
> + * MSI specification.
> + **/
> +int pci_msi_vec_count(struct pci_dev *dev)
> +{
> + int ret;
> + u16 msgctl;
> +
> + if (!dev->msi_cap)
> + return -EINVAL;
> +
> + pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &msgctl);
> + ret = 1 << ((msgctl & PCI_MSI_FLAGS_QMASK) >> 1);
> +
> + return ret;
> +}
> +EXPORT_SYMBOL(pci_msi_vec_count);
> +
> +static void pci_msi_shutdown(struct pci_dev *dev)
> +{
> + struct msi_desc *desc;
> +
> + if (!pci_msi_enable || !dev || !dev->msi_enabled)
> + return;
> +
> + BUG_ON(list_empty(dev_to_msi_list(&dev->dev)));
> + desc = first_pci_msi_entry(dev);
> +
> + pci_msi_set_enable(dev, 0);
> + pci_intx_for_msi(dev, 1);
> + dev->msi_enabled = 0;
> +
> + /* Return the device with MSI unmasked as initial states */
> + pci_msi_unmask(desc, msi_multi_mask(desc));
> +
> + /* Restore dev->irq to its default pin-assertion IRQ */
> + dev->irq = desc->pci.msi_attrib.default_irq;
> + pcibios_alloc_irq(dev);
> +}
> +
> +void pci_disable_msi(struct pci_dev *dev)
> +{
> + if (!pci_msi_enable || !dev || !dev->msi_enabled)
> + return;
> +
> + pci_msi_shutdown(dev);
> + free_msi_irqs(dev);
> +}
> +EXPORT_SYMBOL(pci_disable_msi);
> +
> +/**
> + * pci_msix_vec_count - return the number of device's MSI-X table entries
> + * @dev: pointer to the pci_dev data structure of MSI-X device function
> + * This function returns the number of device's MSI-X table entries and
> + * therefore the number of MSI-X vectors device is capable of sending.
> + * It returns a negative errno if the device is not capable of sending MSI-X
> + * interrupts.
> + **/
> +int pci_msix_vec_count(struct pci_dev *dev)
> +{
> + u16 control;
> +
> + if (!dev->msix_cap)
> + return -EINVAL;
> +
> + pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &control);
> + return msix_table_size(control);
> +}
> +EXPORT_SYMBOL(pci_msix_vec_count);
> +
> +static int __pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries,
> + int nvec, struct irq_affinity *affd, int flags)
> +{
> + int nr_entries;
> + int i, j;
> +
> + if (!pci_msi_supported(dev, nvec) || dev->current_state != PCI_D0)
> + return -EINVAL;
> +
> + nr_entries = pci_msix_vec_count(dev);
> + if (nr_entries < 0)
> + return nr_entries;
> + if (nvec > nr_entries && !(flags & PCI_IRQ_VIRTUAL))
> + return nr_entries;
> +
> + if (entries) {
> + /* Check for any invalid entries */
> + for (i = 0; i < nvec; i++) {
> + if (entries[i].entry >= nr_entries)
> + return -EINVAL; /* invalid entry */
> + for (j = i + 1; j < nvec; j++) {
> + if (entries[i].entry == entries[j].entry)
> + return -EINVAL; /* duplicate entry */
> + }
> + }
> + }
> +
> + /* Check whether driver already requested for MSI IRQ */
> + if (dev->msi_enabled) {
> + pci_info(dev, "can't enable MSI-X (MSI IRQ already assigned)\n");
> + return -EINVAL;
> + }
> + return msix_capability_init(dev, entries, nvec, affd);
> +}
> +
> +static void pci_msix_shutdown(struct pci_dev *dev)
> +{
> + struct msi_desc *entry;
> +
> + if (!pci_msi_enable || !dev || !dev->msix_enabled)
> + return;
> +
> + if (pci_dev_is_disconnected(dev)) {
> + dev->msix_enabled = 0;
> + return;
> + }
> +
> + /* Return the device with MSI-X masked as initial states */
> + for_each_pci_msi_entry(entry, dev)
> + pci_msix_mask(entry);
> +
> + pci_msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_ENABLE, 0);
> + pci_intx_for_msi(dev, 1);
> + dev->msix_enabled = 0;
> + pcibios_alloc_irq(dev);
> +}
> +
> +void pci_disable_msix(struct pci_dev *dev)
> +{
> + if (!pci_msi_enable || !dev || !dev->msix_enabled)
> + return;
> +
> + pci_msix_shutdown(dev);
> + free_msi_irqs(dev);
> +}
> +EXPORT_SYMBOL(pci_disable_msix);
> +
> +void pci_no_msi(void)
> +{
> + pci_msi_enable = 0;
> +}
> +
> +/**
> + * pci_msi_enabled - is MSI enabled?
> + *
> + * Returns true if MSI has not been disabled by the command-line option
> + * pci=nomsi.
> + **/
> +int pci_msi_enabled(void)
> +{
> + return pci_msi_enable;
> +}
> +EXPORT_SYMBOL(pci_msi_enabled);
> +
> +static int __pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec,
> + struct irq_affinity *affd)
> +{
> + int nvec;
> + int rc;
> +
> + if (!pci_msi_supported(dev, minvec) || dev->current_state != PCI_D0)
> + return -EINVAL;
> +
> + /* Check whether driver already requested MSI-X IRQs */
> + if (dev->msix_enabled) {
> + pci_info(dev, "can't enable MSI (MSI-X already enabled)\n");
> + return -EINVAL;
> + }
> +
> + if (maxvec < minvec)
> + return -ERANGE;
> +
> + if (WARN_ON_ONCE(dev->msi_enabled))
> + return -EINVAL;
> +
> + nvec = pci_msi_vec_count(dev);
> + if (nvec < 0)
> + return nvec;
> + if (nvec < minvec)
> + return -ENOSPC;
> +
> + if (nvec > maxvec)
> + nvec = maxvec;
> +
> + for (;;) {
> + if (affd) {
> + nvec = irq_calc_affinity_vectors(minvec, nvec, affd);
> + if (nvec < minvec)
> + return -ENOSPC;
> + }
> +
> + rc = msi_capability_init(dev, nvec, affd);
> + if (rc == 0)
> + return nvec;
> +
> + if (rc < 0)
> + return rc;
> + if (rc < minvec)
> + return -ENOSPC;
> +
> + nvec = rc;
> + }
> +}
> +
> +/* deprecated, don't use */
> +int pci_enable_msi(struct pci_dev *dev)
> +{
> + int rc = __pci_enable_msi_range(dev, 1, 1, NULL);
> + if (rc < 0)
> + return rc;
> + return 0;
> +}
> +EXPORT_SYMBOL(pci_enable_msi);
> +
> +static int __pci_enable_msix_range(struct pci_dev *dev,
> + struct msix_entry *entries, int minvec,
> + int maxvec, struct irq_affinity *affd,
> + int flags)
> +{
> + int rc, nvec = maxvec;
> +
> + if (maxvec < minvec)
> + return -ERANGE;
> +
> + if (WARN_ON_ONCE(dev->msix_enabled))
> + return -EINVAL;
> +
> + for (;;) {
> + if (affd) {
> + nvec = irq_calc_affinity_vectors(minvec, nvec, affd);
> + if (nvec < minvec)
> + return -ENOSPC;
> + }
> +
> + rc = __pci_enable_msix(dev, entries, nvec, affd, flags);
> + if (rc == 0)
> + return nvec;
> +
> + if (rc < 0)
> + return rc;
> + if (rc < minvec)
> + return -ENOSPC;
> +
> + nvec = rc;
> + }
> +}
> +
> +/**
> + * pci_enable_msix_range - configure device's MSI-X capability structure
> + * @dev: pointer to the pci_dev data structure of MSI-X device function
> + * @entries: pointer to an array of MSI-X entries
> + * @minvec: minimum number of MSI-X IRQs requested
> + * @maxvec: maximum number of MSI-X IRQs requested
> + *
> + * Setup the MSI-X capability structure of device function with a maximum
> + * possible number of interrupts in the range between @minvec and @maxvec
> + * upon its software driver call to request for MSI-X mode enabled on its
> + * hardware device function. It returns a negative errno if an error occurs.
> + * If it succeeds, it returns the actual number of interrupts allocated and
> + * indicates the successful configuration of MSI-X capability structure
> + * with new allocated MSI-X interrupts.
> + **/
> +int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries,
> + int minvec, int maxvec)
> +{
> + return __pci_enable_msix_range(dev, entries, minvec, maxvec, NULL, 0);
> +}
> +EXPORT_SYMBOL(pci_enable_msix_range);
> +
> +/**
> + * pci_alloc_irq_vectors_affinity - allocate multiple IRQs for a device
> + * @dev: PCI device to operate on
> + * @min_vecs: minimum number of vectors required (must be >= 1)
> + * @max_vecs: maximum (desired) number of vectors
> + * @flags: flags or quirks for the allocation
> + * @affd: optional description of the affinity requirements
> + *
> + * Allocate up to @max_vecs interrupt vectors for @dev, using MSI-X or MSI
> + * vectors if available, and fall back to a single legacy vector
> + * if neither is available. Return the number of vectors allocated,
> + * (which might be smaller than @max_vecs) if successful, or a negative
> + * error code on error. If less than @min_vecs interrupt vectors are
> + * available for @dev the function will fail with -ENOSPC.
> + *
> + * To get the Linux IRQ number used for a vector that can be passed to
> + * request_irq() use the pci_irq_vector() helper.
> + */
> +int pci_alloc_irq_vectors_affinity(struct pci_dev *dev, unsigned int min_vecs,
> + unsigned int max_vecs, unsigned int flags,
> + struct irq_affinity *affd)
> +{
> + struct irq_affinity msi_default_affd = {0};
> + int nvecs = -ENOSPC;
> +
> + if (flags & PCI_IRQ_AFFINITY) {
> + if (!affd)
> + affd = &msi_default_affd;
> + } else {
> + if (WARN_ON(affd))
> + affd = NULL;
> + }
> +
> + if (flags & PCI_IRQ_MSIX) {
> + nvecs = __pci_enable_msix_range(dev, NULL, min_vecs, max_vecs,
> + affd, flags);
> + if (nvecs > 0)
> + return nvecs;
> + }
> +
> + if (flags & PCI_IRQ_MSI) {
> + nvecs = __pci_enable_msi_range(dev, min_vecs, max_vecs, affd);
> + if (nvecs > 0)
> + return nvecs;
> + }
> +
> + /* use legacy IRQ if allowed */
> + if (flags & PCI_IRQ_LEGACY) {
> + if (min_vecs == 1 && dev->irq) {
> + /*
> + * Invoke the affinity spreading logic to ensure that
> + * the device driver can adjust queue configuration
> + * for the single interrupt case.
> + */
> + if (affd)
> + irq_create_affinity_masks(1, affd);
> + pci_intx(dev, 1);
> + return 1;
> + }
> + }
> +
> + return nvecs;
> +}
> +EXPORT_SYMBOL(pci_alloc_irq_vectors_affinity);
> +
> +/**
> + * pci_free_irq_vectors - free previously allocated IRQs for a device
> + * @dev: PCI device to operate on
> + *
> + * Undoes the allocations and enabling in pci_alloc_irq_vectors().
> + */
> +void pci_free_irq_vectors(struct pci_dev *dev)
> +{
> + pci_disable_msix(dev);
> + pci_disable_msi(dev);
> +}
> +EXPORT_SYMBOL(pci_free_irq_vectors);
> +
> +/**
> + * pci_irq_vector - return Linux IRQ number of a device vector
> + * @dev: PCI device to operate on
> + * @nr: Interrupt vector index (0-based)
> + *
> + * @nr has the following meanings depending on the interrupt mode:
> + * MSI-X: The index in the MSI-X vector table
> + * MSI: The index of the enabled MSI vectors
> + * INTx: Must be 0
> + *
> + * Return: The Linux interrupt number or -EINVAl if @nr is out of range.
> + */
> +int pci_irq_vector(struct pci_dev *dev, unsigned int nr)
> +{
> + if (dev->msix_enabled) {
> + struct msi_desc *entry;
> +
> + for_each_pci_msi_entry(entry, dev) {
> + if (entry->pci.msi_attrib.entry_nr == nr)
> + return entry->irq;
> + }
> + WARN_ON_ONCE(1);
> + return -EINVAL;
> + }
> +
> + if (dev->msi_enabled) {
> + struct msi_desc *entry = first_pci_msi_entry(dev);
> +
> + if (WARN_ON_ONCE(nr >= entry->nvec_used))
> + return -EINVAL;
> + } else {
> + if (WARN_ON_ONCE(nr > 0))
> + return -EINVAL;
> + }
> +
> + return dev->irq + nr;
> +}
> +EXPORT_SYMBOL(pci_irq_vector);
> +
> +/**
> + * pci_irq_get_affinity - return the affinity of a particular MSI vector
> + * @dev: PCI device to operate on
> + * @nr: device-relative interrupt vector index (0-based).
> + *
> + * @nr has the following meanings depending on the interrupt mode:
> + * MSI-X: The index in the MSI-X vector table
> + * MSI: The index of the enabled MSI vectors
> + * INTx: Must be 0
> + *
> + * Return: A cpumask pointer or NULL if @nr is out of range
> + */
> +const struct cpumask *pci_irq_get_affinity(struct pci_dev *dev, int nr)
> +{
> + if (dev->msix_enabled) {
> + struct msi_desc *entry;
> +
> + for_each_pci_msi_entry(entry, dev) {
> + if (entry->pci.msi_attrib.entry_nr == nr)
> + return &entry->affinity->mask;
> + }
> + WARN_ON_ONCE(1);
> + return NULL;
> + } else if (dev->msi_enabled) {
> + struct msi_desc *entry = first_pci_msi_entry(dev);
> +
> + if (WARN_ON_ONCE(!entry || !entry->affinity ||
> + nr >= entry->nvec_used))
> + return NULL;
> +
> + return &entry->affinity[nr].mask;
> + } else {
> + return cpu_possible_mask;
> + }
> +}
> +EXPORT_SYMBOL(pci_irq_get_affinity);
> +
> +struct pci_dev *msi_desc_to_pci_dev(struct msi_desc *desc)
> +{
> + return to_pci_dev(desc->dev);
> +}
> +EXPORT_SYMBOL(msi_desc_to_pci_dev);
> +
> +#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN
> +/**
> + * pci_msi_domain_write_msg - Helper to write MSI message to PCI config space
> + * @irq_data: Pointer to interrupt data of the MSI interrupt
> + * @msg: Pointer to the message
> + */
> +static void pci_msi_domain_write_msg(struct irq_data *irq_data, struct msi_msg *msg)
> +{
> + struct msi_desc *desc = irq_data_get_msi_desc(irq_data);
> +
> + /*
> + * For MSI-X desc->irq is always equal to irq_data->irq. For
> + * MSI only the first interrupt of MULTI MSI passes the test.
> + */
> + if (desc->irq == irq_data->irq)
> + __pci_write_msi_msg(desc, msg);
> +}
> +
> +/**
> + * pci_msi_domain_calc_hwirq - Generate a unique ID for an MSI source
> + * @desc: Pointer to the MSI descriptor
> + *
> + * The ID number is only used within the irqdomain.
> + */
> +static irq_hw_number_t pci_msi_domain_calc_hwirq(struct msi_desc *desc)
> +{
> + struct pci_dev *dev = msi_desc_to_pci_dev(desc);
> +
> + return (irq_hw_number_t)desc->pci.msi_attrib.entry_nr |
> + pci_dev_id(dev) << 11 |
> + (pci_domain_nr(dev->bus) & 0xFFFFFFFF) << 27;
> +}
> +
> +static inline bool pci_msi_desc_is_multi_msi(struct msi_desc *desc)
> +{
> + return !desc->pci.msi_attrib.is_msix && desc->nvec_used > 1;
> +}
> +
> +/**
> + * pci_msi_domain_check_cap - Verify that @domain supports the capabilities
> + * for @dev
> + * @domain: The interrupt domain to check
> + * @info: The domain info for verification
> + * @dev: The device to check
> + *
> + * Returns:
> + * 0 if the functionality is supported
> + * 1 if Multi MSI is requested, but the domain does not support it
> + * -ENOTSUPP otherwise
> + */
> +int pci_msi_domain_check_cap(struct irq_domain *domain,
> + struct msi_domain_info *info, struct device *dev)
> +{
> + struct msi_desc *desc = first_pci_msi_entry(to_pci_dev(dev));
> +
> + /* Special handling to support __pci_enable_msi_range() */
> + if (pci_msi_desc_is_multi_msi(desc) &&
> + !(info->flags & MSI_FLAG_MULTI_PCI_MSI))
> + return 1;
> + else if (desc->pci.msi_attrib.is_msix && !(info->flags & MSI_FLAG_PCI_MSIX))
> + return -ENOTSUPP;
> +
> + return 0;
> +}
> +
> +static int pci_msi_domain_handle_error(struct irq_domain *domain,
> + struct msi_desc *desc, int error)
> +{
> + /* Special handling to support __pci_enable_msi_range() */
> + if (pci_msi_desc_is_multi_msi(desc) && error == -ENOSPC)
> + return 1;
> +
> + return error;
> +}
> +
> +static void pci_msi_domain_set_desc(msi_alloc_info_t *arg,
> + struct msi_desc *desc)
> +{
> + arg->desc = desc;
> + arg->hwirq = pci_msi_domain_calc_hwirq(desc);
> +}
> +
> +static struct msi_domain_ops pci_msi_domain_ops_default = {
> + .set_desc = pci_msi_domain_set_desc,
> + .msi_check = pci_msi_domain_check_cap,
> + .handle_error = pci_msi_domain_handle_error,
> +};
> +
> +static void pci_msi_domain_update_dom_ops(struct msi_domain_info *info)
> +{
> + struct msi_domain_ops *ops = info->ops;
> +
> + if (ops == NULL) {
> + info->ops = &pci_msi_domain_ops_default;
> + } else {
> + if (ops->set_desc == NULL)
> + ops->set_desc = pci_msi_domain_set_desc;
> + if (ops->msi_check == NULL)
> + ops->msi_check = pci_msi_domain_check_cap;
> + if (ops->handle_error == NULL)
> + ops->handle_error = pci_msi_domain_handle_error;
> + }
> +}
> +
> +static void pci_msi_domain_update_chip_ops(struct msi_domain_info *info)
> +{
> + struct irq_chip *chip = info->chip;
> +
> + BUG_ON(!chip);
> + if (!chip->irq_write_msi_msg)
> + chip->irq_write_msi_msg = pci_msi_domain_write_msg;
> + if (!chip->irq_mask)
> + chip->irq_mask = pci_msi_mask_irq;
> + if (!chip->irq_unmask)
> + chip->irq_unmask = pci_msi_unmask_irq;
> +}
> +
> +/**
> + * pci_msi_create_irq_domain - Create a MSI interrupt domain
> + * @fwnode: Optional fwnode of the interrupt controller
> + * @info: MSI domain info
> + * @parent: Parent irq domain
> + *
> + * Updates the domain and chip ops and creates a MSI interrupt domain.
> + *
> + * Returns:
> + * A domain pointer or NULL in case of failure.
> + */
> +struct irq_domain *pci_msi_create_irq_domain(struct fwnode_handle *fwnode,
> + struct msi_domain_info *info,
> + struct irq_domain *parent)
> +{
> + struct irq_domain *domain;
> +
> + if (WARN_ON(info->flags & MSI_FLAG_LEVEL_CAPABLE))
> + info->flags &= ~MSI_FLAG_LEVEL_CAPABLE;
> +
> + if (info->flags & MSI_FLAG_USE_DEF_DOM_OPS)
> + pci_msi_domain_update_dom_ops(info);
> + if (info->flags & MSI_FLAG_USE_DEF_CHIP_OPS)
> + pci_msi_domain_update_chip_ops(info);
> +
> + info->flags |= MSI_FLAG_ACTIVATE_EARLY;
> + if (IS_ENABLED(CONFIG_GENERIC_IRQ_RESERVATION_MODE))
> + info->flags |= MSI_FLAG_MUST_REACTIVATE;
> +
> + /* PCI-MSI is oneshot-safe */
> + info->chip->flags |= IRQCHIP_ONESHOT_SAFE;
> +
> + domain = msi_create_irq_domain(fwnode, info, parent);
> + if (!domain)
> + return NULL;
> +
> + irq_domain_update_bus_token(domain, DOMAIN_BUS_PCI_MSI);
> + return domain;
> +}
> +EXPORT_SYMBOL_GPL(pci_msi_create_irq_domain);
> +
> +/*
> + * Users of the generic MSI infrastructure expect a device to have a single ID,
> + * so with DMA aliases we have to pick the least-worst compromise. Devices with
> + * DMA phantom functions tend to still emit MSIs from the real function number,
> + * so we ignore those and only consider topological aliases where either the
> + * alias device or RID appears on a different bus number. We also make the
> + * reasonable assumption that bridges are walked in an upstream direction (so
> + * the last one seen wins), and the much braver assumption that the most likely
> + * case is that of PCI->PCIe so we should always use the alias RID. This echoes
> + * the logic from intel_irq_remapping's set_msi_sid(), which presumably works
> + * well enough in practice; in the face of the horrible PCIe<->PCI-X conditions
> + * for taking ownership all we can really do is close our eyes and hope...
> + */
> +static int get_msi_id_cb(struct pci_dev *pdev, u16 alias, void *data)
> +{
> + u32 *pa = data;
> + u8 bus = PCI_BUS_NUM(*pa);
> +
> + if (pdev->bus->number != bus || PCI_BUS_NUM(alias) != bus)
> + *pa = alias;
> +
> + return 0;
> +}
> +
> +/**
> + * pci_msi_domain_get_msi_rid - Get the MSI requester id (RID)
> + * @domain: The interrupt domain
> + * @pdev: The PCI device.
> + *
> + * The RID for a device is formed from the alias, with a firmware
> + * supplied mapping applied
> + *
> + * Returns: The RID.
> + */
> +u32 pci_msi_domain_get_msi_rid(struct irq_domain *domain, struct pci_dev *pdev)
> +{
> + struct device_node *of_node;
> + u32 rid = pci_dev_id(pdev);
> +
> + pci_for_each_dma_alias(pdev, get_msi_id_cb, &rid);
> +
> + of_node = irq_domain_get_of_node(domain);
> + rid = of_node ? of_msi_map_id(&pdev->dev, of_node, rid) :
> + iort_msi_map_id(&pdev->dev, rid);
> +
> + return rid;
> +}
> +
> +/**
> + * pci_msi_get_device_domain - Get the MSI domain for a given PCI device
> + * @pdev: The PCI device
> + *
> + * Use the firmware data to find a device-specific MSI domain
> + * (i.e. not one that is set as a default).
> + *
> + * Returns: The corresponding MSI domain or NULL if none has been found.
> + */
> +struct irq_domain *pci_msi_get_device_domain(struct pci_dev *pdev)
> +{
> + struct irq_domain *dom;
> + u32 rid = pci_dev_id(pdev);
> +
> + pci_for_each_dma_alias(pdev, get_msi_id_cb, &rid);
> + dom = of_msi_map_get_device_domain(&pdev->dev, rid, DOMAIN_BUS_PCI_MSI);
> + if (!dom)
> + dom = iort_get_device_domain(&pdev->dev, rid,
> + DOMAIN_BUS_PCI_MSI);
> + return dom;
> +}
> +
> +/**
> + * pci_dev_has_special_msi_domain - Check whether the device is handled by
> + * a non-standard PCI-MSI domain
> + * @pdev: The PCI device to check.
> + *
> + * Returns: True if the device irqdomain or the bus irqdomain is
> + * non-standard PCI/MSI.
> + */
> +bool pci_dev_has_special_msi_domain(struct pci_dev *pdev)
> +{
> + struct irq_domain *dom = dev_get_msi_domain(&pdev->dev);
> +
> + if (!dom)
> + dom = dev_get_msi_domain(&pdev->bus->dev);
> +
> + if (!dom)
> + return true;
> +
> + return dom->bus_token != DOMAIN_BUS_PCI_MSI;
> +}
> +
> +#endif /* CONFIG_PCI_MSI_IRQ_DOMAIN */
> +#endif /* CONFIG_PCI_MSI */
> +
> +void pci_msi_init(struct pci_dev *dev)
> +{
> + u16 ctrl;
> +
> + /*
> + * Disable the MSI hardware to avoid screaming interrupts
> + * during boot. This is the power on reset default so
> + * usually this should be a noop.
> + */
> + dev->msi_cap = pci_find_capability(dev, PCI_CAP_ID_MSI);
> + if (!dev->msi_cap)
> + return;
> +
> + pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &ctrl);
> + if (ctrl & PCI_MSI_FLAGS_ENABLE)
> + pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS,
> + ctrl & ~PCI_MSI_FLAGS_ENABLE);
> +
> + if (!(ctrl & PCI_MSI_FLAGS_64BIT))
> + dev->no_64bit_msi = 1;
> +}
> +
> +void pci_msix_init(struct pci_dev *dev)
> +{
> + u16 ctrl;
> +
> + dev->msix_cap = pci_find_capability(dev, PCI_CAP_ID_MSIX);
> + if (!dev->msix_cap)
> + return;
> +
> + pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &ctrl);
> + if (ctrl & PCI_MSIX_FLAGS_ENABLE)
> + pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS,
> + ctrl & ~PCI_MSIX_FLAGS_ENABLE);
> +}
>
^ permalink raw reply
* Re: [patch V2 14/23] PCI/MSI: Make msix_update_entries() smarter
From: Bjorn Helgaas @ 2021-12-07 20:57 UTC (permalink / raw)
To: Thomas Gleixner
Cc: linux-hyperv, linux-mips, Paul Mackerras, sparclinux, Wei Liu,
Ashok Raj, x86, Christian Borntraeger, Megha Dey, Jason Gunthorpe,
linux-pci, xen-devel, ath11k, Kevin Tian, Heiko Carstens,
Alex Williamson, Cedric Le Goater, Kalle Valo, Juergen Gross,
Thomas Bogendoerfer, Greg Kroah-Hartman, LKML, Marc Zygnier,
linuxppc-dev
In-Reply-To: <20211206210224.600351129@linutronix.de>
On Mon, Dec 06, 2021 at 11:27:46PM +0100, Thomas Gleixner wrote:
> No need to walk the descriptors and check for each one whether the entries
> pointer function argument is NULL. Do it once.
>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> Tested-by: Juergen Gross <jgross@suse.com>
> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
> ---
> drivers/pci/msi.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> --- a/drivers/pci/msi.c
> +++ b/drivers/pci/msi.c
> @@ -642,8 +642,8 @@ static void msix_update_entries(struct p
> {
> struct msi_desc *entry;
>
> - for_each_pci_msi_entry(entry, dev) {
> - if (entries) {
> + if (entries) {
> + for_each_pci_msi_entry(entry, dev) {
> entries->vector = entry->irq;
> entries++;
> }
>
^ permalink raw reply
* Re: [patch V2 13/23] PCI/MSI: Cleanup include zoo
From: Bjorn Helgaas @ 2021-12-07 20:57 UTC (permalink / raw)
To: Thomas Gleixner
Cc: linux-hyperv, linux-mips, Paul Mackerras, sparclinux, Wei Liu,
Ashok Raj, x86, Christian Borntraeger, Megha Dey, Jason Gunthorpe,
linux-pci, xen-devel, ath11k, Kevin Tian, Heiko Carstens,
Alex Williamson, Cedric Le Goater, Kalle Valo, Juergen Gross,
Thomas Bogendoerfer, Greg Kroah-Hartman, LKML, Marc Zygnier,
linuxppc-dev
In-Reply-To: <20211206210224.539281124@linutronix.de>
On Mon, Dec 06, 2021 at 11:27:44PM +0100, Thomas Gleixner wrote:
> Get rid of the pile of unneeded includes which accumulated over time.
>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> Tested-by: Juergen Gross <jgross@suse.com>
> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
Nice, thanks!
> ---
> V2: Address build fail on powerpc - Cedric
> ---
> drivers/pci/msi.c | 16 ++++------------
> 1 file changed, 4 insertions(+), 12 deletions(-)
>
> --- a/drivers/pci/msi.c
> +++ b/drivers/pci/msi.c
> @@ -7,22 +7,14 @@
> * Copyright (C) 2016 Christoph Hellwig.
> */
>
> +#include <linux/acpi_iort.h>
> #include <linux/err.h>
> -#include <linux/mm.h>
> -#include <linux/irq.h>
> -#include <linux/interrupt.h>
> #include <linux/export.h>
> -#include <linux/ioport.h>
> -#include <linux/pci.h>
> -#include <linux/proc_fs.h>
> -#include <linux/msi.h>
> -#include <linux/smp.h>
> -#include <linux/errno.h>
> -#include <linux/io.h>
> -#include <linux/acpi_iort.h>
> -#include <linux/slab.h>
> +#include <linux/irq.h>
> #include <linux/irqdomain.h>
> +#include <linux/msi.h>
> #include <linux/of_irq.h>
> +#include <linux/pci.h>
>
> #include "pci.h"
>
>
^ permalink raw reply
* Re: [patch V2 12/23] PCI/MSI: Make arch_restore_msi_irqs() less horrible.
From: Bjorn Helgaas @ 2021-12-07 20:56 UTC (permalink / raw)
To: Thomas Gleixner
Cc: linux-hyperv, linux-mips, Paul Mackerras, sparclinux, Wei Liu,
Ashok Raj, x86, Christian Borntraeger, Megha Dey, Jason Gunthorpe,
linux-pci, xen-devel, ath11k, Kevin Tian, Heiko Carstens,
Alex Williamson, Cedric Le Goater, Kalle Valo, Juergen Gross,
Thomas Bogendoerfer, Greg Kroah-Hartman, LKML, Marc Zygnier,
linuxppc-dev
In-Reply-To: <20211206210224.485668098@linutronix.de>
On Mon, Dec 06, 2021 at 11:27:42PM +0100, Thomas Gleixner wrote:
> Make arch_restore_msi_irqs() return a boolean which indicates whether the
> core code should restore the MSI message or not. Get rid of the indirection
> in x86.
>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> Tested-by: Juergen Gross <jgross@suse.com>
> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
> Cc: x86@kernel.org
> Cc: xen-devel@lists.xenproject.org
> Cc: Christian Borntraeger <borntraeger@de.ibm.com>
> Cc: Heiko Carstens <hca@linux.ibm.com>
Acked-by: Bjorn Helgaas <bhelgaas@google.com> # PCI
> ---
> arch/s390/pci/pci_irq.c | 4 +-
> arch/x86/include/asm/x86_init.h | 6 ---
> arch/x86/include/asm/xen/hypervisor.h | 8 +++++
> arch/x86/kernel/apic/msi.c | 6 +++
> arch/x86/kernel/x86_init.c | 12 -------
> arch/x86/pci/xen.c | 13 ++++----
> drivers/pci/msi.c | 54 +++++++++++-----------------------
> include/linux/msi.h | 7 +---
> 8 files changed, 45 insertions(+), 65 deletions(-)
>
> --- a/arch/s390/pci/pci_irq.c
> +++ b/arch/s390/pci/pci_irq.c
> @@ -387,13 +387,13 @@ void arch_teardown_msi_irqs(struct pci_d
> airq_iv_free(zpci_ibv[0], zdev->msi_first_bit, zdev->msi_nr_irqs);
> }
>
> -void arch_restore_msi_irqs(struct pci_dev *pdev)
> +bool arch_restore_msi_irqs(struct pci_dev *pdev)
> {
> struct zpci_dev *zdev = to_zpci(pdev);
>
> if (!zdev->irqs_registered)
> zpci_set_irq(zdev);
> - default_restore_msi_irqs(pdev);
> + return true;
> }
>
> static struct airq_struct zpci_airq = {
> --- a/arch/x86/include/asm/x86_init.h
> +++ b/arch/x86/include/asm/x86_init.h
> @@ -289,12 +289,6 @@ struct x86_platform_ops {
> struct x86_hyper_runtime hyper;
> };
>
> -struct pci_dev;
> -
> -struct x86_msi_ops {
> - void (*restore_msi_irqs)(struct pci_dev *dev);
> -};
> -
> struct x86_apic_ops {
> unsigned int (*io_apic_read) (unsigned int apic, unsigned int reg);
> void (*restore)(void);
> --- a/arch/x86/include/asm/xen/hypervisor.h
> +++ b/arch/x86/include/asm/xen/hypervisor.h
> @@ -57,6 +57,14 @@ static inline bool __init xen_x2apic_par
> }
> #endif
>
> +struct pci_dev;
> +
> +#ifdef CONFIG_XEN_DOM0
> +bool xen_initdom_restore_msi(struct pci_dev *dev);
> +#else
> +static inline bool xen_initdom_restore_msi(struct pci_dev *dev) { return true; }
> +#endif
> +
> #ifdef CONFIG_HOTPLUG_CPU
> void xen_arch_register_cpu(int num);
> void xen_arch_unregister_cpu(int num);
> --- a/arch/x86/kernel/apic/msi.c
> +++ b/arch/x86/kernel/apic/msi.c
> @@ -19,6 +19,7 @@
> #include <asm/hw_irq.h>
> #include <asm/apic.h>
> #include <asm/irq_remapping.h>
> +#include <asm/xen/hypervisor.h>
>
> struct irq_domain *x86_pci_msi_default_domain __ro_after_init;
>
> @@ -345,3 +346,8 @@ void dmar_free_hwirq(int irq)
> irq_domain_free_irqs(irq, 1);
> }
> #endif
> +
> +bool arch_restore_msi_irqs(struct pci_dev *dev)
> +{
> + return xen_initdom_restore_msi(dev);
> +}
> --- a/arch/x86/kernel/x86_init.c
> +++ b/arch/x86/kernel/x86_init.c
> @@ -145,18 +145,6 @@ struct x86_platform_ops x86_platform __r
>
> EXPORT_SYMBOL_GPL(x86_platform);
>
> -#if defined(CONFIG_PCI_MSI)
> -struct x86_msi_ops x86_msi __ro_after_init = {
> - .restore_msi_irqs = default_restore_msi_irqs,
> -};
> -
> -/* MSI arch specific hooks */
> -void arch_restore_msi_irqs(struct pci_dev *dev)
> -{
> - x86_msi.restore_msi_irqs(dev);
> -}
> -#endif
> -
> struct x86_apic_ops x86_apic_ops __ro_after_init = {
> .io_apic_read = native_io_apic_read,
> .restore = native_restore_boot_irq_mode,
> --- a/arch/x86/pci/xen.c
> +++ b/arch/x86/pci/xen.c
> @@ -351,10 +351,13 @@ static int xen_initdom_setup_msi_irqs(st
> return ret;
> }
>
> -static void xen_initdom_restore_msi_irqs(struct pci_dev *dev)
> +bool xen_initdom_restore_msi(struct pci_dev *dev)
> {
> int ret = 0;
>
> + if (!xen_initial_domain())
> + return true;
> +
> if (pci_seg_supported) {
> struct physdev_pci_device restore_ext;
>
> @@ -375,10 +378,10 @@ static void xen_initdom_restore_msi_irqs
> ret = HYPERVISOR_physdev_op(PHYSDEVOP_restore_msi, &restore);
> WARN(ret && ret != -ENOSYS, "restore_msi -> %d\n", ret);
> }
> + return false;
> }
> #else /* CONFIG_XEN_PV_DOM0 */
> #define xen_initdom_setup_msi_irqs NULL
> -#define xen_initdom_restore_msi_irqs NULL
> #endif /* !CONFIG_XEN_PV_DOM0 */
>
> static void xen_teardown_msi_irqs(struct pci_dev *dev)
> @@ -466,12 +469,10 @@ static __init struct irq_domain *xen_cre
> static __init void xen_setup_pci_msi(void)
> {
> if (xen_pv_domain()) {
> - if (xen_initial_domain()) {
> + if (xen_initial_domain())
> xen_msi_ops.setup_msi_irqs = xen_initdom_setup_msi_irqs;
> - x86_msi.restore_msi_irqs = xen_initdom_restore_msi_irqs;
> - } else {
> + else
> xen_msi_ops.setup_msi_irqs = xen_setup_msi_irqs;
> - }
> xen_msi_ops.teardown_msi_irqs = xen_pv_teardown_msi_irqs;
> pci_msi_ignore_mask = 1;
> } else if (xen_hvm_domain()) {
> --- a/drivers/pci/msi.c
> +++ b/drivers/pci/msi.c
> @@ -106,29 +106,6 @@ void __weak arch_teardown_msi_irqs(struc
> }
> #endif /* CONFIG_PCI_MSI_ARCH_FALLBACKS */
>
> -static void default_restore_msi_irq(struct pci_dev *dev, int irq)
> -{
> - struct msi_desc *entry;
> -
> - entry = NULL;
> - if (dev->msix_enabled) {
> - for_each_pci_msi_entry(entry, dev) {
> - if (irq == entry->irq)
> - break;
> - }
> - } else if (dev->msi_enabled) {
> - entry = irq_get_msi_desc(irq);
> - }
> -
> - if (entry)
> - __pci_write_msi_msg(entry, &entry->msg);
> -}
> -
> -void __weak arch_restore_msi_irqs(struct pci_dev *dev)
> -{
> - return default_restore_msi_irqs(dev);
> -}
> -
> /*
> * PCI 2.3 does not specify mask bits for each MSI interrupt. Attempting to
> * mask all MSI interrupts by clearing the MSI enable bit does not work
> @@ -242,14 +219,6 @@ void pci_msi_unmask_irq(struct irq_data
> }
> EXPORT_SYMBOL_GPL(pci_msi_unmask_irq);
>
> -void default_restore_msi_irqs(struct pci_dev *dev)
> -{
> - struct msi_desc *entry;
> -
> - for_each_pci_msi_entry(entry, dev)
> - default_restore_msi_irq(dev, entry->irq);
> -}
> -
> void __pci_read_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
> {
> struct pci_dev *dev = msi_desc_to_pci_dev(entry);
> @@ -403,10 +372,19 @@ static void pci_msi_set_enable(struct pc
> pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control);
> }
>
> +/*
> + * Architecture override returns true when the PCI MSI message should be
> + * written by the generic restore function.
> + */
> +bool __weak arch_restore_msi_irqs(struct pci_dev *dev)
> +{
> + return true;
> +}
> +
> static void __pci_restore_msi_state(struct pci_dev *dev)
> {
> - u16 control;
> struct msi_desc *entry;
> + u16 control;
>
> if (!dev->msi_enabled)
> return;
> @@ -415,7 +393,8 @@ static void __pci_restore_msi_state(stru
>
> pci_intx_for_msi(dev, 0);
> pci_msi_set_enable(dev, 0);
> - arch_restore_msi_irqs(dev);
> + if (arch_restore_msi_irqs(dev))
> + __pci_write_msi_msg(entry, &entry->msg);
>
> pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);
> pci_msi_update_mask(entry, 0, 0);
> @@ -437,6 +416,7 @@ static void pci_msix_clear_and_set_ctrl(
> static void __pci_restore_msix_state(struct pci_dev *dev)
> {
> struct msi_desc *entry;
> + bool write_msg;
>
> if (!dev->msix_enabled)
> return;
> @@ -447,9 +427,13 @@ static void __pci_restore_msix_state(str
> pci_msix_clear_and_set_ctrl(dev, 0,
> PCI_MSIX_FLAGS_ENABLE | PCI_MSIX_FLAGS_MASKALL);
>
> - arch_restore_msi_irqs(dev);
> - for_each_pci_msi_entry(entry, dev)
> + write_msg = arch_restore_msi_irqs(dev);
> +
> + for_each_pci_msi_entry(entry, dev) {
> + if (write_msg)
> + __pci_write_msi_msg(entry, &entry->msg);
> pci_msix_write_vector_ctrl(entry, entry->pci.msix_ctrl);
> + }
>
> pci_msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_MASKALL, 0);
> }
> --- a/include/linux/msi.h
> +++ b/include/linux/msi.h
> @@ -273,11 +273,10 @@ static inline void arch_teardown_msi_irq
> #endif
>
> /*
> - * The restore hooks are still available as they are useful even
> - * for fully irq domain based setups. Courtesy to XEN/X86.
> + * The restore hook is still available even for fully irq domain based
> + * setups. Courtesy to XEN/X86.
> */
> -void arch_restore_msi_irqs(struct pci_dev *dev);
> -void default_restore_msi_irqs(struct pci_dev *dev);
> +bool arch_restore_msi_irqs(struct pci_dev *dev);
>
> #ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
>
>
^ permalink raw reply
* Re: [patch V2 08/23] PCI/sysfs: Use pci_irq_vector()
From: Bjorn Helgaas @ 2021-12-07 20:56 UTC (permalink / raw)
To: Thomas Gleixner
Cc: linux-hyperv, linux-mips, Paul Mackerras, sparclinux, Wei Liu,
Ashok Raj, x86, Christian Borntraeger, Megha Dey, Jason Gunthorpe,
linux-pci, xen-devel, ath11k, Kevin Tian, Heiko Carstens,
Alex Williamson, Cedric Le Goater, Kalle Valo, Juergen Gross,
Thomas Bogendoerfer, Greg Kroah-Hartman, LKML, Marc Zygnier,
linuxppc-dev
In-Reply-To: <20211206210224.265589103@linutronix.de>
On Mon, Dec 06, 2021 at 11:27:36PM +0100, Thomas Gleixner wrote:
> instead of fiddling with msi descriptors.
>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> Tested-by: Juergen Gross <jgross@suse.com>
> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
s/msi/MSI/ above if you have a chance. Nice cleanup, thanks!
> ---
> drivers/pci/pci-sysfs.c | 7 ++-----
> 1 file changed, 2 insertions(+), 5 deletions(-)
>
> --- a/drivers/pci/pci-sysfs.c
> +++ b/drivers/pci/pci-sysfs.c
> @@ -62,11 +62,8 @@ static ssize_t irq_show(struct device *d
> * For MSI, show the first MSI IRQ; for all other cases including
> * MSI-X, show the legacy INTx IRQ.
> */
> - if (pdev->msi_enabled) {
> - struct msi_desc *desc = first_pci_msi_entry(pdev);
> -
> - return sysfs_emit(buf, "%u\n", desc->irq);
> - }
> + if (pdev->msi_enabled)
> + return sysfs_emit(buf, "%u\n", pci_irq_vector(pdev, 0));
> #endif
>
> return sysfs_emit(buf, "%u\n", pdev->irq);
>
^ permalink raw reply
* Re: [patch V2 07/23] PCI/MSI: Remove msi_desc_to_pci_sysdata()
From: Bjorn Helgaas @ 2021-12-07 20:55 UTC (permalink / raw)
To: Thomas Gleixner
Cc: linux-hyperv, linux-mips, Paul Mackerras, sparclinux, Wei Liu,
Ashok Raj, x86, Christian Borntraeger, Megha Dey, Jason Gunthorpe,
linux-pci, xen-devel, ath11k, Kevin Tian, Heiko Carstens,
Alex Williamson, Cedric Le Goater, Kalle Valo, Juergen Gross,
Thomas Bogendoerfer, Greg Kroah-Hartman, LKML, Marc Zygnier,
linuxppc-dev
In-Reply-To: <20211206210224.210768199@linutronix.de>
On Mon, Dec 06, 2021 at 11:27:34PM +0100, Thomas Gleixner wrote:
> Last user is gone long ago.
>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> Tested-by: Juergen Gross <jgross@suse.com>
> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
> ---
> drivers/pci/msi.c | 8 --------
> include/linux/msi.h | 5 -----
> 2 files changed, 13 deletions(-)
>
> --- a/drivers/pci/msi.c
> +++ b/drivers/pci/msi.c
> @@ -1267,14 +1267,6 @@ struct pci_dev *msi_desc_to_pci_dev(stru
> }
> EXPORT_SYMBOL(msi_desc_to_pci_dev);
>
> -void *msi_desc_to_pci_sysdata(struct msi_desc *desc)
> -{
> - struct pci_dev *dev = msi_desc_to_pci_dev(desc);
> -
> - return dev->bus->sysdata;
> -}
> -EXPORT_SYMBOL_GPL(msi_desc_to_pci_sysdata);
> -
> #ifdef CONFIG_PCI_MSI_IRQ_DOMAIN
> /**
> * pci_msi_domain_write_msg - Helper to write MSI message to PCI config space
> --- a/include/linux/msi.h
> +++ b/include/linux/msi.h
> @@ -218,13 +218,8 @@ static inline void msi_desc_set_iommu_co
> for_each_msi_entry((desc), &(pdev)->dev)
>
> struct pci_dev *msi_desc_to_pci_dev(struct msi_desc *desc);
> -void *msi_desc_to_pci_sysdata(struct msi_desc *desc);
> void pci_write_msi_msg(unsigned int irq, struct msi_msg *msg);
> #else /* CONFIG_PCI_MSI */
> -static inline void *msi_desc_to_pci_sysdata(struct msi_desc *desc)
> -{
> - return NULL;
> -}
> static inline void pci_write_msi_msg(unsigned int irq, struct msi_msg *msg)
> {
> }
>
^ permalink raw reply
* Re: [patch V2 06/23] PCI/MSI: Make pci_msi_domain_write_msg() static
From: Bjorn Helgaas @ 2021-12-07 20:54 UTC (permalink / raw)
To: Thomas Gleixner
Cc: linux-hyperv, linux-mips, Paul Mackerras, sparclinux, Wei Liu,
Ashok Raj, x86, Christian Borntraeger, Megha Dey, Jason Gunthorpe,
linux-pci, xen-devel, ath11k, Kevin Tian, Heiko Carstens,
Alex Williamson, Cedric Le Goater, Kalle Valo, Juergen Gross,
Thomas Bogendoerfer, Greg Kroah-Hartman, LKML, Marc Zygnier,
linuxppc-dev
In-Reply-To: <20211206210224.157070464@linutronix.de>
On Mon, Dec 06, 2021 at 11:27:33PM +0100, Thomas Gleixner wrote:
> There is no point to have this function public as it is set by the PCI core
> anyway when a PCI/MSI irqdomain is created.
>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> Tested-by: Juergen Gross <jgross@suse.com>
> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Acked-by: Bjorn Helgaas <bhelgaas@google.com> # PCI
> ---
> drivers/irqchip/irq-gic-v2m.c | 1 -
> drivers/irqchip/irq-gic-v3-its-pci-msi.c | 1 -
> drivers/irqchip/irq-gic-v3-mbi.c | 1 -
> drivers/pci/msi.c | 2 +-
> include/linux/msi.h | 1 -
> 5 files changed, 1 insertion(+), 5 deletions(-)
>
> --- a/drivers/irqchip/irq-gic-v2m.c
> +++ b/drivers/irqchip/irq-gic-v2m.c
> @@ -88,7 +88,6 @@ static struct irq_chip gicv2m_msi_irq_ch
> .irq_mask = gicv2m_mask_msi_irq,
> .irq_unmask = gicv2m_unmask_msi_irq,
> .irq_eoi = irq_chip_eoi_parent,
> - .irq_write_msi_msg = pci_msi_domain_write_msg,
> };
>
> static struct msi_domain_info gicv2m_msi_domain_info = {
> --- a/drivers/irqchip/irq-gic-v3-its-pci-msi.c
> +++ b/drivers/irqchip/irq-gic-v3-its-pci-msi.c
> @@ -28,7 +28,6 @@ static struct irq_chip its_msi_irq_chip
> .irq_unmask = its_unmask_msi_irq,
> .irq_mask = its_mask_msi_irq,
> .irq_eoi = irq_chip_eoi_parent,
> - .irq_write_msi_msg = pci_msi_domain_write_msg,
> };
>
> static int its_pci_msi_vec_count(struct pci_dev *pdev, void *data)
> --- a/drivers/irqchip/irq-gic-v3-mbi.c
> +++ b/drivers/irqchip/irq-gic-v3-mbi.c
> @@ -171,7 +171,6 @@ static struct irq_chip mbi_msi_irq_chip
> .irq_unmask = mbi_unmask_msi_irq,
> .irq_eoi = irq_chip_eoi_parent,
> .irq_compose_msi_msg = mbi_compose_msi_msg,
> - .irq_write_msi_msg = pci_msi_domain_write_msg,
> };
>
> static struct msi_domain_info mbi_msi_domain_info = {
> --- a/drivers/pci/msi.c
> +++ b/drivers/pci/msi.c
> @@ -1281,7 +1281,7 @@ EXPORT_SYMBOL_GPL(msi_desc_to_pci_sysdat
> * @irq_data: Pointer to interrupt data of the MSI interrupt
> * @msg: Pointer to the message
> */
> -void pci_msi_domain_write_msg(struct irq_data *irq_data, struct msi_msg *msg)
> +static void pci_msi_domain_write_msg(struct irq_data *irq_data, struct msi_msg *msg)
> {
> struct msi_desc *desc = irq_data_get_msi_desc(irq_data);
>
> --- a/include/linux/msi.h
> +++ b/include/linux/msi.h
> @@ -455,7 +455,6 @@ void *platform_msi_get_host_data(struct
> #endif /* CONFIG_GENERIC_MSI_IRQ_DOMAIN */
>
> #ifdef CONFIG_PCI_MSI_IRQ_DOMAIN
> -void pci_msi_domain_write_msg(struct irq_data *irq_data, struct msi_msg *msg);
> struct irq_domain *pci_msi_create_irq_domain(struct fwnode_handle *fwnode,
> struct msi_domain_info *info,
> struct irq_domain *parent);
>
^ permalink raw reply
* Re: [patch V2 02/23] PCI/MSI: Fix pci_irq_vector()/pci_irq_get_affinity()
From: Bjorn Helgaas @ 2021-12-07 20:53 UTC (permalink / raw)
To: Thomas Gleixner
Cc: linux-hyperv, linux-mips, Paul Mackerras, sparclinux, Wei Liu,
Ashok Raj, x86, Christian Borntraeger, Megha Dey, Jason Gunthorpe,
linux-pci, xen-devel, ath11k, Kevin Tian, Heiko Carstens,
Alex Williamson, Cedric Le Goater, Kalle Valo, Juergen Gross,
Thomas Bogendoerfer, Greg Kroah-Hartman, LKML, Marc Zygnier,
linuxppc-dev
In-Reply-To: <20211206210223.929792157@linutronix.de>
On Mon, Dec 06, 2021 at 11:27:26PM +0100, Thomas Gleixner wrote:
> pci_irq_vector() and pci_irq_get_affinity() use the list position to find the
> MSI-X descriptor at a given index. That's correct for the normal case where
> the entry number is the same as the list position.
>
> But it's wrong for cases where MSI-X was allocated with an entries array
> describing sparse entry numbers into the hardware message descriptor
> table. That's inconsistent at best.
>
> Make it always check the entry number because that's what the zero base
> index really means. This change won't break existing users which use a
> sparse entries array for allocation because these users retrieve the Linux
> interrupt number from the entries array after allocation and none of them
> uses pci_irq_vector() or pci_irq_get_affinity().
>
> Fixes: aff171641d18 ("PCI: Provide sensible IRQ vector alloc/free routines")
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> Tested-by: Juergen Gross <jgross@suse.com>
> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
> ---
> V2: Fix typo in subject - Jason
> ---
> drivers/pci/msi.c | 26 ++++++++++++++++++--------
> 1 file changed, 18 insertions(+), 8 deletions(-)
>
> --- a/drivers/pci/msi.c
> +++ b/drivers/pci/msi.c
> @@ -1187,19 +1187,24 @@ EXPORT_SYMBOL(pci_free_irq_vectors);
>
> /**
> * pci_irq_vector - return Linux IRQ number of a device vector
> - * @dev: PCI device to operate on
> - * @nr: device-relative interrupt vector index (0-based).
> + * @dev: PCI device to operate on
> + * @nr: Interrupt vector index (0-based)
> + *
> + * @nr has the following meanings depending on the interrupt mode:
> + * MSI-X: The index in the MSI-X vector table
> + * MSI: The index of the enabled MSI vectors
> + * INTx: Must be 0
> + *
> + * Return: The Linux interrupt number or -EINVAl if @nr is out of range.
> */
> int pci_irq_vector(struct pci_dev *dev, unsigned int nr)
> {
> if (dev->msix_enabled) {
> struct msi_desc *entry;
> - int i = 0;
>
> for_each_pci_msi_entry(entry, dev) {
> - if (i == nr)
> + if (entry->msi_attrib.entry_nr == nr)
> return entry->irq;
> - i++;
> }
> WARN_ON_ONCE(1);
> return -EINVAL;
> @@ -1223,17 +1228,22 @@ EXPORT_SYMBOL(pci_irq_vector);
> * pci_irq_get_affinity - return the affinity of a particular MSI vector
> * @dev: PCI device to operate on
> * @nr: device-relative interrupt vector index (0-based).
> + *
> + * @nr has the following meanings depending on the interrupt mode:
> + * MSI-X: The index in the MSI-X vector table
> + * MSI: The index of the enabled MSI vectors
> + * INTx: Must be 0
> + *
> + * Return: A cpumask pointer or NULL if @nr is out of range
> */
> const struct cpumask *pci_irq_get_affinity(struct pci_dev *dev, int nr)
> {
> if (dev->msix_enabled) {
> struct msi_desc *entry;
> - int i = 0;
>
> for_each_pci_msi_entry(entry, dev) {
> - if (i == nr)
> + if (entry->msi_attrib.entry_nr == nr)
> return &entry->affinity->mask;
> - i++;
> }
> WARN_ON_ONCE(1);
> return NULL;
>
^ permalink raw reply
* Re: [patch V2 01/23] powerpc/4xx: Remove MSI support which never worked
From: Thomas Gleixner @ 2021-12-07 20:42 UTC (permalink / raw)
To: Cédric Le Goater, Michael Ellerman, LKML
Cc: linux-hyperv, Paul Mackerras, sparclinux, Wei Liu, Ashok Raj,
Marc Zygnier, x86, Christian Borntraeger, Bjorn Helgaas,
Megha Dey, Jason Gunthorpe, linux-pci, xen-devel, ath11k,
Kevin Tian, Heiko Carstens, Alex Williamson, Kalle Valo,
Juergen Gross, Thomas Bogendoerfer, Greg Kroah-Hartman,
linux-mips, linuxppc-dev
In-Reply-To: <27f22e0e-8f84-a6d7-704b-d9eddc642d74@kaod.org>
Cedric,
On Tue, Dec 07 2021 at 16:50, Cédric Le Goater wrote:
> On 12/7/21 12:36, Michael Ellerman wrote:
>>
>> This patch should drop those selects I guess. Can you send an
>> incremental diff for Thomas to squash in?
>
> Sure.
>
>> Removing all the tendrils in various device tree files will probably
>> require some archaeology, and it should be perfectly safe to leave those
>> in the tree with the driver gone. So I think we can do that as a
>> subsequent patch, rather than in this series.
>
> Here are the changes. Compiled tested with ppc40x and ppc44x defconfigs.
< Lots of patch skipped />
> @@ -141,7 +138,6 @@ config REDWOOD
> select FORCE_PCI
> select PPC4xx_PCI_EXPRESS
> select PCI_MSI
> - select PPC4xx_MSI
> help
> This option enables support for the AMCC PPC460SX Redwood board.
While that is incremental it certainly is worth a patch on it's
own. Could you add a proper changelog and an SOB please?
Thanks,
tglx
^ permalink raw reply
* Re: [PATCH] powerpc/603: Fix boot failure with DEBUG_PAGEALLOC and KFENCE
From: Christophe Leroy @ 2021-12-07 17:49 UTC (permalink / raw)
To: mbizon@freebox.fr, Michael Ellerman, Aneesh Kumar K.V
Cc: linuxppc-dev@lists.ozlabs.org, Paul Mackerras,
linux-kernel@vger.kernel.org, stable@vger.kernel.org
In-Reply-To: <12988dafdf7e14ba6db69ab483a2eb53e411fc0d.camel@freebox.fr>
Le 07/12/2021 à 11:34, Maxime Bizon a écrit :
>
> On Tue, 2021-12-07 at 06:10 +0000, Christophe Leroy wrote:
>
> Hello,
>
> With the patch applied and
>
> CONFIG_DEBUG_PAGEALLOC=y
> CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT=y
> CONFIG_DEBUG_VM=y
>
> I get tons of this during boot:
>
> [ 0.000000] Dentry cache hash table entries: 262144 (order: 8, 1048576 bytes, linear)
> [ 0.000000] Inode-cache hash table entries: 131072 (order: 7, 524288 bytes, linear)
> [ 0.000000] mem auto-init: stack:off, heap alloc:off, heap free:off
> [ 0.000000] ------------[ cut here ]------------
> [ 0.000000] WARNING: CPU: 0 PID: 0 at arch/powerpc/mm/pgtable.c:194 set_pte_at+0x18/0x160
> [ 0.000000] CPU: 0 PID: 0 Comm: swapper Not tainted 5.15.0+ #442
> [ 0.000000] NIP: 80015ebc LR: 80016728 CTR: 800166e4
> [ 0.000000] REGS: 80751dd0 TRAP: 0700 Not tainted (5.15.0+)
> [ 0.000000] MSR: 00021032 <ME,IR,DR,RI> CR: 42228882 XER: 20000000
> [ 0.000000]
> [ 0.000000] GPR00: 800b8dc8 80751e80 806c6300 807311d8 807a1000 8ffffe84 80751ea8 00000000
> [ 0.000000] GPR08: 007a1591 00000001 007a1180 00000000 42224882 00000000 3ff9c608 3fffd79c
> [ 0.000000] GPR16: 00000000 00000000 00000000 00000000 00000000 00000000 800166e4 807a2000
> [ 0.000000] GPR24: 807a1fff 807311d8 807311d8 807a2000 80768804 00000000 807a1000 007a1180
> [ 0.000000] NIP [80015ebc] set_pte_at+0x18/0x160
> [ 0.000000] LR [80016728] set_page_attr+0x44/0xc0
> [ 0.000000] Call Trace:
> [ 0.000000] [80751e80] [80058570] console_unlock+0x340/0x428 (unreliable)
> [ 0.000000] [80751ea0] [00000000] 0x0
> [ 0.000000] [80751ec0] [800b8dc8] __apply_to_page_range+0x144/0x2a8
> [ 0.000000] [80751f00] [80016918] __kernel_map_pages+0x54/0x64
> [ 0.000000] [80751f10] [800cfeb0] __free_pages_ok+0x1b0/0x440
> [ 0.000000] [80751f50] [805cfc8c] memblock_free_all+0x1d8/0x274
> [ 0.000000] [80751f90] [805c5e0c] mem_init+0x3c/0xd0
> [ 0.000000] [80751fb0] [805c0bdc] start_kernel+0x404/0x5c4
> [ 0.000000] [80751ff0] [000033f0] 0x33f0
> [ 0.000000] Instruction dump:
> [ 0.000000] 7c630034 83e1000c 5463d97e 7c0803a6 38210010 4e800020 9421ffe0 93e1001c
> [ 0.000000] 83e60000 81250000 71290001 41820014 <0fe00000> 7c0802a6 93c10018 90010024
>
>
That's unrelated to this patch.
The problem is linked to patch c988cfd38e48 ("powerpc/32: use
set_memory_attr()"), which changed from using __set_pte_at() to using
set_memory_attr() which uses set_pte_at().
set_pte_at() has additional checks and shall not be used to updating an
existing PTE.
Wondering if I should just use __set_pte_at() instead like in the past,
or do like commit 9f7853d7609d ("powerpc/mm: Fix set_memory_*() against
concurrent accesses") and use pte_update()
Michael, Aneesh, any suggestion ?
Thanks
Christophe
^ 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