^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Driver for Pondicherry2 memory controller.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (c) 2016, Intel Corporation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * [Derived from sb_edac.c]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Translation of system physical addresses to DIMM addresses
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * is a two stage process:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * First the Pondicherry 2 memory controller handles slice and channel interleaving
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * in "sys2pmi()". This is (almost) completley common between platforms.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * Then a platform specific dunit (DIMM unit) completes the process to provide DIMM,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * rank, bank, row and column using the appropriate "dunit_ops" functions/parameters.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/pci.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/pci_ids.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/edac.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/mmzone.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/smp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/bitmap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/math64.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <linux/mod_devicetable.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <asm/cpu_device_id.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <asm/intel-family.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include <asm/processor.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #include <asm/mce.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #include "edac_mc.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #include "edac_module.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #include "pnd2_edac.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define EDAC_MOD_STR "pnd2_edac"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #define APL_NUM_CHANNELS 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define DNV_NUM_CHANNELS 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #define DNV_MAX_DIMMS 2 /* Max DIMMs per channel */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) enum type {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) APL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) DNV, /* All requests go to PMI CH0 on each slice (CH1 disabled) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) struct dram_addr {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) int chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) int dimm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) int rank;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) int bank;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) int row;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) int col;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) struct pnd2_pvt {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) int dimm_geom[APL_NUM_CHANNELS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) u64 tolm, tohm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) * System address space is divided into multiple regions with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) * different interleave rules in each. The as0/as1 regions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) * have no interleaving at all. The as2 region is interleaved
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) * between two channels. The mot region is magic and may overlap
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) * other regions, with its interleave rules taking precedence.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) * Addresses not in any of these regions are interleaved across
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * all four channels.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) static struct region {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) u64 base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) u64 limit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) u8 enabled;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) } mot, as0, as1, as2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) static struct dunit_ops {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) enum type type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) int pmiaddr_shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) int pmiidx_shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) int channels;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) int dimms_per_channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) int (*rd_reg)(int port, int off, int op, void *data, size_t sz, char *name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) int (*get_registers)(void);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) int (*check_ecc)(void);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) void (*mk_region)(char *name, struct region *rp, void *asym);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) void (*get_dimm_config)(struct mem_ctl_info *mci);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) int (*pmi2mem)(struct mem_ctl_info *mci, u64 pmiaddr, u32 pmiidx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) struct dram_addr *daddr, char *msg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) } *ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) static struct mem_ctl_info *pnd2_mci;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) #define PND2_MSG_SIZE 256
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) /* Debug macros */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) #define pnd2_printk(level, fmt, arg...) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) edac_printk(level, "pnd2", fmt, ##arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) #define pnd2_mc_printk(mci, level, fmt, arg...) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) edac_mc_chipset_printk(mci, level, "pnd2", fmt, ##arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) #define MOT_CHAN_INTLV_BIT_1SLC_2CH 12
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) #define MOT_CHAN_INTLV_BIT_2SLC_2CH 13
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) #define SELECTOR_DISABLED (-1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) #define _4GB (1ul << 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) #define PMI_ADDRESS_WIDTH 31
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) #define PND_MAX_PHYS_BIT 39
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) #define APL_ASYMSHIFT 28
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) #define DNV_ASYMSHIFT 31
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) #define CH_HASH_MASK_LSB 6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) #define SLICE_HASH_MASK_LSB 6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) #define MOT_SLC_INTLV_BIT 12
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) #define LOG2_PMI_ADDR_GRANULARITY 5
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) #define MOT_SHIFT 24
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) #define GET_BITFIELD(v, lo, hi) (((v) & GENMASK_ULL(hi, lo)) >> (lo))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) #define U64_LSHIFT(val, s) ((u64)(val) << (s))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) * On Apollo Lake we access memory controller registers via a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) * side-band mailbox style interface in a hidden PCI device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) * configuration space.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) static struct pci_bus *p2sb_bus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) #define P2SB_DEVFN PCI_DEVFN(0xd, 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) #define P2SB_ADDR_OFF 0xd0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) #define P2SB_DATA_OFF 0xd4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) #define P2SB_STAT_OFF 0xd8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) #define P2SB_ROUT_OFF 0xda
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) #define P2SB_EADD_OFF 0xdc
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) #define P2SB_HIDE_OFF 0xe1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) #define P2SB_BUSY 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) #define P2SB_READ(size, off, ptr) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) pci_bus_read_config_##size(p2sb_bus, P2SB_DEVFN, off, ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) #define P2SB_WRITE(size, off, val) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) pci_bus_write_config_##size(p2sb_bus, P2SB_DEVFN, off, val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) static bool p2sb_is_busy(u16 *status)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) P2SB_READ(word, P2SB_STAT_OFF, status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) return !!(*status & P2SB_BUSY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) static int _apl_rd_reg(int port, int off, int op, u32 *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) int retries = 0xff, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) u16 status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) u8 hidden;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) /* Unhide the P2SB device, if it's hidden */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) P2SB_READ(byte, P2SB_HIDE_OFF, &hidden);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) if (hidden)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) P2SB_WRITE(byte, P2SB_HIDE_OFF, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) if (p2sb_is_busy(&status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) ret = -EAGAIN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) P2SB_WRITE(dword, P2SB_ADDR_OFF, (port << 24) | off);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) P2SB_WRITE(dword, P2SB_DATA_OFF, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) P2SB_WRITE(dword, P2SB_EADD_OFF, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) P2SB_WRITE(word, P2SB_ROUT_OFF, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) P2SB_WRITE(word, P2SB_STAT_OFF, (op << 8) | P2SB_BUSY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) while (p2sb_is_busy(&status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) if (retries-- == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) ret = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) P2SB_READ(dword, P2SB_DATA_OFF, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) ret = (status >> 1) & 0x3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) /* Hide the P2SB device, if it was hidden before */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) if (hidden)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) P2SB_WRITE(byte, P2SB_HIDE_OFF, hidden);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) static int apl_rd_reg(int port, int off, int op, void *data, size_t sz, char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) edac_dbg(2, "Read %s port=%x off=%x op=%x\n", name, port, off, op);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) switch (sz) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) case 8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) ret = _apl_rd_reg(port, off + 4, op, (u32 *)(data + 4));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) fallthrough;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) case 4:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) ret |= _apl_rd_reg(port, off, op, (u32 *)data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) pnd2_printk(KERN_DEBUG, "%s=%x%08x ret=%d\n", name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) sz == 8 ? *((u32 *)(data + 4)) : 0, *((u32 *)data), ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) static u64 get_mem_ctrl_hub_base_addr(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) struct b_cr_mchbar_lo_pci lo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) struct b_cr_mchbar_hi_pci hi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) struct pci_dev *pdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x1980, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) if (pdev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) pci_read_config_dword(pdev, 0x48, (u32 *)&lo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) pci_read_config_dword(pdev, 0x4c, (u32 *)&hi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) pci_dev_put(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) if (!lo.enable) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) edac_dbg(2, "MMIO via memory controller hub base address is disabled!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) return U64_LSHIFT(hi.base, 32) | U64_LSHIFT(lo.base, 15);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) static u64 get_sideband_reg_base_addr(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) struct pci_dev *pdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) u32 hi, lo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) u8 hidden;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x19dd, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) if (pdev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) /* Unhide the P2SB device, if it's hidden */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) pci_read_config_byte(pdev, 0xe1, &hidden);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) if (hidden)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) pci_write_config_byte(pdev, 0xe1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) pci_read_config_dword(pdev, 0x10, &lo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) pci_read_config_dword(pdev, 0x14, &hi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) lo &= 0xfffffff0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) /* Hide the P2SB device, if it was hidden before */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) if (hidden)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) pci_write_config_byte(pdev, 0xe1, hidden);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) pci_dev_put(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) return (U64_LSHIFT(hi, 32) | U64_LSHIFT(lo, 0));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) return 0xfd000000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) #define DNV_MCHBAR_SIZE 0x8000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) #define DNV_SB_PORT_SIZE 0x10000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) static int dnv_rd_reg(int port, int off, int op, void *data, size_t sz, char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) struct pci_dev *pdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) char *base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) u64 addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) unsigned long size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) if (op == 4) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x1980, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) if (!pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) pci_read_config_dword(pdev, off, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) pci_dev_put(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) /* MMIO via memory controller hub base address */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) if (op == 0 && port == 0x4c) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) addr = get_mem_ctrl_hub_base_addr();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) if (!addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) size = DNV_MCHBAR_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) /* MMIO via sideband register base address */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) addr = get_sideband_reg_base_addr();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) if (!addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) addr += (port << 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) size = DNV_SB_PORT_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) base = ioremap((resource_size_t)addr, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) if (!base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) if (sz == 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) *(u32 *)(data + 4) = *(u32 *)(base + off + 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) *(u32 *)data = *(u32 *)(base + off);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) iounmap(base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) edac_dbg(2, "Read %s=%.8x_%.8x\n", name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) (sz == 8) ? *(u32 *)(data + 4) : 0, *(u32 *)data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) #define RD_REGP(regp, regname, port) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) ops->rd_reg(port, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) regname##_offset, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) regname##_r_opcode, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) regp, sizeof(struct regname), \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) #regname)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) #define RD_REG(regp, regname) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) ops->rd_reg(regname ## _port, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) regname##_offset, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) regname##_r_opcode, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) regp, sizeof(struct regname), \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) #regname)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) static u64 top_lm, top_hm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) static bool two_slices;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) static bool two_channels; /* Both PMI channels in one slice enabled */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) static u8 sym_chan_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) static u8 asym_chan_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) static u8 chan_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) static int slice_selector = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) static int chan_selector = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) static u64 slice_hash_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) static u64 chan_hash_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) static void mk_region(char *name, struct region *rp, u64 base, u64 limit)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) rp->enabled = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) rp->base = base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) rp->limit = limit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) edac_dbg(2, "Region:%s [%llx, %llx]\n", name, base, limit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) static void mk_region_mask(char *name, struct region *rp, u64 base, u64 mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) if (mask == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) pr_info(FW_BUG "MOT mask cannot be zero\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) if (mask != GENMASK_ULL(PND_MAX_PHYS_BIT, __ffs(mask))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) pr_info(FW_BUG "MOT mask not power of two\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) if (base & ~mask) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) pr_info(FW_BUG "MOT region base/mask alignment error\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) rp->base = base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) rp->limit = (base | ~mask) & GENMASK_ULL(PND_MAX_PHYS_BIT, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) rp->enabled = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) edac_dbg(2, "Region:%s [%llx, %llx]\n", name, base, rp->limit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) static bool in_region(struct region *rp, u64 addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) if (!rp->enabled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) return rp->base <= addr && addr <= rp->limit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) static int gen_sym_mask(struct b_cr_slice_channel_hash *p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) int mask = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) if (!p->slice_0_mem_disabled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) mask |= p->sym_slice0_channel_enabled;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) if (!p->slice_1_disabled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) mask |= p->sym_slice1_channel_enabled << 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) if (p->ch_1_disabled || p->enable_pmi_dual_data_mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) mask &= 0x5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) return mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) static int gen_asym_mask(struct b_cr_slice_channel_hash *p,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) struct b_cr_asym_mem_region0_mchbar *as0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) struct b_cr_asym_mem_region1_mchbar *as1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) struct b_cr_asym_2way_mem_region_mchbar *as2way)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) const int intlv[] = { 0x5, 0xA, 0x3, 0xC };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) int mask = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) if (as2way->asym_2way_interleave_enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) mask = intlv[as2way->asym_2way_intlv_mode];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) if (as0->slice0_asym_enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) mask |= (1 << as0->slice0_asym_channel_select);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) if (as1->slice1_asym_enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) mask |= (4 << as1->slice1_asym_channel_select);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) if (p->slice_0_mem_disabled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) mask &= 0xc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) if (p->slice_1_disabled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) mask &= 0x3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) if (p->ch_1_disabled || p->enable_pmi_dual_data_mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) mask &= 0x5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) return mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) static struct b_cr_tolud_pci tolud;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) static struct b_cr_touud_lo_pci touud_lo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) static struct b_cr_touud_hi_pci touud_hi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) static struct b_cr_asym_mem_region0_mchbar asym0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) static struct b_cr_asym_mem_region1_mchbar asym1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) static struct b_cr_asym_2way_mem_region_mchbar asym_2way;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) static struct b_cr_mot_out_base_mchbar mot_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) static struct b_cr_mot_out_mask_mchbar mot_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) static struct b_cr_slice_channel_hash chash;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) /* Apollo Lake dunit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) * Validated on board with just two DIMMs in the [0] and [2] positions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) * in this array. Other port number matches documentation, but caution
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) * advised.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) static const int apl_dports[APL_NUM_CHANNELS] = { 0x18, 0x10, 0x11, 0x19 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) static struct d_cr_drp0 drp0[APL_NUM_CHANNELS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) /* Denverton dunit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) static const int dnv_dports[DNV_NUM_CHANNELS] = { 0x10, 0x12 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) static struct d_cr_dsch dsch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) static struct d_cr_ecc_ctrl ecc_ctrl[DNV_NUM_CHANNELS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) static struct d_cr_drp drp[DNV_NUM_CHANNELS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) static struct d_cr_dmap dmap[DNV_NUM_CHANNELS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) static struct d_cr_dmap1 dmap1[DNV_NUM_CHANNELS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) static struct d_cr_dmap2 dmap2[DNV_NUM_CHANNELS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) static struct d_cr_dmap3 dmap3[DNV_NUM_CHANNELS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) static struct d_cr_dmap4 dmap4[DNV_NUM_CHANNELS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) static struct d_cr_dmap5 dmap5[DNV_NUM_CHANNELS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) static void apl_mk_region(char *name, struct region *rp, void *asym)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) struct b_cr_asym_mem_region0_mchbar *a = asym;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) mk_region(name, rp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) U64_LSHIFT(a->slice0_asym_base, APL_ASYMSHIFT),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) U64_LSHIFT(a->slice0_asym_limit, APL_ASYMSHIFT) +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) GENMASK_ULL(APL_ASYMSHIFT - 1, 0));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) static void dnv_mk_region(char *name, struct region *rp, void *asym)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) struct b_cr_asym_mem_region_denverton *a = asym;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) mk_region(name, rp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) U64_LSHIFT(a->slice_asym_base, DNV_ASYMSHIFT),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) U64_LSHIFT(a->slice_asym_limit, DNV_ASYMSHIFT) +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) GENMASK_ULL(DNV_ASYMSHIFT - 1, 0));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) static int apl_get_registers(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) int ret = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) if (RD_REG(&asym_2way, b_cr_asym_2way_mem_region_mchbar))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) * RD_REGP() will fail for unpopulated or non-existent
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) * DIMM slots. Return success if we find at least one DIMM.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) for (i = 0; i < APL_NUM_CHANNELS; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) if (!RD_REGP(&drp0[i], d_cr_drp0, apl_dports[i]))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) static int dnv_get_registers(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) if (RD_REG(&dsch, d_cr_dsch))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) for (i = 0; i < DNV_NUM_CHANNELS; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) if (RD_REGP(&ecc_ctrl[i], d_cr_ecc_ctrl, dnv_dports[i]) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) RD_REGP(&drp[i], d_cr_drp, dnv_dports[i]) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) RD_REGP(&dmap[i], d_cr_dmap, dnv_dports[i]) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) RD_REGP(&dmap1[i], d_cr_dmap1, dnv_dports[i]) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) RD_REGP(&dmap2[i], d_cr_dmap2, dnv_dports[i]) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) RD_REGP(&dmap3[i], d_cr_dmap3, dnv_dports[i]) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) RD_REGP(&dmap4[i], d_cr_dmap4, dnv_dports[i]) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) RD_REGP(&dmap5[i], d_cr_dmap5, dnv_dports[i]))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) * Read all the h/w config registers once here (they don't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) * change at run time. Figure out which address ranges have
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) * which interleave characteristics.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) static int get_registers(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) const int intlv[] = { 10, 11, 12, 12 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) if (RD_REG(&tolud, b_cr_tolud_pci) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) RD_REG(&touud_lo, b_cr_touud_lo_pci) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) RD_REG(&touud_hi, b_cr_touud_hi_pci) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) RD_REG(&asym0, b_cr_asym_mem_region0_mchbar) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) RD_REG(&asym1, b_cr_asym_mem_region1_mchbar) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) RD_REG(&mot_base, b_cr_mot_out_base_mchbar) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) RD_REG(&mot_mask, b_cr_mot_out_mask_mchbar) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) RD_REG(&chash, b_cr_slice_channel_hash))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) if (ops->get_registers())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) if (ops->type == DNV) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) /* PMI channel idx (always 0) for asymmetric region */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) asym0.slice0_asym_channel_select = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) asym1.slice1_asym_channel_select = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) /* PMI channel bitmap (always 1) for symmetric region */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) chash.sym_slice0_channel_enabled = 0x1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) chash.sym_slice1_channel_enabled = 0x1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) if (asym0.slice0_asym_enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) ops->mk_region("as0", &as0, &asym0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) if (asym1.slice1_asym_enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) ops->mk_region("as1", &as1, &asym1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) if (asym_2way.asym_2way_interleave_enable) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) mk_region("as2way", &as2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) U64_LSHIFT(asym_2way.asym_2way_base, APL_ASYMSHIFT),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) U64_LSHIFT(asym_2way.asym_2way_limit, APL_ASYMSHIFT) +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) GENMASK_ULL(APL_ASYMSHIFT - 1, 0));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) if (mot_base.imr_en) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) mk_region_mask("mot", &mot,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) U64_LSHIFT(mot_base.mot_out_base, MOT_SHIFT),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) U64_LSHIFT(mot_mask.mot_out_mask, MOT_SHIFT));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) top_lm = U64_LSHIFT(tolud.tolud, 20);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) top_hm = U64_LSHIFT(touud_hi.touud, 32) | U64_LSHIFT(touud_lo.touud, 20);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) two_slices = !chash.slice_1_disabled &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) !chash.slice_0_mem_disabled &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) (chash.sym_slice0_channel_enabled != 0) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) (chash.sym_slice1_channel_enabled != 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) two_channels = !chash.ch_1_disabled &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) !chash.enable_pmi_dual_data_mode &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) ((chash.sym_slice0_channel_enabled == 3) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) (chash.sym_slice1_channel_enabled == 3));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) sym_chan_mask = gen_sym_mask(&chash);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) asym_chan_mask = gen_asym_mask(&chash, &asym0, &asym1, &asym_2way);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) chan_mask = sym_chan_mask | asym_chan_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) if (two_slices && !two_channels) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) if (chash.hvm_mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) slice_selector = 29;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) slice_selector = intlv[chash.interleave_mode];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) } else if (!two_slices && two_channels) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) if (chash.hvm_mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) chan_selector = 29;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) chan_selector = intlv[chash.interleave_mode];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) } else if (two_slices && two_channels) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) if (chash.hvm_mode) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) slice_selector = 29;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) chan_selector = 30;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) slice_selector = intlv[chash.interleave_mode];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) chan_selector = intlv[chash.interleave_mode] + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) if (two_slices) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) if (!chash.hvm_mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) slice_hash_mask = chash.slice_hash_mask << SLICE_HASH_MASK_LSB;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) if (!two_channels)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) slice_hash_mask |= BIT_ULL(slice_selector);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) if (two_channels) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) if (!chash.hvm_mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) chan_hash_mask = chash.ch_hash_mask << CH_HASH_MASK_LSB;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) if (!two_slices)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) chan_hash_mask |= BIT_ULL(chan_selector);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) /* Get a contiguous memory address (remove the MMIO gap) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) static u64 remove_mmio_gap(u64 sys)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) return (sys < _4GB) ? sys : sys - (_4GB - top_lm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) /* Squeeze out one address bit, shift upper part down to fill gap */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) static void remove_addr_bit(u64 *addr, int bitidx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) u64 mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) if (bitidx == -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) mask = (1ull << bitidx) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) *addr = ((*addr >> 1) & ~mask) | (*addr & mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) /* XOR all the bits from addr specified in mask */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) static int hash_by_mask(u64 addr, u64 mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) u64 result = addr & mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) result = (result >> 32) ^ result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) result = (result >> 16) ^ result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) result = (result >> 8) ^ result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) result = (result >> 4) ^ result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) result = (result >> 2) ^ result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) result = (result >> 1) ^ result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) return (int)result & 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) * First stage decode. Take the system address and figure out which
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) * second stage will deal with it based on interleave modes.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) static int sys2pmi(const u64 addr, u32 *pmiidx, u64 *pmiaddr, char *msg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) u64 contig_addr, contig_base, contig_offset, contig_base_adj;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) int mot_intlv_bit = two_slices ? MOT_CHAN_INTLV_BIT_2SLC_2CH :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) MOT_CHAN_INTLV_BIT_1SLC_2CH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) int slice_intlv_bit_rm = SELECTOR_DISABLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) int chan_intlv_bit_rm = SELECTOR_DISABLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) /* Determine if address is in the MOT region. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) bool mot_hit = in_region(&mot, addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) /* Calculate the number of symmetric regions enabled. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) int sym_channels = hweight8(sym_chan_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) * The amount we need to shift the asym base can be determined by the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) * number of enabled symmetric channels.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) * NOTE: This can only work because symmetric memory is not supposed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) * to do a 3-way interleave.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) int sym_chan_shift = sym_channels >> 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) /* Give up if address is out of range, or in MMIO gap */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) if (addr >= (1ul << PND_MAX_PHYS_BIT) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) (addr >= top_lm && addr < _4GB) || addr >= top_hm) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) snprintf(msg, PND2_MSG_SIZE, "Error address 0x%llx is not DRAM", addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) /* Get a contiguous memory address (remove the MMIO gap) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) contig_addr = remove_mmio_gap(addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) if (in_region(&as0, addr)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) *pmiidx = asym0.slice0_asym_channel_select;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) contig_base = remove_mmio_gap(as0.base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) contig_offset = contig_addr - contig_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) contig_base_adj = (contig_base >> sym_chan_shift) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) ((chash.sym_slice0_channel_enabled >> (*pmiidx & 1)) & 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) contig_addr = contig_offset + ((sym_channels > 0) ? contig_base_adj : 0ull);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) } else if (in_region(&as1, addr)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) *pmiidx = 2u + asym1.slice1_asym_channel_select;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) contig_base = remove_mmio_gap(as1.base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) contig_offset = contig_addr - contig_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) contig_base_adj = (contig_base >> sym_chan_shift) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) ((chash.sym_slice1_channel_enabled >> (*pmiidx & 1)) & 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) contig_addr = contig_offset + ((sym_channels > 0) ? contig_base_adj : 0ull);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) } else if (in_region(&as2, addr) && (asym_2way.asym_2way_intlv_mode == 0x3ul)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) bool channel1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) mot_intlv_bit = MOT_CHAN_INTLV_BIT_1SLC_2CH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) *pmiidx = (asym_2way.asym_2way_intlv_mode & 1) << 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) channel1 = mot_hit ? ((bool)((addr >> mot_intlv_bit) & 1)) :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) hash_by_mask(contig_addr, chan_hash_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) *pmiidx |= (u32)channel1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) contig_base = remove_mmio_gap(as2.base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) chan_intlv_bit_rm = mot_hit ? mot_intlv_bit : chan_selector;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) contig_offset = contig_addr - contig_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) remove_addr_bit(&contig_offset, chan_intlv_bit_rm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) contig_addr = (contig_base >> sym_chan_shift) + contig_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) /* Otherwise we're in normal, boring symmetric mode. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) *pmiidx = 0u;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) if (two_slices) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) bool slice1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) if (mot_hit) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) slice_intlv_bit_rm = MOT_SLC_INTLV_BIT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) slice1 = (addr >> MOT_SLC_INTLV_BIT) & 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) slice_intlv_bit_rm = slice_selector;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) slice1 = hash_by_mask(addr, slice_hash_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) *pmiidx = (u32)slice1 << 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) if (two_channels) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) bool channel1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) mot_intlv_bit = two_slices ? MOT_CHAN_INTLV_BIT_2SLC_2CH :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) MOT_CHAN_INTLV_BIT_1SLC_2CH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) if (mot_hit) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) chan_intlv_bit_rm = mot_intlv_bit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) channel1 = (addr >> mot_intlv_bit) & 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) chan_intlv_bit_rm = chan_selector;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) channel1 = hash_by_mask(contig_addr, chan_hash_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) *pmiidx |= (u32)channel1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) /* Remove the chan_selector bit first */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) remove_addr_bit(&contig_addr, chan_intlv_bit_rm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) /* Remove the slice bit (we remove it second because it must be lower */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) remove_addr_bit(&contig_addr, slice_intlv_bit_rm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) *pmiaddr = contig_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) /* Translate PMI address to memory (rank, row, bank, column) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) #define C(n) (0x10 | (n)) /* column */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) #define B(n) (0x20 | (n)) /* bank */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) #define R(n) (0x40 | (n)) /* row */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) #define RS (0x80) /* rank */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) /* addrdec values */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) #define AMAP_1KB 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) #define AMAP_2KB 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) #define AMAP_4KB 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) #define AMAP_RSVD 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) /* dden values */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) #define DEN_4Gb 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) #define DEN_8Gb 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) /* dwid values */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) #define X8 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) #define X16 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) static struct dimm_geometry {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) u8 addrdec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) u8 dden;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) u8 dwid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) u8 rowbits, colbits;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) u16 bits[PMI_ADDRESS_WIDTH];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) } dimms[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) .addrdec = AMAP_1KB, .dden = DEN_4Gb, .dwid = X16,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) .rowbits = 15, .colbits = 10,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) .bits = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) C(2), C(3), C(4), C(5), C(6), B(0), B(1), B(2), R(0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) R(1), R(2), R(3), R(4), R(5), R(6), R(7), R(8), R(9),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) R(10), C(7), C(8), C(9), R(11), RS, R(12), R(13), R(14),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) 0, 0, 0, 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) .addrdec = AMAP_1KB, .dden = DEN_4Gb, .dwid = X8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) .rowbits = 16, .colbits = 10,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) .bits = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) C(2), C(3), C(4), C(5), C(6), B(0), B(1), B(2), R(0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) R(1), R(2), R(3), R(4), R(5), R(6), R(7), R(8), R(9),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) R(10), C(7), C(8), C(9), R(11), RS, R(12), R(13), R(14),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) R(15), 0, 0, 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) .addrdec = AMAP_1KB, .dden = DEN_8Gb, .dwid = X16,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) .rowbits = 16, .colbits = 10,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) .bits = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) C(2), C(3), C(4), C(5), C(6), B(0), B(1), B(2), R(0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) R(1), R(2), R(3), R(4), R(5), R(6), R(7), R(8), R(9),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) R(10), C(7), C(8), C(9), R(11), RS, R(12), R(13), R(14),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) R(15), 0, 0, 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) .addrdec = AMAP_1KB, .dden = DEN_8Gb, .dwid = X8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) .rowbits = 16, .colbits = 11,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) .bits = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) C(2), C(3), C(4), C(5), C(6), B(0), B(1), B(2), R(0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) R(1), R(2), R(3), R(4), R(5), R(6), R(7), R(8), R(9),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) R(10), C(7), C(8), C(9), R(11), RS, C(11), R(12), R(13),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) R(14), R(15), 0, 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) .addrdec = AMAP_2KB, .dden = DEN_4Gb, .dwid = X16,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) .rowbits = 15, .colbits = 10,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) .bits = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) C(2), C(3), C(4), C(5), C(6), C(7), B(0), B(1), B(2),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) R(0), R(1), R(2), R(3), R(4), R(5), R(6), R(7), R(8),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) R(9), R(10), C(8), C(9), R(11), RS, R(12), R(13), R(14),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) 0, 0, 0, 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) .addrdec = AMAP_2KB, .dden = DEN_4Gb, .dwid = X8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) .rowbits = 16, .colbits = 10,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) .bits = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) C(2), C(3), C(4), C(5), C(6), C(7), B(0), B(1), B(2),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) R(0), R(1), R(2), R(3), R(4), R(5), R(6), R(7), R(8),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) R(9), R(10), C(8), C(9), R(11), RS, R(12), R(13), R(14),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) R(15), 0, 0, 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) .addrdec = AMAP_2KB, .dden = DEN_8Gb, .dwid = X16,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) .rowbits = 16, .colbits = 10,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) .bits = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) C(2), C(3), C(4), C(5), C(6), C(7), B(0), B(1), B(2),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) R(0), R(1), R(2), R(3), R(4), R(5), R(6), R(7), R(8),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) R(9), R(10), C(8), C(9), R(11), RS, R(12), R(13), R(14),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) R(15), 0, 0, 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) .addrdec = AMAP_2KB, .dden = DEN_8Gb, .dwid = X8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) .rowbits = 16, .colbits = 11,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) .bits = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) C(2), C(3), C(4), C(5), C(6), C(7), B(0), B(1), B(2),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) R(0), R(1), R(2), R(3), R(4), R(5), R(6), R(7), R(8),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) R(9), R(10), C(8), C(9), R(11), RS, C(11), R(12), R(13),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) R(14), R(15), 0, 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) .addrdec = AMAP_4KB, .dden = DEN_4Gb, .dwid = X16,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) .rowbits = 15, .colbits = 10,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) .bits = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) C(2), C(3), C(4), C(5), C(6), C(7), C(8), B(0), B(1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) B(2), R(0), R(1), R(2), R(3), R(4), R(5), R(6), R(7),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) R(8), R(9), R(10), C(9), R(11), RS, R(12), R(13), R(14),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) 0, 0, 0, 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) .addrdec = AMAP_4KB, .dden = DEN_4Gb, .dwid = X8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) .rowbits = 16, .colbits = 10,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) .bits = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) C(2), C(3), C(4), C(5), C(6), C(7), C(8), B(0), B(1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) B(2), R(0), R(1), R(2), R(3), R(4), R(5), R(6), R(7),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) R(8), R(9), R(10), C(9), R(11), RS, R(12), R(13), R(14),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) R(15), 0, 0, 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) .addrdec = AMAP_4KB, .dden = DEN_8Gb, .dwid = X16,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) .rowbits = 16, .colbits = 10,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) .bits = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) C(2), C(3), C(4), C(5), C(6), C(7), C(8), B(0), B(1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) B(2), R(0), R(1), R(2), R(3), R(4), R(5), R(6), R(7),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) R(8), R(9), R(10), C(9), R(11), RS, R(12), R(13), R(14),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) R(15), 0, 0, 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) .addrdec = AMAP_4KB, .dden = DEN_8Gb, .dwid = X8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) .rowbits = 16, .colbits = 11,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) .bits = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) C(2), C(3), C(4), C(5), C(6), C(7), C(8), B(0), B(1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) B(2), R(0), R(1), R(2), R(3), R(4), R(5), R(6), R(7),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) R(8), R(9), R(10), C(9), R(11), RS, C(11), R(12), R(13),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) R(14), R(15), 0, 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) static int bank_hash(u64 pmiaddr, int idx, int shft)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) int bhash = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) switch (idx) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) case 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) bhash ^= ((pmiaddr >> (12 + shft)) ^ (pmiaddr >> (9 + shft))) & 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) bhash ^= (((pmiaddr >> (10 + shft)) ^ (pmiaddr >> (8 + shft))) & 1) << 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) bhash ^= ((pmiaddr >> 22) & 1) << 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) case 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) bhash ^= (((pmiaddr >> (13 + shft)) ^ (pmiaddr >> (11 + shft))) & 1) << 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) return bhash;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) static int rank_hash(u64 pmiaddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) return ((pmiaddr >> 16) ^ (pmiaddr >> 10)) & 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) /* Second stage decode. Compute rank, bank, row & column. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) static int apl_pmi2mem(struct mem_ctl_info *mci, u64 pmiaddr, u32 pmiidx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) struct dram_addr *daddr, char *msg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) struct d_cr_drp0 *cr_drp0 = &drp0[pmiidx];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) struct pnd2_pvt *pvt = mci->pvt_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) int g = pvt->dimm_geom[pmiidx];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) struct dimm_geometry *d = &dimms[g];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) int column = 0, bank = 0, row = 0, rank = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) int i, idx, type, skiprs = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) for (i = 0; i < PMI_ADDRESS_WIDTH; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) int bit = (pmiaddr >> i) & 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) if (i + skiprs >= PMI_ADDRESS_WIDTH) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) snprintf(msg, PND2_MSG_SIZE, "Bad dimm_geometry[] table\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) type = d->bits[i + skiprs] & ~0xf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) idx = d->bits[i + skiprs] & 0xf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) * On single rank DIMMs ignore the rank select bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) * and shift remainder of "bits[]" down one place.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) if (type == RS && (cr_drp0->rken0 + cr_drp0->rken1) == 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) skiprs = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) type = d->bits[i + skiprs] & ~0xf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) idx = d->bits[i + skiprs] & 0xf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) switch (type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) case C(0):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) column |= (bit << idx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) case B(0):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) bank |= (bit << idx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) if (cr_drp0->bahen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) bank ^= bank_hash(pmiaddr, idx, d->addrdec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) case R(0):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) row |= (bit << idx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) case RS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) rank = bit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) if (cr_drp0->rsien)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) rank ^= rank_hash(pmiaddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) if (bit) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) snprintf(msg, PND2_MSG_SIZE, "Bad translation\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) goto done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) done:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) daddr->col = column;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) daddr->bank = bank;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) daddr->row = row;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) daddr->rank = rank;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) daddr->dimm = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) /* Pluck bit "in" from pmiaddr and return value shifted to bit "out" */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) #define dnv_get_bit(pmi, in, out) ((int)(((pmi) >> (in)) & 1u) << (out))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) static int dnv_pmi2mem(struct mem_ctl_info *mci, u64 pmiaddr, u32 pmiidx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) struct dram_addr *daddr, char *msg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) /* Rank 0 or 1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) daddr->rank = dnv_get_bit(pmiaddr, dmap[pmiidx].rs0 + 13, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) /* Rank 2 or 3 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) daddr->rank |= dnv_get_bit(pmiaddr, dmap[pmiidx].rs1 + 13, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) * Normally ranks 0,1 are DIMM0, and 2,3 are DIMM1, but we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) * flip them if DIMM1 is larger than DIMM0.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) daddr->dimm = (daddr->rank >= 2) ^ drp[pmiidx].dimmflip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) daddr->bank = dnv_get_bit(pmiaddr, dmap[pmiidx].ba0 + 6, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) daddr->bank |= dnv_get_bit(pmiaddr, dmap[pmiidx].ba1 + 6, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) daddr->bank |= dnv_get_bit(pmiaddr, dmap[pmiidx].bg0 + 6, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) if (dsch.ddr4en)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) daddr->bank |= dnv_get_bit(pmiaddr, dmap[pmiidx].bg1 + 6, 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) if (dmap1[pmiidx].bxor) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) if (dsch.ddr4en) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) daddr->bank ^= dnv_get_bit(pmiaddr, dmap3[pmiidx].row6 + 6, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) daddr->bank ^= dnv_get_bit(pmiaddr, dmap3[pmiidx].row7 + 6, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) if (dsch.chan_width == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) /* 64/72 bit dram channel width */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) daddr->bank ^= dnv_get_bit(pmiaddr, dmap5[pmiidx].ca3 + 6, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) /* 32/40 bit dram channel width */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) daddr->bank ^= dnv_get_bit(pmiaddr, dmap5[pmiidx].ca4 + 6, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) daddr->bank ^= dnv_get_bit(pmiaddr, dmap2[pmiidx].row2 + 6, 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) daddr->bank ^= dnv_get_bit(pmiaddr, dmap2[pmiidx].row2 + 6, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) daddr->bank ^= dnv_get_bit(pmiaddr, dmap3[pmiidx].row6 + 6, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) if (dsch.chan_width == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) daddr->bank ^= dnv_get_bit(pmiaddr, dmap5[pmiidx].ca3 + 6, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) daddr->bank ^= dnv_get_bit(pmiaddr, dmap5[pmiidx].ca4 + 6, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) daddr->row = dnv_get_bit(pmiaddr, dmap2[pmiidx].row0 + 6, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) daddr->row |= dnv_get_bit(pmiaddr, dmap2[pmiidx].row1 + 6, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) daddr->row |= dnv_get_bit(pmiaddr, dmap2[pmiidx].row2 + 6, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) daddr->row |= dnv_get_bit(pmiaddr, dmap2[pmiidx].row3 + 6, 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) daddr->row |= dnv_get_bit(pmiaddr, dmap2[pmiidx].row4 + 6, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) daddr->row |= dnv_get_bit(pmiaddr, dmap2[pmiidx].row5 + 6, 5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) daddr->row |= dnv_get_bit(pmiaddr, dmap3[pmiidx].row6 + 6, 6);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) daddr->row |= dnv_get_bit(pmiaddr, dmap3[pmiidx].row7 + 6, 7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) daddr->row |= dnv_get_bit(pmiaddr, dmap3[pmiidx].row8 + 6, 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) daddr->row |= dnv_get_bit(pmiaddr, dmap3[pmiidx].row9 + 6, 9);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) daddr->row |= dnv_get_bit(pmiaddr, dmap3[pmiidx].row10 + 6, 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) daddr->row |= dnv_get_bit(pmiaddr, dmap3[pmiidx].row11 + 6, 11);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) daddr->row |= dnv_get_bit(pmiaddr, dmap4[pmiidx].row12 + 6, 12);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) daddr->row |= dnv_get_bit(pmiaddr, dmap4[pmiidx].row13 + 6, 13);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) if (dmap4[pmiidx].row14 != 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) daddr->row |= dnv_get_bit(pmiaddr, dmap4[pmiidx].row14 + 6, 14);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) if (dmap4[pmiidx].row15 != 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) daddr->row |= dnv_get_bit(pmiaddr, dmap4[pmiidx].row15 + 6, 15);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) if (dmap4[pmiidx].row16 != 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) daddr->row |= dnv_get_bit(pmiaddr, dmap4[pmiidx].row16 + 6, 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) if (dmap4[pmiidx].row17 != 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) daddr->row |= dnv_get_bit(pmiaddr, dmap4[pmiidx].row17 + 6, 17);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) daddr->col = dnv_get_bit(pmiaddr, dmap5[pmiidx].ca3 + 6, 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) daddr->col |= dnv_get_bit(pmiaddr, dmap5[pmiidx].ca4 + 6, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) daddr->col |= dnv_get_bit(pmiaddr, dmap5[pmiidx].ca5 + 6, 5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) daddr->col |= dnv_get_bit(pmiaddr, dmap5[pmiidx].ca6 + 6, 6);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) daddr->col |= dnv_get_bit(pmiaddr, dmap5[pmiidx].ca7 + 6, 7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) daddr->col |= dnv_get_bit(pmiaddr, dmap5[pmiidx].ca8 + 6, 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) daddr->col |= dnv_get_bit(pmiaddr, dmap5[pmiidx].ca9 + 6, 9);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) if (!dsch.ddr4en && dmap1[pmiidx].ca11 != 0x3f)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) daddr->col |= dnv_get_bit(pmiaddr, dmap1[pmiidx].ca11 + 13, 11);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) static int check_channel(int ch)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) if (drp0[ch].dramtype != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) pnd2_printk(KERN_INFO, "Unsupported DIMM in channel %d\n", ch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) } else if (drp0[ch].eccen == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) pnd2_printk(KERN_INFO, "ECC disabled on channel %d\n", ch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) static int apl_check_ecc_active(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) int i, ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) /* Check dramtype and ECC mode for each present DIMM */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) for (i = 0; i < APL_NUM_CHANNELS; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) if (chan_mask & BIT(i))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) ret += check_channel(i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) return ret ? -EINVAL : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) #define DIMMS_PRESENT(d) ((d)->rken0 + (d)->rken1 + (d)->rken2 + (d)->rken3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) static int check_unit(int ch)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) struct d_cr_drp *d = &drp[ch];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) if (DIMMS_PRESENT(d) && !ecc_ctrl[ch].eccen) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) pnd2_printk(KERN_INFO, "ECC disabled on channel %d\n", ch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) static int dnv_check_ecc_active(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) int i, ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) for (i = 0; i < DNV_NUM_CHANNELS; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) ret += check_unit(i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) return ret ? -EINVAL : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) static int get_memory_error_data(struct mem_ctl_info *mci, u64 addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118) struct dram_addr *daddr, char *msg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) u64 pmiaddr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) u32 pmiidx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) ret = sys2pmi(addr, &pmiidx, &pmiaddr, msg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) pmiaddr >>= ops->pmiaddr_shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) /* pmi channel idx to dimm channel idx */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) pmiidx >>= ops->pmiidx_shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) daddr->chan = pmiidx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) ret = ops->pmi2mem(mci, pmiaddr, pmiidx, daddr, msg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) edac_dbg(0, "SysAddr=%llx PmiAddr=%llx Channel=%d DIMM=%d Rank=%d Bank=%d Row=%d Column=%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) addr, pmiaddr, daddr->chan, daddr->dimm, daddr->rank, daddr->bank, daddr->row, daddr->col);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) static void pnd2_mce_output_error(struct mem_ctl_info *mci, const struct mce *m,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) struct dram_addr *daddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) enum hw_event_mc_err_type tp_event;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) char *optype, msg[PND2_MSG_SIZE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) bool ripv = m->mcgstatus & MCG_STATUS_RIPV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) bool overflow = m->status & MCI_STATUS_OVER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) bool uc_err = m->status & MCI_STATUS_UC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) bool recov = m->status & MCI_STATUS_S;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) u32 core_err_cnt = GET_BITFIELD(m->status, 38, 52);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) u32 mscod = GET_BITFIELD(m->status, 16, 31);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154) u32 errcode = GET_BITFIELD(m->status, 0, 15);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) u32 optypenum = GET_BITFIELD(m->status, 4, 6);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158) tp_event = uc_err ? (ripv ? HW_EVENT_ERR_UNCORRECTED : HW_EVENT_ERR_FATAL) :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159) HW_EVENT_ERR_CORRECTED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162) * According with Table 15-9 of the Intel Architecture spec vol 3A,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163) * memory errors should fit in this mask:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) * 000f 0000 1mmm cccc (binary)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165) * where:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166) * f = Correction Report Filtering Bit. If 1, subsequent errors
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167) * won't be shown
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) * mmm = error type
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169) * cccc = channel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170) * If the mask doesn't match, report an error to the parsing logic
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172) if (!((errcode & 0xef80) == 0x80)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) optype = "Can't parse: it is not a mem";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175) switch (optypenum) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176) case 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177) optype = "generic undef request error";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180) optype = "memory read error";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182) case 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183) optype = "memory write error";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185) case 3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) optype = "addr/cmd error";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188) case 4:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189) optype = "memory scrubbing error";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192) optype = "reserved";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197) /* Only decode errors with an valid address (ADDRV) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198) if (!(m->status & MCI_STATUS_ADDRV))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201) rc = get_memory_error_data(mci, m->addr, daddr, msg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203) goto address_error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205) snprintf(msg, sizeof(msg),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206) "%s%s err_code:%04x:%04x channel:%d DIMM:%d rank:%d row:%d bank:%d col:%d",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207) overflow ? " OVERFLOW" : "", (uc_err && recov) ? " recoverable" : "", mscod,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208) errcode, daddr->chan, daddr->dimm, daddr->rank, daddr->row, daddr->bank, daddr->col);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210) edac_dbg(0, "%s\n", msg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212) /* Call the helper to output message */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213) edac_mc_handle_error(tp_event, mci, core_err_cnt, m->addr >> PAGE_SHIFT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214) m->addr & ~PAGE_MASK, 0, daddr->chan, daddr->dimm, -1, optype, msg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218) address_error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219) edac_mc_handle_error(tp_event, mci, core_err_cnt, 0, 0, 0, -1, -1, -1, msg, "");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222) static void apl_get_dimm_config(struct mem_ctl_info *mci)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224) struct pnd2_pvt *pvt = mci->pvt_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225) struct dimm_info *dimm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226) struct d_cr_drp0 *d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227) u64 capacity;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228) int i, g;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230) for (i = 0; i < APL_NUM_CHANNELS; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231) if (!(chan_mask & BIT(i)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234) dimm = edac_get_dimm(mci, i, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235) if (!dimm) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236) edac_dbg(0, "No allocated DIMM for channel %d\n", i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240) d = &drp0[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1241) for (g = 0; g < ARRAY_SIZE(dimms); g++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1242) if (dimms[g].addrdec == d->addrdec &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1243) dimms[g].dden == d->dden &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1244) dimms[g].dwid == d->dwid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1245) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1247) if (g == ARRAY_SIZE(dimms)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1248) edac_dbg(0, "Channel %d: unrecognized DIMM\n", i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1249) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1250) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1252) pvt->dimm_geom[i] = g;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1253) capacity = (d->rken0 + d->rken1) * 8 * (1ul << dimms[g].rowbits) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1254) (1ul << dimms[g].colbits);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1255) edac_dbg(0, "Channel %d: %lld MByte DIMM\n", i, capacity >> (20 - 3));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1256) dimm->nr_pages = MiB_TO_PAGES(capacity >> (20 - 3));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1257) dimm->grain = 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1258) dimm->dtype = (d->dwid == 0) ? DEV_X8 : DEV_X16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1259) dimm->mtype = MEM_DDR3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1260) dimm->edac_mode = EDAC_SECDED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1261) snprintf(dimm->label, sizeof(dimm->label), "Slice#%d_Chan#%d", i / 2, i % 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1262) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1263) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1265) static const int dnv_dtypes[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1266) DEV_X8, DEV_X4, DEV_X16, DEV_UNKNOWN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1267) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1269) static void dnv_get_dimm_config(struct mem_ctl_info *mci)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1270) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1271) int i, j, ranks_of_dimm[DNV_MAX_DIMMS], banks, rowbits, colbits, memtype;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1272) struct dimm_info *dimm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1273) struct d_cr_drp *d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1274) u64 capacity;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1275)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1276) if (dsch.ddr4en) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1277) memtype = MEM_DDR4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1278) banks = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1279) colbits = 10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1280) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1281) memtype = MEM_DDR3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1282) banks = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1283) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1284)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1285) for (i = 0; i < DNV_NUM_CHANNELS; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1286) if (dmap4[i].row14 == 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1287) rowbits = 14;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1288) else if (dmap4[i].row15 == 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1289) rowbits = 15;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1290) else if (dmap4[i].row16 == 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1291) rowbits = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1292) else if (dmap4[i].row17 == 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1293) rowbits = 17;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1294) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1295) rowbits = 18;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1297) if (memtype == MEM_DDR3) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1298) if (dmap1[i].ca11 != 0x3f)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1299) colbits = 12;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1300) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1301) colbits = 10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1302) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1304) d = &drp[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1305) /* DIMM0 is present if rank0 and/or rank1 is enabled */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1306) ranks_of_dimm[0] = d->rken0 + d->rken1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1307) /* DIMM1 is present if rank2 and/or rank3 is enabled */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1308) ranks_of_dimm[1] = d->rken2 + d->rken3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1309)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1310) for (j = 0; j < DNV_MAX_DIMMS; j++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1311) if (!ranks_of_dimm[j])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1312) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1314) dimm = edac_get_dimm(mci, i, j, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1315) if (!dimm) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1316) edac_dbg(0, "No allocated DIMM for channel %d DIMM %d\n", i, j);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1317) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1318) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1320) capacity = ranks_of_dimm[j] * banks * (1ul << rowbits) * (1ul << colbits);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1321) edac_dbg(0, "Channel %d DIMM %d: %lld MByte DIMM\n", i, j, capacity >> (20 - 3));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1322) dimm->nr_pages = MiB_TO_PAGES(capacity >> (20 - 3));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1323) dimm->grain = 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1324) dimm->dtype = dnv_dtypes[j ? d->dimmdwid0 : d->dimmdwid1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1325) dimm->mtype = memtype;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1326) dimm->edac_mode = EDAC_SECDED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1327) snprintf(dimm->label, sizeof(dimm->label), "Chan#%d_DIMM#%d", i, j);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1328) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1329) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1330) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1332) static int pnd2_register_mci(struct mem_ctl_info **ppmci)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1333) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1334) struct edac_mc_layer layers[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1335) struct mem_ctl_info *mci;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1336) struct pnd2_pvt *pvt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1337) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1339) rc = ops->check_ecc();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1340) if (rc < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1341) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1342)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1343) /* Allocate a new MC control structure */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1344) layers[0].type = EDAC_MC_LAYER_CHANNEL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1345) layers[0].size = ops->channels;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1346) layers[0].is_virt_csrow = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1347) layers[1].type = EDAC_MC_LAYER_SLOT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1348) layers[1].size = ops->dimms_per_channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1349) layers[1].is_virt_csrow = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1350) mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, sizeof(*pvt));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1351) if (!mci)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1352) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1353)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1354) pvt = mci->pvt_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1355) memset(pvt, 0, sizeof(*pvt));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1356)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1357) mci->mod_name = EDAC_MOD_STR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1358) mci->dev_name = ops->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1359) mci->ctl_name = "Pondicherry2";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1361) /* Get dimm basic config and the memory layout */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1362) ops->get_dimm_config(mci);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1364) if (edac_mc_add_mc(mci)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1365) edac_dbg(0, "MC: failed edac_mc_add_mc()\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1366) edac_mc_free(mci);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1367) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1368) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1370) *ppmci = mci;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1371)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1372) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1373) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1374)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1375) static void pnd2_unregister_mci(struct mem_ctl_info *mci)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1376) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1377) if (unlikely(!mci || !mci->pvt_info)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1378) pnd2_printk(KERN_ERR, "Couldn't find mci handler\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1379) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1380) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1381)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1382) /* Remove MC sysfs nodes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1383) edac_mc_del_mc(NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1384) edac_dbg(1, "%s: free mci struct\n", mci->ctl_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1385) edac_mc_free(mci);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1386) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1387)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1388) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1389) * Callback function registered with core kernel mce code.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1390) * Called once for each logged error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1391) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1392) static int pnd2_mce_check_error(struct notifier_block *nb, unsigned long val, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1393) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1394) struct mce *mce = (struct mce *)data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1395) struct mem_ctl_info *mci;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1396) struct dram_addr daddr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1397) char *type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1398)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1399) mci = pnd2_mci;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1400) if (!mci || (mce->kflags & MCE_HANDLED_CEC))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1401) return NOTIFY_DONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1402)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1403) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1404) * Just let mcelog handle it if the error is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1405) * outside the memory controller. A memory error
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1406) * is indicated by bit 7 = 1 and bits = 8-11,13-15 = 0.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1407) * bit 12 has an special meaning.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1408) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1409) if ((mce->status & 0xefff) >> 7 != 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1410) return NOTIFY_DONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1412) if (mce->mcgstatus & MCG_STATUS_MCIP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1413) type = "Exception";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1414) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1415) type = "Event";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1416)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1417) pnd2_mc_printk(mci, KERN_INFO, "HANDLING MCE MEMORY ERROR\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1418) pnd2_mc_printk(mci, KERN_INFO, "CPU %u: Machine Check %s: %llx Bank %u: %llx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1419) mce->extcpu, type, mce->mcgstatus, mce->bank, mce->status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1420) pnd2_mc_printk(mci, KERN_INFO, "TSC %llx ", mce->tsc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1421) pnd2_mc_printk(mci, KERN_INFO, "ADDR %llx ", mce->addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1422) pnd2_mc_printk(mci, KERN_INFO, "MISC %llx ", mce->misc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1423) pnd2_mc_printk(mci, KERN_INFO, "PROCESSOR %u:%x TIME %llu SOCKET %u APIC %x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1424) mce->cpuvendor, mce->cpuid, mce->time, mce->socketid, mce->apicid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1425)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1426) pnd2_mce_output_error(mci, mce, &daddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1427)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1428) /* Advice mcelog that the error were handled */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1429) mce->kflags |= MCE_HANDLED_EDAC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1430) return NOTIFY_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1431) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1432)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1433) static struct notifier_block pnd2_mce_dec = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1434) .notifier_call = pnd2_mce_check_error,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1435) .priority = MCE_PRIO_EDAC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1436) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1437)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1438) #ifdef CONFIG_EDAC_DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1439) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1440) * Write an address to this file to exercise the address decode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1441) * logic in this driver.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1442) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1443) static u64 pnd2_fake_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1444) #define PND2_BLOB_SIZE 1024
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1445) static char pnd2_result[PND2_BLOB_SIZE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1446) static struct dentry *pnd2_test;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1447) static struct debugfs_blob_wrapper pnd2_blob = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1448) .data = pnd2_result,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1449) .size = 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1450) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1451)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1452) static int debugfs_u64_set(void *data, u64 val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1453) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1454) struct dram_addr daddr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1455) struct mce m;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1456)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1457) *(u64 *)data = val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1458) m.mcgstatus = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1459) /* ADDRV + MemRd + Unknown channel */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1460) m.status = MCI_STATUS_ADDRV + 0x9f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1461) m.addr = val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1462) pnd2_mce_output_error(pnd2_mci, &m, &daddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1463) snprintf(pnd2_blob.data, PND2_BLOB_SIZE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1464) "SysAddr=%llx Channel=%d DIMM=%d Rank=%d Bank=%d Row=%d Column=%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1465) m.addr, daddr.chan, daddr.dimm, daddr.rank, daddr.bank, daddr.row, daddr.col);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1466) pnd2_blob.size = strlen(pnd2_blob.data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1467)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1468) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1469) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1470) DEFINE_DEBUGFS_ATTRIBUTE(fops_u64_wo, NULL, debugfs_u64_set, "%llu\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1471)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1472) static void setup_pnd2_debug(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1473) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1474) pnd2_test = edac_debugfs_create_dir("pnd2_test");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1475) edac_debugfs_create_file("pnd2_debug_addr", 0200, pnd2_test,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1476) &pnd2_fake_addr, &fops_u64_wo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1477) debugfs_create_blob("pnd2_debug_results", 0400, pnd2_test, &pnd2_blob);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1478) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1479)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1480) static void teardown_pnd2_debug(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1481) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1482) debugfs_remove_recursive(pnd2_test);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1483) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1484) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1485) static void setup_pnd2_debug(void) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1486) static void teardown_pnd2_debug(void) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1487) #endif /* CONFIG_EDAC_DEBUG */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1488)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1489)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1490) static int pnd2_probe(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1491) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1492) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1493)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1494) edac_dbg(2, "\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1495) rc = get_registers();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1496) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1497) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1498)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1499) return pnd2_register_mci(&pnd2_mci);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1500) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1501)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1502) static void pnd2_remove(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1503) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1504) edac_dbg(0, "\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1505) pnd2_unregister_mci(pnd2_mci);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1506) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1507)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1508) static struct dunit_ops apl_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1509) .name = "pnd2/apl",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1510) .type = APL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1511) .pmiaddr_shift = LOG2_PMI_ADDR_GRANULARITY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1512) .pmiidx_shift = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1513) .channels = APL_NUM_CHANNELS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1514) .dimms_per_channel = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1515) .rd_reg = apl_rd_reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1516) .get_registers = apl_get_registers,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1517) .check_ecc = apl_check_ecc_active,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1518) .mk_region = apl_mk_region,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1519) .get_dimm_config = apl_get_dimm_config,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1520) .pmi2mem = apl_pmi2mem,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1521) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1522)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1523) static struct dunit_ops dnv_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1524) .name = "pnd2/dnv",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1525) .type = DNV,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1526) .pmiaddr_shift = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1527) .pmiidx_shift = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1528) .channels = DNV_NUM_CHANNELS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1529) .dimms_per_channel = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1530) .rd_reg = dnv_rd_reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1531) .get_registers = dnv_get_registers,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1532) .check_ecc = dnv_check_ecc_active,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1533) .mk_region = dnv_mk_region,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1534) .get_dimm_config = dnv_get_dimm_config,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1535) .pmi2mem = dnv_pmi2mem,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1536) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1537)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1538) static const struct x86_cpu_id pnd2_cpuids[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1539) X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT, &apl_ops),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1540) X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT_D, &dnv_ops),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1541) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1542) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1543) MODULE_DEVICE_TABLE(x86cpu, pnd2_cpuids);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1544)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1545) static int __init pnd2_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1546) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1547) const struct x86_cpu_id *id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1548) const char *owner;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1549) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1550)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1551) edac_dbg(2, "\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1552)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1553) owner = edac_get_owner();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1554) if (owner && strncmp(owner, EDAC_MOD_STR, sizeof(EDAC_MOD_STR)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1555) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1556)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1557) if (cpu_feature_enabled(X86_FEATURE_HYPERVISOR))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1558) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1559)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1560) id = x86_match_cpu(pnd2_cpuids);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1561) if (!id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1562) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1563)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1564) ops = (struct dunit_ops *)id->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1565)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1566) if (ops->type == APL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1567) p2sb_bus = pci_find_bus(0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1568) if (!p2sb_bus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1569) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1570) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1571)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1572) /* Ensure that the OPSTATE is set correctly for POLL or NMI */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1573) opstate_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1574)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1575) rc = pnd2_probe();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1576) if (rc < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1577) pnd2_printk(KERN_ERR, "Failed to register device with error %d.\n", rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1578) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1579) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1580)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1581) if (!pnd2_mci)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1582) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1583)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1584) mce_register_decode_chain(&pnd2_mce_dec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1585) setup_pnd2_debug();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1586)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1587) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1588) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1589)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1590) static void __exit pnd2_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1591) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1592) edac_dbg(2, "\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1593) teardown_pnd2_debug();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1594) mce_unregister_decode_chain(&pnd2_mce_dec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1595) pnd2_remove();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1596) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1597)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1598) module_init(pnd2_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1599) module_exit(pnd2_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1600)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1601) module_param(edac_op_state, int, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1602) MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1603)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1604) MODULE_LICENSE("GPL v2");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1605) MODULE_AUTHOR("Tony Luck");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1606) MODULE_DESCRIPTION("MC Driver for Intel SoC using Pondicherry memory controller");