Showing error 849

User: Jiri Slaby
Error type: Resource Leak
Error type description: The code omits to put the resource to the system for reuse
File location: drivers/video/vermilion/cr_pll.c
Line in file: 159
Project: Linux Kernel
Project version: 2.6.28
Tools: Stanse (1.2)
Entered: 2011-11-07 22:40:13 UTC


Source:

  1/*
  2 * Copyright (c) Intel Corp. 2007.
  3 * All Rights Reserved.
  4 *
  5 * Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
  6 * develop this driver.
  7 *
  8 * This file is part of the Carillo Ranch video subsystem driver.
  9 * The Carillo Ranch video subsystem driver is free software;
 10 * you can redistribute it and/or modify
 11 * it under the terms of the GNU General Public License as published by
 12 * the Free Software Foundation; either version 2 of the License, or
 13 * (at your option) any later version.
 14 *
 15 * The Carillo Ranch video subsystem driver is distributed
 16 * in the hope that it will be useful,
 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 19 * GNU General Public License for more details.
 20 *
 21 * You should have received a copy of the GNU General Public License
 22 * along with this driver; if not, write to the Free Software
 23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 24 *
 25 * Authors:
 26 *   Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
 27 *   Alan Hourihane <alanh-at-tungstengraphics-dot-com>
 28 */
 29
 30#include <linux/module.h>
 31#include <linux/kernel.h>
 32#include <linux/pci.h>
 33#include <linux/errno.h>
 34#include <linux/fb.h>
 35#include "vermilion.h"
 36
 37/* The PLL Clock register sits on Host bridge */
 38#define CRVML_DEVICE_MCH   0x5001
 39#define CRVML_REG_MCHBAR   0x44
 40#define CRVML_REG_MCHEN    0x54
 41#define CRVML_MCHEN_BIT    (1 << 28)
 42#define CRVML_MCHMAP_SIZE  4096
 43#define CRVML_REG_CLOCK    0xc3c
 44#define CRVML_CLOCK_SHIFT  8
 45#define CRVML_CLOCK_MASK   0x00000f00
 46
 47static struct pci_dev *mch_dev;
 48static u32 mch_bar;
 49static void __iomem *mch_regs_base;
 50static u32 saved_clock;
 51
 52static const unsigned crvml_clocks[] = {
 53        6750,
 54        13500,
 55        27000,
 56        29700,
 57        37125,
 58        54000,
 59        59400,
 60        74250,
 61        120000
 62            /*
 63             * There are more clocks, but they are disabled on the CR board.
 64             */
 65};
 66
 67static const u32 crvml_clock_bits[] = {
 68        0x0a,
 69        0x09,
 70        0x08,
 71        0x07,
 72        0x06,
 73        0x05,
 74        0x04,
 75        0x03,
 76        0x0b
 77};
 78
 79static const unsigned crvml_num_clocks = ARRAY_SIZE(crvml_clocks);
 80
 81static int crvml_sys_restore(struct vml_sys *sys)
 82{
 83        void __iomem *clock_reg = mch_regs_base + CRVML_REG_CLOCK;
 84
 85        iowrite32(saved_clock, clock_reg);
 86        ioread32(clock_reg);
 87
 88        return 0;
 89}
 90
 91static int crvml_sys_save(struct vml_sys *sys)
 92{
 93        void __iomem *clock_reg = mch_regs_base + CRVML_REG_CLOCK;
 94
 95        saved_clock = ioread32(clock_reg);
 96
 97        return 0;
 98}
 99
100static int crvml_nearest_index(const struct vml_sys *sys, int clock)
101{
102        int i;
103        int cur_index = 0;
104        int cur_diff;
105        int diff;
106
107        cur_diff = clock - crvml_clocks[0];
108        cur_diff = (cur_diff < 0) ? -cur_diff : cur_diff;
109        for (i = 1; i < crvml_num_clocks; ++i) {
110                diff = clock - crvml_clocks[i];
111                diff = (diff < 0) ? -diff : diff;
112                if (diff < cur_diff) {
113                        cur_index = i;
114                        cur_diff = diff;
115                }
116        }
117        return cur_index;
118}
119
120static int crvml_nearest_clock(const struct vml_sys *sys, int clock)
121{
122        return crvml_clocks[crvml_nearest_index(sys, clock)];
123}
124
125static int crvml_set_clock(struct vml_sys *sys, int clock)
126{
127        void __iomem *clock_reg = mch_regs_base + CRVML_REG_CLOCK;
128        int index;
129        u32 clock_val;
130
131        index = crvml_nearest_index(sys, clock);
132
133        if (crvml_clocks[index] != clock)
134                return -EINVAL;
135
136        clock_val = ioread32(clock_reg) & ~CRVML_CLOCK_MASK;
137        clock_val = crvml_clock_bits[index] << CRVML_CLOCK_SHIFT;
138        iowrite32(clock_val, clock_reg);
139        ioread32(clock_reg);
140
141        return 0;
142}
143
144static struct vml_sys cr_pll_ops = {
145        .name = "Carillo Ranch",
146        .save = crvml_sys_save,
147        .restore = crvml_sys_restore,
148        .set_clock = crvml_set_clock,
149        .nearest_clock = crvml_nearest_clock,
150};
151
152static int __init cr_pll_init(void)
153{
154        int err;
155        u32 dev_en;
156
157        mch_dev = pci_get_device(PCI_VENDOR_ID_INTEL,
158                                        CRVML_DEVICE_MCH, NULL);
159        if (!mch_dev) {
160                printk(KERN_ERR
161                       "Could not find Carillo Ranch MCH device.\n");
162                return -ENODEV;
163        }
164
165        pci_read_config_dword(mch_dev, CRVML_REG_MCHEN, &dev_en);
166        if (!(dev_en & CRVML_MCHEN_BIT)) {
167                printk(KERN_ERR
168                       "Carillo Ranch MCH device was not enabled.\n");
169                pci_dev_put(mch_dev);
170                return -ENODEV;
171        }
172
173        pci_read_config_dword(mch_dev, CRVML_REG_MCHBAR,
174                              &mch_bar);
175        mch_regs_base =
176            ioremap_nocache(mch_bar, CRVML_MCHMAP_SIZE);
177        if (!mch_regs_base) {
178                printk(KERN_ERR
179                       "Carillo Ranch MCH device was not enabled.\n");
180                pci_dev_put(mch_dev);
181                return -ENODEV;
182        }
183
184        err = vmlfb_register_subsys(&cr_pll_ops);
185        if (err) {
186                printk(KERN_ERR
187                       "Carillo Ranch failed to initialize vml_sys.\n");
188                pci_dev_put(mch_dev);
189                return err;
190        }
191
192        return 0;
193}
194
195static void __exit cr_pll_exit(void)
196{
197        vmlfb_unregister_subsys(&cr_pll_ops);
198
199        iounmap(mch_regs_base);
200        pci_dev_put(mch_dev);
201}
202
203module_init(cr_pll_init);
204module_exit(cr_pll_exit);
205
206MODULE_AUTHOR("Tungsten Graphics Inc.");
207MODULE_DESCRIPTION("Carillo Ranch PLL Driver");
208MODULE_LICENSE("GPL");