mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-04 18:09:57 +00:00
* mpc85xx PCIe error interrupt support
* misc small enhancements/fixes all over the place. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.15 (GNU/Linux) iQIcBAABAgAGBQJS3PEWAAoJEBLB8Bhh3lVKziAP/3nNouipUvIcRpL3o8U3jX19 Z38tD0KPjIIX46rgexjoXbI/bKEy6whE1eDc0CG9GPpOaN9p9WWe81hfBIQc9DYK epFNdH3Wk83Ml+3+01CBKfLfiIV25c7rc9IOM7g+nMOg65Z++iC1Cea7i7Ul7T5a C+CIDdsmco9VrDBNjHHsrdYVZ1Ufx4NxPb5xhemQAiGCXseBtoD1IDS/gOM1F+aP UBDSJobjDrFq5JasEkp83U62VBTDndEcxb6yHROVahIPRn4miroc0NMHJ3XEd1/H K9u24iXmHgjjG3Euzd3mq8Axsscz8dUksKQT+lL2YIXz+AM8PcrCDrXK6TiVF9/A k5Vj91svnWUDrEU0OF1HysOvn0Z/9Y0+Fwyt6//HMyl/7ehCZBINwxsZ4sc4whtd nVHV2Ddcc/LjZzQEAvHuyWdf2pfxi3M1VRhNvuGyWtdHBPf5P8tqVUteoztELPM+ bKr7wkpvKzKajX6xldNNrVP9xNps8hrYdETjhP5FpUYpF4HKntAe+VJvIue+nOja K2AxB25qGHyK5rgh69DkSuatZmImflG4brKWbOE+4La0E8OajrM790YdqP2hRnDQ 3zpuIRr/htIAy7C2vGbmWITRhxXnGx5FhDI7AQRr1VjvgJprWM5zgIacDuH+5C9K ftouZ1hFTDI1WEEMDxRF =EJ+3 -----END PGP SIGNATURE----- Merge tag 'edac_for_3.14' of git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp Pull EDAC updates from Borislav Petkov: - mpc85xx PCIe error interrupt support - misc small enhancements/fixes all over the place. * tag 'edac_for_3.14' of git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp: EDAC: Don't try to cancel workqueue when it's never setup e752x_edac: Fix pci_dev usage count sb_edac: Mark get_mci_for_node_id as static EDAC: Mark edac_create_debug_nodes as static amd64_edac: Remove "amd64" prefix from static functions amd64_edac: Simplify code around decode_bus_error amd64_edac: Mark amd64_decode_bus_error as static EDAC: Remove DEFINE_PCI_DEVICE_TABLE macro amd64_edac: Fix condition to verify max channels allowed for F15 M30h edac/85xx: Add PCIe error interrupt edac support
This commit is contained in:
commit
09854dde94
22 changed files with 181 additions and 104 deletions
|
@ -1,7 +1,7 @@
|
|||
#include "amd64_edac.h"
|
||||
#include <asm/amd_nb.h>
|
||||
|
||||
static struct edac_pci_ctl_info *amd64_ctl_pci;
|
||||
static struct edac_pci_ctl_info *pci_ctl;
|
||||
|
||||
static int report_gart_errors;
|
||||
module_param(report_gart_errors, int, 0644);
|
||||
|
@ -162,7 +162,7 @@ static int f15_read_dct_pci_cfg(struct amd64_pvt *pvt, int addr, u32 *val,
|
|||
* scan the scrub rate mapping table for a close or matching bandwidth value to
|
||||
* issue. If requested is too big, then use last maximum value found.
|
||||
*/
|
||||
static int __amd64_set_scrub_rate(struct pci_dev *ctl, u32 new_bw, u32 min_rate)
|
||||
static int __set_scrub_rate(struct pci_dev *ctl, u32 new_bw, u32 min_rate)
|
||||
{
|
||||
u32 scrubval;
|
||||
int i;
|
||||
|
@ -198,7 +198,7 @@ static int __amd64_set_scrub_rate(struct pci_dev *ctl, u32 new_bw, u32 min_rate)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int amd64_set_scrub_rate(struct mem_ctl_info *mci, u32 bw)
|
||||
static int set_scrub_rate(struct mem_ctl_info *mci, u32 bw)
|
||||
{
|
||||
struct amd64_pvt *pvt = mci->pvt_info;
|
||||
u32 min_scrubrate = 0x5;
|
||||
|
@ -210,10 +210,10 @@ static int amd64_set_scrub_rate(struct mem_ctl_info *mci, u32 bw)
|
|||
if (pvt->fam == 0x15 && pvt->model < 0x10)
|
||||
f15h_select_dct(pvt, 0);
|
||||
|
||||
return __amd64_set_scrub_rate(pvt->F3, bw, min_scrubrate);
|
||||
return __set_scrub_rate(pvt->F3, bw, min_scrubrate);
|
||||
}
|
||||
|
||||
static int amd64_get_scrub_rate(struct mem_ctl_info *mci)
|
||||
static int get_scrub_rate(struct mem_ctl_info *mci)
|
||||
{
|
||||
struct amd64_pvt *pvt = mci->pvt_info;
|
||||
u32 scrubval = 0;
|
||||
|
@ -240,8 +240,7 @@ static int amd64_get_scrub_rate(struct mem_ctl_info *mci)
|
|||
* returns true if the SysAddr given by sys_addr matches the
|
||||
* DRAM base/limit associated with node_id
|
||||
*/
|
||||
static bool amd64_base_limit_match(struct amd64_pvt *pvt, u64 sys_addr,
|
||||
u8 nid)
|
||||
static bool base_limit_match(struct amd64_pvt *pvt, u64 sys_addr, u8 nid)
|
||||
{
|
||||
u64 addr;
|
||||
|
||||
|
@ -285,7 +284,7 @@ static struct mem_ctl_info *find_mc_by_sys_addr(struct mem_ctl_info *mci,
|
|||
|
||||
if (intlv_en == 0) {
|
||||
for (node_id = 0; node_id < DRAM_RANGES; node_id++) {
|
||||
if (amd64_base_limit_match(pvt, sys_addr, node_id))
|
||||
if (base_limit_match(pvt, sys_addr, node_id))
|
||||
goto found;
|
||||
}
|
||||
goto err_no_match;
|
||||
|
@ -309,7 +308,7 @@ static struct mem_ctl_info *find_mc_by_sys_addr(struct mem_ctl_info *mci,
|
|||
}
|
||||
|
||||
/* sanity test for sys_addr */
|
||||
if (unlikely(!amd64_base_limit_match(pvt, sys_addr, node_id))) {
|
||||
if (unlikely(!base_limit_match(pvt, sys_addr, node_id))) {
|
||||
amd64_warn("%s: sys_addr 0x%llx falls outside base/limit address"
|
||||
"range for node %d with node interleaving enabled.\n",
|
||||
__func__, sys_addr, node_id);
|
||||
|
@ -660,7 +659,7 @@ static int get_channel_from_ecc_syndrome(struct mem_ctl_info *, u16);
|
|||
* Determine if the DIMMs have ECC enabled. ECC is enabled ONLY if all the DIMMs
|
||||
* are ECC capable.
|
||||
*/
|
||||
static unsigned long amd64_determine_edac_cap(struct amd64_pvt *pvt)
|
||||
static unsigned long determine_edac_cap(struct amd64_pvt *pvt)
|
||||
{
|
||||
u8 bit;
|
||||
unsigned long edac_cap = EDAC_FLAG_NONE;
|
||||
|
@ -675,9 +674,9 @@ static unsigned long amd64_determine_edac_cap(struct amd64_pvt *pvt)
|
|||
return edac_cap;
|
||||
}
|
||||
|
||||
static void amd64_debug_display_dimm_sizes(struct amd64_pvt *, u8);
|
||||
static void debug_display_dimm_sizes(struct amd64_pvt *, u8);
|
||||
|
||||
static void amd64_dump_dramcfg_low(struct amd64_pvt *pvt, u32 dclr, int chan)
|
||||
static void debug_dump_dramcfg_low(struct amd64_pvt *pvt, u32 dclr, int chan)
|
||||
{
|
||||
edac_dbg(1, "F2x%d90 (DRAM Cfg Low): 0x%08x\n", chan, dclr);
|
||||
|
||||
|
@ -711,7 +710,7 @@ static void dump_misc_regs(struct amd64_pvt *pvt)
|
|||
(pvt->nbcap & NBCAP_SECDED) ? "yes" : "no",
|
||||
(pvt->nbcap & NBCAP_CHIPKILL) ? "yes" : "no");
|
||||
|
||||
amd64_dump_dramcfg_low(pvt, pvt->dclr0, 0);
|
||||
debug_dump_dramcfg_low(pvt, pvt->dclr0, 0);
|
||||
|
||||
edac_dbg(1, "F3xB0 (Online Spare): 0x%08x\n", pvt->online_spare);
|
||||
|
||||
|
@ -722,19 +721,19 @@ static void dump_misc_regs(struct amd64_pvt *pvt)
|
|||
|
||||
edac_dbg(1, " DramHoleValid: %s\n", dhar_valid(pvt) ? "yes" : "no");
|
||||
|
||||
amd64_debug_display_dimm_sizes(pvt, 0);
|
||||
debug_display_dimm_sizes(pvt, 0);
|
||||
|
||||
/* everything below this point is Fam10h and above */
|
||||
if (pvt->fam == 0xf)
|
||||
return;
|
||||
|
||||
amd64_debug_display_dimm_sizes(pvt, 1);
|
||||
debug_display_dimm_sizes(pvt, 1);
|
||||
|
||||
amd64_info("using %s syndromes.\n", ((pvt->ecc_sym_sz == 8) ? "x8" : "x4"));
|
||||
|
||||
/* Only if NOT ganged does dclr1 have valid info */
|
||||
if (!dct_ganging_enabled(pvt))
|
||||
amd64_dump_dramcfg_low(pvt, pvt->dclr1, 1);
|
||||
debug_dump_dramcfg_low(pvt, pvt->dclr1, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -800,7 +799,7 @@ static void read_dct_base_mask(struct amd64_pvt *pvt)
|
|||
}
|
||||
}
|
||||
|
||||
static enum mem_type amd64_determine_memory_type(struct amd64_pvt *pvt, int cs)
|
||||
static enum mem_type determine_memory_type(struct amd64_pvt *pvt, int cs)
|
||||
{
|
||||
enum mem_type type;
|
||||
|
||||
|
@ -1578,7 +1577,7 @@ static int f15_m30h_match_to_this_node(struct amd64_pvt *pvt, unsigned range,
|
|||
num_dcts_intlv, dct_sel);
|
||||
|
||||
/* Verify we stay within the MAX number of channels allowed */
|
||||
if (channel > 4 || channel < 0)
|
||||
if (channel > 3)
|
||||
return -EINVAL;
|
||||
|
||||
leg_mmio_hole = (u8) (dct_cont_base_reg >> 1 & BIT(0));
|
||||
|
@ -1702,7 +1701,7 @@ static void f1x_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
|
|||
* debug routine to display the memory sizes of all logical DIMMs and its
|
||||
* CSROWs
|
||||
*/
|
||||
static void amd64_debug_display_dimm_sizes(struct amd64_pvt *pvt, u8 ctrl)
|
||||
static void debug_display_dimm_sizes(struct amd64_pvt *pvt, u8 ctrl)
|
||||
{
|
||||
int dimm, size0, size1;
|
||||
u32 *dcsb = ctrl ? pvt->csels[1].csbases : pvt->csels[0].csbases;
|
||||
|
@ -1744,7 +1743,7 @@ static void amd64_debug_display_dimm_sizes(struct amd64_pvt *pvt, u8 ctrl)
|
|||
}
|
||||
}
|
||||
|
||||
static struct amd64_family_type amd64_family_types[] = {
|
||||
static struct amd64_family_type family_types[] = {
|
||||
[K8_CPUS] = {
|
||||
.ctl_name = "K8",
|
||||
.f1_id = PCI_DEVICE_ID_AMD_K8_NB_ADDRMAP,
|
||||
|
@ -2005,9 +2004,9 @@ static void __log_bus_error(struct mem_ctl_info *mci, struct err_info *err,
|
|||
string, "");
|
||||
}
|
||||
|
||||
static inline void __amd64_decode_bus_error(struct mem_ctl_info *mci,
|
||||
struct mce *m)
|
||||
static inline void decode_bus_error(int node_id, struct mce *m)
|
||||
{
|
||||
struct mem_ctl_info *mci = mcis[node_id];
|
||||
struct amd64_pvt *pvt = mci->pvt_info;
|
||||
u8 ecc_type = (m->status >> 45) & 0x3;
|
||||
u8 xec = XEC(m->status, 0x1f);
|
||||
|
@ -2035,11 +2034,6 @@ static inline void __amd64_decode_bus_error(struct mem_ctl_info *mci,
|
|||
__log_bus_error(mci, &err, ecc_type);
|
||||
}
|
||||
|
||||
void amd64_decode_bus_error(int node_id, struct mce *m)
|
||||
{
|
||||
__amd64_decode_bus_error(mcis[node_id], m);
|
||||
}
|
||||
|
||||
/*
|
||||
* Use pvt->F2 which contains the F2 CPU PCI device to get the related
|
||||
* F1 (AddrMap) and F3 (Misc) devices. Return negative value on error.
|
||||
|
@ -2196,7 +2190,7 @@ static void read_mc_regs(struct amd64_pvt *pvt)
|
|||
* encompasses
|
||||
*
|
||||
*/
|
||||
static u32 amd64_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr)
|
||||
static u32 get_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr)
|
||||
{
|
||||
u32 cs_mode, nr_pages;
|
||||
u32 dbam = dct ? pvt->dbam1 : pvt->dbam0;
|
||||
|
@ -2263,19 +2257,19 @@ static int init_csrows(struct mem_ctl_info *mci)
|
|||
pvt->mc_node_id, i);
|
||||
|
||||
if (row_dct0) {
|
||||
nr_pages = amd64_csrow_nr_pages(pvt, 0, i);
|
||||
nr_pages = get_csrow_nr_pages(pvt, 0, i);
|
||||
csrow->channels[0]->dimm->nr_pages = nr_pages;
|
||||
}
|
||||
|
||||
/* K8 has only one DCT */
|
||||
if (pvt->fam != 0xf && row_dct1) {
|
||||
int row_dct1_pages = amd64_csrow_nr_pages(pvt, 1, i);
|
||||
int row_dct1_pages = get_csrow_nr_pages(pvt, 1, i);
|
||||
|
||||
csrow->channels[1]->dimm->nr_pages = row_dct1_pages;
|
||||
nr_pages += row_dct1_pages;
|
||||
}
|
||||
|
||||
mtype = amd64_determine_memory_type(pvt, i);
|
||||
mtype = determine_memory_type(pvt, i);
|
||||
|
||||
edac_dbg(1, "Total csrow%d pages: %u\n", i, nr_pages);
|
||||
|
||||
|
@ -2309,7 +2303,7 @@ static void get_cpus_on_this_dct_cpumask(struct cpumask *mask, u16 nid)
|
|||
}
|
||||
|
||||
/* check MCG_CTL on all the cpus on this node */
|
||||
static bool amd64_nb_mce_bank_enabled_on_node(u16 nid)
|
||||
static bool nb_mce_bank_enabled_on_node(u16 nid)
|
||||
{
|
||||
cpumask_var_t mask;
|
||||
int cpu, nbe;
|
||||
|
@ -2482,7 +2476,7 @@ static bool ecc_enabled(struct pci_dev *F3, u16 nid)
|
|||
ecc_en = !!(value & NBCFG_ECC_ENABLE);
|
||||
amd64_info("DRAM ECC %s.\n", (ecc_en ? "enabled" : "disabled"));
|
||||
|
||||
nb_mce_en = amd64_nb_mce_bank_enabled_on_node(nid);
|
||||
nb_mce_en = nb_mce_bank_enabled_on_node(nid);
|
||||
if (!nb_mce_en)
|
||||
amd64_notice("NB MCE bank disabled, set MSR "
|
||||
"0x%08x[4] on node %d to enable.\n",
|
||||
|
@ -2537,7 +2531,7 @@ static void setup_mci_misc_attrs(struct mem_ctl_info *mci,
|
|||
if (pvt->nbcap & NBCAP_CHIPKILL)
|
||||
mci->edac_ctl_cap |= EDAC_FLAG_S4ECD4ED;
|
||||
|
||||
mci->edac_cap = amd64_determine_edac_cap(pvt);
|
||||
mci->edac_cap = determine_edac_cap(pvt);
|
||||
mci->mod_name = EDAC_MOD_STR;
|
||||
mci->mod_ver = EDAC_AMD64_VERSION;
|
||||
mci->ctl_name = fam->ctl_name;
|
||||
|
@ -2545,14 +2539,14 @@ static void setup_mci_misc_attrs(struct mem_ctl_info *mci,
|
|||
mci->ctl_page_to_phys = NULL;
|
||||
|
||||
/* memory scrubber interface */
|
||||
mci->set_sdram_scrub_rate = amd64_set_scrub_rate;
|
||||
mci->get_sdram_scrub_rate = amd64_get_scrub_rate;
|
||||
mci->set_sdram_scrub_rate = set_scrub_rate;
|
||||
mci->get_sdram_scrub_rate = get_scrub_rate;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns a pointer to the family descriptor on success, NULL otherwise.
|
||||
*/
|
||||
static struct amd64_family_type *amd64_per_family_init(struct amd64_pvt *pvt)
|
||||
static struct amd64_family_type *per_family_init(struct amd64_pvt *pvt)
|
||||
{
|
||||
struct amd64_family_type *fam_type = NULL;
|
||||
|
||||
|
@ -2563,29 +2557,29 @@ static struct amd64_family_type *amd64_per_family_init(struct amd64_pvt *pvt)
|
|||
|
||||
switch (pvt->fam) {
|
||||
case 0xf:
|
||||
fam_type = &amd64_family_types[K8_CPUS];
|
||||
pvt->ops = &amd64_family_types[K8_CPUS].ops;
|
||||
fam_type = &family_types[K8_CPUS];
|
||||
pvt->ops = &family_types[K8_CPUS].ops;
|
||||
break;
|
||||
|
||||
case 0x10:
|
||||
fam_type = &amd64_family_types[F10_CPUS];
|
||||
pvt->ops = &amd64_family_types[F10_CPUS].ops;
|
||||
fam_type = &family_types[F10_CPUS];
|
||||
pvt->ops = &family_types[F10_CPUS].ops;
|
||||
break;
|
||||
|
||||
case 0x15:
|
||||
if (pvt->model == 0x30) {
|
||||
fam_type = &amd64_family_types[F15_M30H_CPUS];
|
||||
pvt->ops = &amd64_family_types[F15_M30H_CPUS].ops;
|
||||
fam_type = &family_types[F15_M30H_CPUS];
|
||||
pvt->ops = &family_types[F15_M30H_CPUS].ops;
|
||||
break;
|
||||
}
|
||||
|
||||
fam_type = &amd64_family_types[F15_CPUS];
|
||||
pvt->ops = &amd64_family_types[F15_CPUS].ops;
|
||||
fam_type = &family_types[F15_CPUS];
|
||||
pvt->ops = &family_types[F15_CPUS].ops;
|
||||
break;
|
||||
|
||||
case 0x16:
|
||||
fam_type = &amd64_family_types[F16_CPUS];
|
||||
pvt->ops = &amd64_family_types[F16_CPUS].ops;
|
||||
fam_type = &family_types[F16_CPUS];
|
||||
pvt->ops = &family_types[F16_CPUS].ops;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -2601,7 +2595,7 @@ static struct amd64_family_type *amd64_per_family_init(struct amd64_pvt *pvt)
|
|||
return fam_type;
|
||||
}
|
||||
|
||||
static int amd64_init_one_instance(struct pci_dev *F2)
|
||||
static int init_one_instance(struct pci_dev *F2)
|
||||
{
|
||||
struct amd64_pvt *pvt = NULL;
|
||||
struct amd64_family_type *fam_type = NULL;
|
||||
|
@ -2619,7 +2613,7 @@ static int amd64_init_one_instance(struct pci_dev *F2)
|
|||
pvt->F2 = F2;
|
||||
|
||||
ret = -EINVAL;
|
||||
fam_type = amd64_per_family_init(pvt);
|
||||
fam_type = per_family_init(pvt);
|
||||
if (!fam_type)
|
||||
goto err_free;
|
||||
|
||||
|
@ -2680,7 +2674,7 @@ static int amd64_init_one_instance(struct pci_dev *F2)
|
|||
if (report_gart_errors)
|
||||
amd_report_gart_errors(true);
|
||||
|
||||
amd_register_ecc_decoder(amd64_decode_bus_error);
|
||||
amd_register_ecc_decoder(decode_bus_error);
|
||||
|
||||
mcis[nid] = mci;
|
||||
|
||||
|
@ -2703,8 +2697,8 @@ static int amd64_init_one_instance(struct pci_dev *F2)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int amd64_probe_one_instance(struct pci_dev *pdev,
|
||||
const struct pci_device_id *mc_type)
|
||||
static int probe_one_instance(struct pci_dev *pdev,
|
||||
const struct pci_device_id *mc_type)
|
||||
{
|
||||
u16 nid = amd_get_node_id(pdev);
|
||||
struct pci_dev *F3 = node_to_amd_nb(nid)->misc;
|
||||
|
@ -2736,7 +2730,7 @@ static int amd64_probe_one_instance(struct pci_dev *pdev,
|
|||
goto err_enable;
|
||||
}
|
||||
|
||||
ret = amd64_init_one_instance(pdev);
|
||||
ret = init_one_instance(pdev);
|
||||
if (ret < 0) {
|
||||
amd64_err("Error probing instance: %d\n", nid);
|
||||
restore_ecc_error_reporting(s, nid, F3);
|
||||
|
@ -2752,7 +2746,7 @@ static int amd64_probe_one_instance(struct pci_dev *pdev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void amd64_remove_one_instance(struct pci_dev *pdev)
|
||||
static void remove_one_instance(struct pci_dev *pdev)
|
||||
{
|
||||
struct mem_ctl_info *mci;
|
||||
struct amd64_pvt *pvt;
|
||||
|
@ -2777,7 +2771,7 @@ static void amd64_remove_one_instance(struct pci_dev *pdev)
|
|||
|
||||
/* unregister from EDAC MCE */
|
||||
amd_report_gart_errors(false);
|
||||
amd_unregister_ecc_decoder(amd64_decode_bus_error);
|
||||
amd_unregister_ecc_decoder(decode_bus_error);
|
||||
|
||||
kfree(ecc_stngs[nid]);
|
||||
ecc_stngs[nid] = NULL;
|
||||
|
@ -2795,7 +2789,7 @@ static void amd64_remove_one_instance(struct pci_dev *pdev)
|
|||
* PCI core identifies what devices are on a system during boot, and then
|
||||
* inquiry this table to see if this driver is for a given device found.
|
||||
*/
|
||||
static DEFINE_PCI_DEVICE_TABLE(amd64_pci_table) = {
|
||||
static const struct pci_device_id amd64_pci_table[] = {
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_AMD,
|
||||
.device = PCI_DEVICE_ID_AMD_K8_NB_MEMCTL,
|
||||
|
@ -2843,8 +2837,8 @@ MODULE_DEVICE_TABLE(pci, amd64_pci_table);
|
|||
|
||||
static struct pci_driver amd64_pci_driver = {
|
||||
.name = EDAC_MOD_STR,
|
||||
.probe = amd64_probe_one_instance,
|
||||
.remove = amd64_remove_one_instance,
|
||||
.probe = probe_one_instance,
|
||||
.remove = remove_one_instance,
|
||||
.id_table = amd64_pci_table,
|
||||
};
|
||||
|
||||
|
@ -2853,23 +2847,18 @@ static void setup_pci_device(void)
|
|||
struct mem_ctl_info *mci;
|
||||
struct amd64_pvt *pvt;
|
||||
|
||||
if (amd64_ctl_pci)
|
||||
if (pci_ctl)
|
||||
return;
|
||||
|
||||
mci = mcis[0];
|
||||
if (mci) {
|
||||
if (!mci)
|
||||
return;
|
||||
|
||||
pvt = mci->pvt_info;
|
||||
amd64_ctl_pci =
|
||||
edac_pci_create_generic_ctl(&pvt->F2->dev, EDAC_MOD_STR);
|
||||
|
||||
if (!amd64_ctl_pci) {
|
||||
pr_warning("%s(): Unable to create PCI control\n",
|
||||
__func__);
|
||||
|
||||
pr_warning("%s(): PCI error report via EDAC not set\n",
|
||||
__func__);
|
||||
}
|
||||
pvt = mci->pvt_info;
|
||||
pci_ctl = edac_pci_create_generic_ctl(&pvt->F2->dev, EDAC_MOD_STR);
|
||||
if (!pci_ctl) {
|
||||
pr_warn("%s(): Unable to create PCI control\n", __func__);
|
||||
pr_warn("%s(): PCI error report via EDAC not set\n", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2925,8 +2914,8 @@ static int __init amd64_edac_init(void)
|
|||
|
||||
static void __exit amd64_edac_exit(void)
|
||||
{
|
||||
if (amd64_ctl_pci)
|
||||
edac_pci_release_generic_ctl(amd64_ctl_pci);
|
||||
if (pci_ctl)
|
||||
edac_pci_release_generic_ctl(pci_ctl);
|
||||
|
||||
pci_unregister_driver(&amd64_pci_driver);
|
||||
|
||||
|
|
|
@ -333,7 +333,7 @@ static void amd76x_remove_one(struct pci_dev *pdev)
|
|||
edac_mc_free(mci);
|
||||
}
|
||||
|
||||
static DEFINE_PCI_DEVICE_TABLE(amd76x_pci_tbl) = {
|
||||
static const struct pci_device_id amd76x_pci_tbl[] = {
|
||||
{
|
||||
PCI_VEND_DEV(AMD, FE_GATE_700C), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||||
AMD762},
|
||||
|
|
|
@ -1182,9 +1182,11 @@ static int e752x_get_devs(struct pci_dev *pdev, int dev_idx,
|
|||
pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL,
|
||||
pvt->dev_info->err_dev, pvt->bridge_ck);
|
||||
|
||||
if (pvt->bridge_ck == NULL)
|
||||
if (pvt->bridge_ck == NULL) {
|
||||
pvt->bridge_ck = pci_scan_single_device(pdev->bus,
|
||||
PCI_DEVFN(0, 1));
|
||||
pci_dev_get(pvt->bridge_ck);
|
||||
}
|
||||
|
||||
if (pvt->bridge_ck == NULL) {
|
||||
e752x_printk(KERN_ERR, "error reporting device not found:"
|
||||
|
@ -1421,7 +1423,7 @@ static void e752x_remove_one(struct pci_dev *pdev)
|
|||
edac_mc_free(mci);
|
||||
}
|
||||
|
||||
static DEFINE_PCI_DEVICE_TABLE(e752x_pci_tbl) = {
|
||||
static const struct pci_device_id e752x_pci_tbl[] = {
|
||||
{
|
||||
PCI_VEND_DEV(INTEL, 7520_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||||
E7520},
|
||||
|
|
|
@ -555,7 +555,7 @@ static void e7xxx_remove_one(struct pci_dev *pdev)
|
|||
edac_mc_free(mci);
|
||||
}
|
||||
|
||||
static DEFINE_PCI_DEVICE_TABLE(e7xxx_pci_tbl) = {
|
||||
static const struct pci_device_id e7xxx_pci_tbl[] = {
|
||||
{
|
||||
PCI_VEND_DEV(INTEL, 7205_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||||
E7205},
|
||||
|
|
|
@ -437,6 +437,9 @@ void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev)
|
|||
{
|
||||
int status;
|
||||
|
||||
if (!edac_dev->edac_check)
|
||||
return;
|
||||
|
||||
status = cancel_delayed_work(&edac_dev->work);
|
||||
if (status == 0) {
|
||||
/* workq instance might be running, wait for it */
|
||||
|
|
|
@ -914,7 +914,7 @@ void __exit edac_debugfs_exit(void)
|
|||
debugfs_remove(edac_debugfs);
|
||||
}
|
||||
|
||||
int edac_create_debug_nodes(struct mem_ctl_info *mci)
|
||||
static int edac_create_debug_nodes(struct mem_ctl_info *mci)
|
||||
{
|
||||
struct dentry *d, *parent;
|
||||
char name[80];
|
||||
|
|
|
@ -487,7 +487,7 @@ static void i3000_remove_one(struct pci_dev *pdev)
|
|||
edac_mc_free(mci);
|
||||
}
|
||||
|
||||
static DEFINE_PCI_DEVICE_TABLE(i3000_pci_tbl) = {
|
||||
static const struct pci_device_id i3000_pci_tbl[] = {
|
||||
{
|
||||
PCI_VEND_DEV(INTEL, 3000_HB), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||||
I3000},
|
||||
|
|
|
@ -466,7 +466,7 @@ static void i3200_remove_one(struct pci_dev *pdev)
|
|||
edac_mc_free(mci);
|
||||
}
|
||||
|
||||
static DEFINE_PCI_DEVICE_TABLE(i3200_pci_tbl) = {
|
||||
static const struct pci_device_id i3200_pci_tbl[] = {
|
||||
{
|
||||
PCI_VEND_DEV(INTEL, 3200_HB), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||||
I3200},
|
||||
|
|
|
@ -1530,7 +1530,7 @@ static void i5000_remove_one(struct pci_dev *pdev)
|
|||
*
|
||||
* The "E500P" device is the first device supported.
|
||||
*/
|
||||
static DEFINE_PCI_DEVICE_TABLE(i5000_pci_tbl) = {
|
||||
static const struct pci_device_id i5000_pci_tbl[] = {
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I5000_DEV16),
|
||||
.driver_data = I5000P},
|
||||
|
||||
|
|
|
@ -1213,7 +1213,7 @@ static void i5100_remove_one(struct pci_dev *pdev)
|
|||
edac_mc_free(mci);
|
||||
}
|
||||
|
||||
static DEFINE_PCI_DEVICE_TABLE(i5100_pci_tbl) = {
|
||||
static const struct pci_device_id i5100_pci_tbl[] = {
|
||||
/* Device 16, Function 0, Channel 0 Memory Map, Error Flag/Mask, ... */
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5100_16) },
|
||||
{ 0, }
|
||||
|
|
|
@ -1416,7 +1416,7 @@ static void i5400_remove_one(struct pci_dev *pdev)
|
|||
*
|
||||
* The "E500P" device is the first device supported.
|
||||
*/
|
||||
static DEFINE_PCI_DEVICE_TABLE(i5400_pci_tbl) = {
|
||||
static const struct pci_device_id i5400_pci_tbl[] = {
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5400_ERR)},
|
||||
{0,} /* 0 terminated list. */
|
||||
};
|
||||
|
|
|
@ -1160,7 +1160,7 @@ static void i7300_remove_one(struct pci_dev *pdev)
|
|||
*
|
||||
* Has only 8086:360c PCI ID
|
||||
*/
|
||||
static DEFINE_PCI_DEVICE_TABLE(i7300_pci_tbl) = {
|
||||
static const struct pci_device_id i7300_pci_tbl[] = {
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7300_MCH_ERR)},
|
||||
{0,} /* 0 terminated list. */
|
||||
};
|
||||
|
|
|
@ -394,7 +394,7 @@ static const struct pci_id_table pci_dev_table[] = {
|
|||
/*
|
||||
* pci_device_id table for which devices we are looking for
|
||||
*/
|
||||
static DEFINE_PCI_DEVICE_TABLE(i7core_pci_tbl) = {
|
||||
static const struct pci_device_id i7core_pci_tbl[] = {
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_X58_HUB_MGMT)},
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNNFIELD_QPI_LINK0)},
|
||||
{0,} /* 0 terminated list. */
|
||||
|
|
|
@ -386,7 +386,7 @@ static void i82443bxgx_edacmc_remove_one(struct pci_dev *pdev)
|
|||
|
||||
EXPORT_SYMBOL_GPL(i82443bxgx_edacmc_remove_one);
|
||||
|
||||
static DEFINE_PCI_DEVICE_TABLE(i82443bxgx_pci_tbl) = {
|
||||
static const struct pci_device_id i82443bxgx_pci_tbl[] = {
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_0)},
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_2)},
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443GX_0)},
|
||||
|
|
|
@ -288,7 +288,7 @@ static void i82860_remove_one(struct pci_dev *pdev)
|
|||
edac_mc_free(mci);
|
||||
}
|
||||
|
||||
static DEFINE_PCI_DEVICE_TABLE(i82860_pci_tbl) = {
|
||||
static const struct pci_device_id i82860_pci_tbl[] = {
|
||||
{
|
||||
PCI_VEND_DEV(INTEL, 82860_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||||
I82860},
|
||||
|
|
|
@ -527,7 +527,7 @@ static void i82875p_remove_one(struct pci_dev *pdev)
|
|||
edac_mc_free(mci);
|
||||
}
|
||||
|
||||
static DEFINE_PCI_DEVICE_TABLE(i82875p_pci_tbl) = {
|
||||
static const struct pci_device_id i82875p_pci_tbl[] = {
|
||||
{
|
||||
PCI_VEND_DEV(INTEL, 82875_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||||
I82875P},
|
||||
|
|
|
@ -628,7 +628,7 @@ static void i82975x_remove_one(struct pci_dev *pdev)
|
|||
edac_mc_free(mci);
|
||||
}
|
||||
|
||||
static DEFINE_PCI_DEVICE_TABLE(i82975x_pci_tbl) = {
|
||||
static const struct pci_device_id i82975x_pci_tbl[] = {
|
||||
{
|
||||
PCI_VEND_DEV(INTEL, 82975_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||||
I82975X
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
/*
|
||||
* Freescale MPC85xx Memory Controller kenel module
|
||||
*
|
||||
* Parts Copyrighted (c) 2013 by Freescale Semiconductor, Inc.
|
||||
*
|
||||
* Author: Dave Jiang <djiang@mvista.com>
|
||||
*
|
||||
* 2006-2007 (c) MontaVista Software, Inc. This file is licensed under
|
||||
|
@ -196,6 +198,42 @@ static void mpc85xx_pci_check(struct edac_pci_ctl_info *pci)
|
|||
edac_pci_handle_npe(pci, pci->ctl_name);
|
||||
}
|
||||
|
||||
static void mpc85xx_pcie_check(struct edac_pci_ctl_info *pci)
|
||||
{
|
||||
struct mpc85xx_pci_pdata *pdata = pci->pvt_info;
|
||||
u32 err_detect;
|
||||
|
||||
err_detect = in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR);
|
||||
|
||||
pr_err("PCIe error(s) detected\n");
|
||||
pr_err("PCIe ERR_DR register: 0x%08x\n", err_detect);
|
||||
pr_err("PCIe ERR_CAP_STAT register: 0x%08x\n",
|
||||
in_be32(pdata->pci_vbase + MPC85XX_PCI_GAS_TIMR));
|
||||
pr_err("PCIe ERR_CAP_R0 register: 0x%08x\n",
|
||||
in_be32(pdata->pci_vbase + MPC85XX_PCIE_ERR_CAP_R0));
|
||||
pr_err("PCIe ERR_CAP_R1 register: 0x%08x\n",
|
||||
in_be32(pdata->pci_vbase + MPC85XX_PCIE_ERR_CAP_R1));
|
||||
pr_err("PCIe ERR_CAP_R2 register: 0x%08x\n",
|
||||
in_be32(pdata->pci_vbase + MPC85XX_PCIE_ERR_CAP_R2));
|
||||
pr_err("PCIe ERR_CAP_R3 register: 0x%08x\n",
|
||||
in_be32(pdata->pci_vbase + MPC85XX_PCIE_ERR_CAP_R3));
|
||||
|
||||
/* clear error bits */
|
||||
out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR, err_detect);
|
||||
}
|
||||
|
||||
static int mpc85xx_pcie_find_capability(struct device_node *np)
|
||||
{
|
||||
struct pci_controller *hose;
|
||||
|
||||
if (!np)
|
||||
return -EINVAL;
|
||||
|
||||
hose = pci_find_hose_for_OF_device(np);
|
||||
|
||||
return early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP);
|
||||
}
|
||||
|
||||
static irqreturn_t mpc85xx_pci_isr(int irq, void *dev_id)
|
||||
{
|
||||
struct edac_pci_ctl_info *pci = dev_id;
|
||||
|
@ -207,7 +245,10 @@ static irqreturn_t mpc85xx_pci_isr(int irq, void *dev_id)
|
|||
if (!err_detect)
|
||||
return IRQ_NONE;
|
||||
|
||||
mpc85xx_pci_check(pci);
|
||||
if (pdata->is_pcie)
|
||||
mpc85xx_pcie_check(pci);
|
||||
else
|
||||
mpc85xx_pci_check(pci);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -239,14 +280,22 @@ int mpc85xx_pci_err_probe(struct platform_device *op)
|
|||
pdata = pci->pvt_info;
|
||||
pdata->name = "mpc85xx_pci_err";
|
||||
pdata->irq = NO_IRQ;
|
||||
|
||||
if (mpc85xx_pcie_find_capability(op->dev.of_node) > 0)
|
||||
pdata->is_pcie = true;
|
||||
|
||||
dev_set_drvdata(&op->dev, pci);
|
||||
pci->dev = &op->dev;
|
||||
pci->mod_name = EDAC_MOD_STR;
|
||||
pci->ctl_name = pdata->name;
|
||||
pci->dev_name = dev_name(&op->dev);
|
||||
|
||||
if (edac_op_state == EDAC_OPSTATE_POLL)
|
||||
pci->edac_check = mpc85xx_pci_check;
|
||||
if (edac_op_state == EDAC_OPSTATE_POLL) {
|
||||
if (pdata->is_pcie)
|
||||
pci->edac_check = mpc85xx_pcie_check;
|
||||
else
|
||||
pci->edac_check = mpc85xx_pci_check;
|
||||
}
|
||||
|
||||
pdata->edac_idx = edac_pci_idx++;
|
||||
|
||||
|
@ -275,16 +324,26 @@ int mpc85xx_pci_err_probe(struct platform_device *op)
|
|||
goto err;
|
||||
}
|
||||
|
||||
orig_pci_err_cap_dr =
|
||||
in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_CAP_DR);
|
||||
if (pdata->is_pcie) {
|
||||
orig_pci_err_cap_dr =
|
||||
in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_ADDR);
|
||||
out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_ADDR, ~0);
|
||||
orig_pci_err_en =
|
||||
in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN);
|
||||
out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN, 0);
|
||||
} else {
|
||||
orig_pci_err_cap_dr =
|
||||
in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_CAP_DR);
|
||||
|
||||
/* PCI master abort is expected during config cycles */
|
||||
out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_CAP_DR, 0x40);
|
||||
/* PCI master abort is expected during config cycles */
|
||||
out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_CAP_DR, 0x40);
|
||||
|
||||
orig_pci_err_en = in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN);
|
||||
orig_pci_err_en =
|
||||
in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN);
|
||||
|
||||
/* disable master abort reporting */
|
||||
out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN, ~0x40);
|
||||
/* disable master abort reporting */
|
||||
out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN, ~0x40);
|
||||
}
|
||||
|
||||
/* clear error bits */
|
||||
out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR, ~0);
|
||||
|
@ -297,7 +356,8 @@ int mpc85xx_pci_err_probe(struct platform_device *op)
|
|||
if (edac_op_state == EDAC_OPSTATE_INT) {
|
||||
pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0);
|
||||
res = devm_request_irq(&op->dev, pdata->irq,
|
||||
mpc85xx_pci_isr, IRQF_DISABLED,
|
||||
mpc85xx_pci_isr,
|
||||
IRQF_DISABLED | IRQF_SHARED,
|
||||
"[EDAC] PCI err", pci);
|
||||
if (res < 0) {
|
||||
printk(KERN_ERR
|
||||
|
@ -312,6 +372,22 @@ int mpc85xx_pci_err_probe(struct platform_device *op)
|
|||
pdata->irq);
|
||||
}
|
||||
|
||||
if (pdata->is_pcie) {
|
||||
/*
|
||||
* Enable all PCIe error interrupt & error detect except invalid
|
||||
* PEX_CONFIG_ADDR/PEX_CONFIG_DATA access interrupt generation
|
||||
* enable bit and invalid PEX_CONFIG_ADDR/PEX_CONFIG_DATA access
|
||||
* detection enable bit. Because PCIe bus code to initialize and
|
||||
* configure these PCIe devices on booting will use some invalid
|
||||
* PEX_CONFIG_ADDR/PEX_CONFIG_DATA, edac driver prints the much
|
||||
* notice information. So disable this detect to fix ugly print.
|
||||
*/
|
||||
out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN, ~0
|
||||
& ~PEX_ERR_ICCAIE_EN_BIT);
|
||||
out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_ADDR, 0
|
||||
| PEX_ERR_ICCAD_DISR_BIT);
|
||||
}
|
||||
|
||||
devres_remove_group(&op->dev, mpc85xx_pci_err_probe);
|
||||
edac_dbg(3, "success\n");
|
||||
printk(KERN_INFO EDAC_MOD_STR " PCI err registered\n");
|
||||
|
|
|
@ -134,13 +134,19 @@
|
|||
#define MPC85XX_PCI_ERR_DR 0x0000
|
||||
#define MPC85XX_PCI_ERR_CAP_DR 0x0004
|
||||
#define MPC85XX_PCI_ERR_EN 0x0008
|
||||
#define PEX_ERR_ICCAIE_EN_BIT 0x00020000
|
||||
#define MPC85XX_PCI_ERR_ATTRIB 0x000c
|
||||
#define MPC85XX_PCI_ERR_ADDR 0x0010
|
||||
#define PEX_ERR_ICCAD_DISR_BIT 0x00020000
|
||||
#define MPC85XX_PCI_ERR_EXT_ADDR 0x0014
|
||||
#define MPC85XX_PCI_ERR_DL 0x0018
|
||||
#define MPC85XX_PCI_ERR_DH 0x001c
|
||||
#define MPC85XX_PCI_GAS_TIMR 0x0020
|
||||
#define MPC85XX_PCI_PCIX_TIMR 0x0024
|
||||
#define MPC85XX_PCIE_ERR_CAP_R0 0x0028
|
||||
#define MPC85XX_PCIE_ERR_CAP_R1 0x002c
|
||||
#define MPC85XX_PCIE_ERR_CAP_R2 0x0030
|
||||
#define MPC85XX_PCIE_ERR_CAP_R3 0x0034
|
||||
|
||||
struct mpc85xx_mc_pdata {
|
||||
char *name;
|
||||
|
@ -158,6 +164,7 @@ struct mpc85xx_l2_pdata {
|
|||
|
||||
struct mpc85xx_pci_pdata {
|
||||
char *name;
|
||||
bool is_pcie;
|
||||
int edac_idx;
|
||||
void __iomem *pci_vbase;
|
||||
int irq;
|
||||
|
|
|
@ -383,7 +383,7 @@ static void r82600_remove_one(struct pci_dev *pdev)
|
|||
edac_mc_free(mci);
|
||||
}
|
||||
|
||||
static DEFINE_PCI_DEVICE_TABLE(r82600_pci_tbl) = {
|
||||
static const struct pci_device_id r82600_pci_tbl[] = {
|
||||
{
|
||||
PCI_DEVICE(PCI_VENDOR_ID_RADISYS, R82600_BRIDGE_ID)
|
||||
},
|
||||
|
|
|
@ -461,7 +461,7 @@ static const struct pci_id_table pci_dev_descr_ibridge_table[] = {
|
|||
/*
|
||||
* pci_device_id table for which devices we are looking for
|
||||
*/
|
||||
static DEFINE_PCI_DEVICE_TABLE(sbridge_pci_tbl) = {
|
||||
static const struct pci_device_id sbridge_pci_tbl[] = {
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA)},
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA)},
|
||||
{0,} /* 0 terminated list. */
|
||||
|
@ -915,7 +915,7 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
|
|||
}
|
||||
}
|
||||
|
||||
struct mem_ctl_info *get_mci_for_node_id(u8 node_id)
|
||||
static struct mem_ctl_info *get_mci_for_node_id(u8 node_id)
|
||||
{
|
||||
struct sbridge_dev *sbridge_dev;
|
||||
|
||||
|
|
|
@ -448,7 +448,7 @@ static void x38_remove_one(struct pci_dev *pdev)
|
|||
edac_mc_free(mci);
|
||||
}
|
||||
|
||||
static DEFINE_PCI_DEVICE_TABLE(x38_pci_tbl) = {
|
||||
static const struct pci_device_id x38_pci_tbl[] = {
|
||||
{
|
||||
PCI_VEND_DEV(INTEL, X38_HB), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||||
X38},
|
||||
|
|
Loading…
Reference in a new issue