lkml.org 
[lkml]   [2009]   [Apr]   [29]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 05/21] amd64_edac: add sys addr to memory controller mapping helpers
    Date
    From: Doug Thompson <dougthompson@xmission.com>

    Signed-off-by: Doug Thompson <dougthompson@xmission.com>
    Signed-off-by: Borislav Petkov <borislav.petkov@amd.com>
    ---
    drivers/edac/amd64_edac.c | 163 +++++++++++++++++++++++++++++++++++++++++++++
    1 files changed, 163 insertions(+), 0 deletions(-)

    diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
    index a121785..49c931f 100644
    --- a/drivers/edac/amd64_edac.c
    +++ b/drivers/edac/amd64_edac.c
    @@ -1115,4 +1115,167 @@ static int amd64_get_scrub_rate(struct mem_ctl_info *mci, u32 *bw)
    return status;
    }

    +/*
    + * amd64_map_to_dcs_mask
    + *
    + * Map from a CSROW entry to the mask entry that operates on it
    + */
    +static inline u32 amd64_map_to_dcs_mask(struct amd64_pvt *pvt, int csrow)
    +{
    + return csrow >> (pvt->num_dcsm >> 3);
    +}
    +
    +/*
    + * amd64_get_dct_base()
    + *
    + * getter function to return the 'base' address the i'th CS entry
    + * of the 'dct' DRAM controller
    + */
    +static u32 amd64_get_dct_base(struct amd64_pvt *pvt, int dct, int csrow)
    +{
    + if (dct == 0)
    + return pvt->dcsb0[csrow];
    + else
    + return pvt->dcsb1[csrow];
    +}
    +
    +/*
    + * amd64_get_dct_mask()
    + *
    + * getter function to return the 'mask' address the i'th CS entry.
    + * This getter function is needed because there different number
    + * of DCSM registers on Rev E and prior vs Rev F and later
    + */
    +static u32 amd64_get_dct_mask(struct amd64_pvt *pvt, int dct, int csrow)
    +{
    + if (dct == 0)
    + return pvt->dcsm0[amd64_map_to_dcs_mask(pvt, csrow)];
    + else
    + return pvt->dcsm1[amd64_map_to_dcs_mask(pvt, csrow)];
    +}
    +
    +
    +/*
    + * amd64_get_base_and_limit()
    + *
    + * In *base and *limit, pass back the full 40-bit base and limit physical
    + * addresses for the node given by node_id. This information is obtained from
    + * DRAM Base (section 3.4.4.1) and DRAM Limit (section 3.4.4.2) registers. The
    + * base and limit addresses are of type SysAddr, as defined at the start of
    + * section 3.4.4 (p. 70). They are the lowest and highest physical addresses
    + * in the address range they represent.
    + */
    +static void amd64_get_base_and_limit(struct amd64_pvt *pvt, int node_id,
    + u64 *base, u64 *limit)
    +{
    + *base = pvt->dram_base[node_id];
    + *limit = pvt->dram_limit[node_id];
    +}
    +
    +/*
    + * Return 1 if the SysAddr given by sys_addr matches the base/limit associated
    + * with node_id
    + */
    +static int amd64_base_limit_match(struct amd64_pvt *pvt,
    + u64 sys_addr, int node_id)
    +{
    + u64 base, limit, addr;

    + amd64_get_base_and_limit(pvt, node_id, &base, &limit);
    +
    + /* The K8 treats this as a 40-bit value. However, bits 63-40 will be
    + * all ones if the most significant implemented address bit is 1.
    + * Here we discard bits 63-40. See section 3.4.2 of AMD publication
    + * 24592: AMD x86-64 Architecture Programmer's Manual Volume 1
    + * Application Programming.
    + */
    + addr = sys_addr & 0x000000ffffffffffull;
    +
    + return (addr >= base) && (addr <= limit);
    +}
    +
    +/* find_mc_by_sys_addr
    + *
    + * Attempt to map a SysAddr to a node.
    + *
    + * On success, return a pointer to the mem_ctl_info structure for
    + * the node that the SysAddr maps to.
    + *
    + * On failure, return NULL
    + */
    +static struct mem_ctl_info *find_mc_by_sys_addr(struct mem_ctl_info *mci,
    + u64 sys_addr)
    +{
    + struct amd64_pvt *pvt;
    + int node_id;
    + u32 intlv_en, bits;
    +
    + /*
    + * Here we use the DRAM Base (section 3.4.4.1) and DRAM Limit (section
    + * 3.4.4.2) registers to map the SysAddr to a node ID.
    + */
    + pvt = mci->pvt_info;
    +
    + /* The value of this field should be the same for all DRAM Base
    + * registers. Therefore we arbitrarily choose to read it from the
    + * register for node 0.
    + */
    + intlv_en = pvt->dram_IntlvEn[0];
    +
    + if (intlv_en == 0) {
    + debugf2("%s(): node interleaving disabled\n", __func__);
    + for (node_id = 0; ; ) {
    + if (amd64_base_limit_match(pvt, sys_addr, node_id))
    + break;
    +
    + if (++node_id >= DRAM_REG_COUNT) {
    + debugf2("%s(): sys_addr 0x%lx "
    + "does not match any node\n", __func__,
    + (unsigned long)sys_addr);
    + return NULL;
    + }
    + }
    +
    + goto found;
    + }
    +
    + if (unlikely((intlv_en != (0x01 << 8)) &&
    + (intlv_en != (0x03 << 8)) && (intlv_en != (0x07 << 8)))) {
    + amd64_printk(KERN_WARNING,
    + "%s(): junk value of 0x%x extracted from IntlvEn "
    + "field of DRAM Base Register for node 0: This "
    + "probably indicates a BIOS bug.\n", __func__,
    + intlv_en);
    + return NULL;
    + }
    +
    + debugf2("%s(): node interleaving enabled\n", __func__);
    + bits = (((u32) sys_addr) >> 12) & intlv_en;
    +
    + for (node_id = 0; ; ) {
    + if ((pvt->dram_limit[node_id] & intlv_en) == bits)
    + break; /* intlv_sel field matches */
    +
    + if (++node_id >= DRAM_REG_COUNT) {
    + debugf2("%s(): sys_addr 0x%lx does not match any "
    + "node\n", __func__, (unsigned long)sys_addr);
    + return NULL;
    + }
    + }
    +
    + /* sanity test for sys_addr */
    + if (unlikely(!amd64_base_limit_match(pvt, sys_addr, node_id))) {
    + amd64_printk(KERN_WARNING,
    + "%s(): sys_addr 0x%lx falls outside base/limit "
    + "address range for node %d with node interleaving "
    + "enabled.\n", __func__, (unsigned long)sys_addr,
    + node_id);
    + return NULL;
    + }
    +
    +found:
    + debugf2("%s(): sys_addr 0x%lx matches node %d\n", __func__,
    + (unsigned long)sys_addr, node_id);
    +
    + return edac_mc_find(node_id);
    +}
    --
    1.6.2.4



    \
     
     \ /
      Last update: 2009-04-29 18:59    [W:0.029 / U:31.536 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site