15c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf/* 25c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf * Copyright 2011 Tilera Corporation. All Rights Reserved. 35c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf * 45c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf * This program is free software; you can redistribute it and/or 55c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf * modify it under the terms of the GNU General Public License 65c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf * as published by the Free Software Foundation, version 2. 75c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf * 85c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf * This program is distributed in the hope that it will be useful, but 95c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf * WITHOUT ANY WARRANTY; without even the implied warranty of 105c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or 115c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf * NON INFRINGEMENT. See the GNU General Public License for 125c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf * more details. 135c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf * Tilera-specific EDAC driver. 145c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf * 155c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf * This source code is derived from the following driver: 165c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf * 175c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf * Cell MIC driver for ECC counting 185c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf * 195c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf * Copyright 2007 Benjamin Herrenschmidt, IBM Corp. 205c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf * <benh@kernel.crashing.org> 215c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf * 225c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf */ 235c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf 245c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf#include <linux/module.h> 255c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf#include <linux/init.h> 265c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf#include <linux/platform_device.h> 275c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf#include <linux/io.h> 285c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf#include <linux/uaccess.h> 295c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf#include <linux/edac.h> 305c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf#include <hv/hypervisor.h> 315c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf#include <hv/drv_mshim_intf.h> 325c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf 335c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf#include "edac_core.h" 345c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf 355c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf#define DRV_NAME "tile-edac" 365c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf 375c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf/* Number of cs_rows needed per memory controller on TILEPro. */ 385c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf#define TILE_EDAC_NR_CSROWS 1 395c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf 405c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf/* Number of channels per memory controller on TILEPro. */ 415c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf#define TILE_EDAC_NR_CHANS 1 425c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf 435c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf/* Granularity of reported error in bytes on TILEPro. */ 445c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf#define TILE_EDAC_ERROR_GRAIN 8 455c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf 465c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf/* TILE processor has multiple independent memory controllers. */ 475c7707554858eca8903706b6df7cba5c0f802244Chris Metcalfstruct platform_device *mshim_pdev[TILE_MAX_MSHIMS]; 485c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf 495c7707554858eca8903706b6df7cba5c0f802244Chris Metcalfstruct tile_edac_priv { 505c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf int hv_devhdl; /* Hypervisor device handle. */ 515c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf int node; /* Memory controller instance #. */ 525c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf unsigned int ce_count; /* 535c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf * Correctable-error counter 545c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf * kept by the driver. 555c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf */ 565c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf}; 575c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf 585c7707554858eca8903706b6df7cba5c0f802244Chris Metcalfstatic void tile_edac_check(struct mem_ctl_info *mci) 595c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf{ 605c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf struct tile_edac_priv *priv = mci->pvt_info; 615c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf struct mshim_mem_error mem_error; 625c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf 635c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf if (hv_dev_pread(priv->hv_devhdl, 0, (HV_VirtAddr)&mem_error, 645c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf sizeof(struct mshim_mem_error), MSHIM_MEM_ERROR_OFF) != 655c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf sizeof(struct mshim_mem_error)) { 665c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf pr_err(DRV_NAME ": MSHIM_MEM_ERROR_OFF pread failure.\n"); 675c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf return; 685c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf } 695c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf 705c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf /* Check if the current error count is different from the saved one. */ 715c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf if (mem_error.sbe_count != priv->ce_count) { 725c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf dev_dbg(mci->dev, "ECC CE err on node %d\n", priv->node); 735c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf priv->ce_count = mem_error.sbe_count; 745c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf edac_mc_handle_ce(mci, 0, 0, 0, 0, 0, mci->ctl_name); 755c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf } 765c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf} 775c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf 785c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf/* 795c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf * Initialize the 'csrows' table within the mci control structure with the 805c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf * addressing of memory. 815c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf */ 825c7707554858eca8903706b6df7cba5c0f802244Chris Metcalfstatic int __devinit tile_edac_init_csrows(struct mem_ctl_info *mci) 835c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf{ 845c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf struct csrow_info *csrow = &mci->csrows[0]; 855c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf struct tile_edac_priv *priv = mci->pvt_info; 865c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf struct mshim_mem_info mem_info; 875c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf 885c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf if (hv_dev_pread(priv->hv_devhdl, 0, (HV_VirtAddr)&mem_info, 895c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf sizeof(struct mshim_mem_info), MSHIM_MEM_INFO_OFF) != 905c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf sizeof(struct mshim_mem_info)) { 915c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf pr_err(DRV_NAME ": MSHIM_MEM_INFO_OFF pread failure.\n"); 925c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf return -1; 935c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf } 945c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf 955c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf if (mem_info.mem_ecc) 965c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf csrow->edac_mode = EDAC_SECDED; 975c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf else 985c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf csrow->edac_mode = EDAC_NONE; 995c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf switch (mem_info.mem_type) { 1005c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf case DDR2: 1015c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf csrow->mtype = MEM_DDR2; 1025c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf break; 1035c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf 1045c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf case DDR3: 1055c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf csrow->mtype = MEM_DDR3; 1065c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf break; 1075c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf 1085c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf default: 1095c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf return -1; 1105c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf } 1115c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf 1125c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf csrow->first_page = 0; 1135c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf csrow->nr_pages = mem_info.mem_size >> PAGE_SHIFT; 1145c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf csrow->last_page = csrow->first_page + csrow->nr_pages - 1; 1155c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf csrow->grain = TILE_EDAC_ERROR_GRAIN; 1165c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf csrow->dtype = DEV_UNKNOWN; 1175c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf 1185c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf return 0; 1195c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf} 1205c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf 1215c7707554858eca8903706b6df7cba5c0f802244Chris Metcalfstatic int __devinit tile_edac_mc_probe(struct platform_device *pdev) 1225c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf{ 1235c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf char hv_file[32]; 1245c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf int hv_devhdl; 1255c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf struct mem_ctl_info *mci; 1265c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf struct tile_edac_priv *priv; 1275c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf int rc; 1285c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf 1295c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf sprintf(hv_file, "mshim/%d", pdev->id); 1305c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf hv_devhdl = hv_dev_open((HV_VirtAddr)hv_file, 0); 1315c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf if (hv_devhdl < 0) 1325c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf return -EINVAL; 1335c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf 1345c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf /* A TILE MC has a single channel and one chip-select row. */ 1355c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf mci = edac_mc_alloc(sizeof(struct tile_edac_priv), 1365c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf TILE_EDAC_NR_CSROWS, TILE_EDAC_NR_CHANS, pdev->id); 1375c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf if (mci == NULL) 1385c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf return -ENOMEM; 1395c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf priv = mci->pvt_info; 1405c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf priv->node = pdev->id; 1415c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf priv->hv_devhdl = hv_devhdl; 1425c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf 1435c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf mci->dev = &pdev->dev; 1445c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf mci->mtype_cap = MEM_FLAG_DDR2; 1455c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf mci->edac_ctl_cap = EDAC_FLAG_SECDED; 1465c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf 1475c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf mci->mod_name = DRV_NAME; 148e2e110d7596656e2badd21c48713bd01e1b40f44Chris Metcalf#ifdef __tilegx__ 149e2e110d7596656e2badd21c48713bd01e1b40f44Chris Metcalf mci->ctl_name = "TILEGx_Memory_Controller"; 150e2e110d7596656e2badd21c48713bd01e1b40f44Chris Metcalf#else 1515c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf mci->ctl_name = "TILEPro_Memory_Controller"; 152e2e110d7596656e2badd21c48713bd01e1b40f44Chris Metcalf#endif 1535c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf mci->dev_name = dev_name(&pdev->dev); 1545c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf mci->edac_check = tile_edac_check; 1555c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf 1565c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf /* 1575c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf * Initialize the MC control structure 'csrows' table 1585c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf * with the mapping and control information. 1595c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf */ 1605c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf if (tile_edac_init_csrows(mci)) { 1615c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf /* No csrows found. */ 1625c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf mci->edac_cap = EDAC_FLAG_NONE; 1635c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf } else { 1645c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf mci->edac_cap = EDAC_FLAG_SECDED; 1655c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf } 1665c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf 1675c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf platform_set_drvdata(pdev, mci); 1685c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf 1695c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf /* Register with EDAC core */ 1705c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf rc = edac_mc_add_mc(mci); 1715c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf if (rc) { 1725c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf dev_err(&pdev->dev, "failed to register with EDAC core\n"); 1735c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf edac_mc_free(mci); 1745c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf return rc; 1755c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf } 1765c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf 1775c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf return 0; 1785c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf} 1795c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf 1805c7707554858eca8903706b6df7cba5c0f802244Chris Metcalfstatic int __devexit tile_edac_mc_remove(struct platform_device *pdev) 1815c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf{ 1825c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf struct mem_ctl_info *mci = platform_get_drvdata(pdev); 1835c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf 1845c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf edac_mc_del_mc(&pdev->dev); 1855c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf if (mci) 1865c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf edac_mc_free(mci); 1875c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf return 0; 1885c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf} 1895c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf 1905c7707554858eca8903706b6df7cba5c0f802244Chris Metcalfstatic struct platform_driver tile_edac_mc_driver = { 1915c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf .driver = { 1925c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf .name = DRV_NAME, 1935c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf .owner = THIS_MODULE, 1945c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf }, 1955c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf .probe = tile_edac_mc_probe, 1965c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf .remove = __devexit_p(tile_edac_mc_remove), 1975c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf}; 1985c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf 1995c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf/* 2005c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf * Driver init routine. 2015c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf */ 2025c7707554858eca8903706b6df7cba5c0f802244Chris Metcalfstatic int __init tile_edac_init(void) 2035c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf{ 2045c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf char hv_file[32]; 2055c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf struct platform_device *pdev; 2065c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf int i, err, num = 0; 2075c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf 2085c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf /* Only support POLL mode. */ 2095c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf edac_op_state = EDAC_OPSTATE_POLL; 2105c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf 2115c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf err = platform_driver_register(&tile_edac_mc_driver); 2125c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf if (err) 2135c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf return err; 2145c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf 2155c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf for (i = 0; i < TILE_MAX_MSHIMS; i++) { 2165c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf /* 2175c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf * Not all memory controllers are configured such as in the 2185c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf * case of a simulator. So we register only those mshims 2195c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf * that are configured by the hypervisor. 2205c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf */ 2215c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf sprintf(hv_file, "mshim/%d", i); 2225c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf if (hv_dev_open((HV_VirtAddr)hv_file, 0) < 0) 2235c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf continue; 2245c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf 2255c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf pdev = platform_device_register_simple(DRV_NAME, i, NULL, 0); 2265c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf if (IS_ERR(pdev)) 2275c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf continue; 2285c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf mshim_pdev[i] = pdev; 2295c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf num++; 2305c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf } 2315c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf 2325c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf if (num == 0) { 2335c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf platform_driver_unregister(&tile_edac_mc_driver); 2345c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf return -ENODEV; 2355c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf } 2365c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf return 0; 2375c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf} 2385c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf 2395c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf/* 2405c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf * Driver cleanup routine. 2415c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf */ 2425c7707554858eca8903706b6df7cba5c0f802244Chris Metcalfstatic void __exit tile_edac_exit(void) 2435c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf{ 2445c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf int i; 2455c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf 2465c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf for (i = 0; i < TILE_MAX_MSHIMS; i++) { 2475c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf struct platform_device *pdev = mshim_pdev[i]; 2485c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf if (!pdev) 2495c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf continue; 2505c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf 2515c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf platform_set_drvdata(pdev, NULL); 2525c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf platform_device_unregister(pdev); 2535c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf } 2545c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf platform_driver_unregister(&tile_edac_mc_driver); 2555c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf} 2565c7707554858eca8903706b6df7cba5c0f802244Chris Metcalf 2575c7707554858eca8903706b6df7cba5c0f802244Chris Metcalfmodule_init(tile_edac_init); 2585c7707554858eca8903706b6df7cba5c0f802244Chris Metcalfmodule_exit(tile_edac_exit); 259