⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pmc551.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * $Id: pmc551.c,v 1.11 2000/11/23 13:40:12 dwmw2 Exp $ * * PMC551 PCI Mezzanine Ram Device * * Author: *       Mark Ferrell <mferrell@mvista.com> *       Copyright 1999,2000 Nortel Networks * * License: *	 As part of this driver was derrived from the slram.c driver it falls *	 under the same license, which is GNU General Public License v2 * * Description: *	 This driver is intended to support the PMC551 PCI Ram device from *	 Ramix Inc.  The PMC551 is a PMC Mezzanine module for cPCI embeded *	 systems.  The device contains a single SROM that initally programs the *	 V370PDC chipset onboard the device, and various banks of DRAM/SDRAM *	 onboard.  This driver implements this PCI Ram device as an MTD (Memory *	 Technologies Device) so that it can be used to hold a filesystem, or *	 for added swap space in embeded systems.  Since the memory on this *	 board isn't as fast as main memory we do not try to hook it into main *	 memeory as that would simply reduce performance on the system.  Using *	 it as a block device allows us to use it as high speed swap or for a *	 high speed disk device of some sort.  Which becomes very usefull on *	 diskless systems in the embeded market I might add. *	  * Notes: *	 Due to what I assume is more buggy SROM, the 64M PMC551 I have *	 available claims that all 4 of it's DRAM banks have 64M of ram  *	 configured (making a grand total of 256M onboard).  This is slightly *	 annoying since the BAR0 size reflects the aperture size, not the dram *	 size, and the V370PDC supplies no other method for memory size *	 discovery.  This problem is mostly only relivant when compiled as a *	 module, as the unloading of the module with an aperture size  smaller *	 then the ram will cause the driver to detect the onboard memory size *	 to be equal to the aperture size when the module is reloaded.  Soooo, *	 to help, the module supports an msize option to allow the *	 specification of the onboard memory, and an asize option, to allow the *	 specification of the aperture size.  The aperture must be equal to or *	 less then the memory size, the driver will correct this if you screw *	 it up.  This problem is not relivant for compiled in drivers as *	 compiled in drivers only init once. * * Credits: *       Saeed Karamooz <saeed@ramix.com> of Ramix INC. for the initial *       example code of how to initialize this device and for help with *       questions I had concerning operation of the device. * *       Most of the MTD code for this driver was originally written for the *       slram.o module in the MTD drivers package written by David Hinds *       <dhinds@allegro.stanford.edu> which allows the mapping of system *       memory into an mtd device.  Since the PMC551 memory module is *       accessed in the same fashion as system memory, the slram.c code *       became a very nice fit to the needs of this driver.  All we added was *       PCI detection/initialization to the driver and automaticly figure out *       the size via the PCI detection.o, later changes by Corey Minyard *       settup the card to utilize a 1M sliding apature. * *	 Corey Minyard <minyard@nortelnetworks.com> *       * Modified driver to utilize a sliding apature instead of mapping all *       memory into kernel space which turned out to be very wastefull. *       * Located a bug in the SROM's initialization sequence that made the *       memory unusable, added a fix to code to touch up the DRAM some. * * Bugs/FIXME's: *       * MUST fix the init function to not spin on a register *       waiting for it to set .. this does not safely handle busted devices *       that never reset the register correctly which will cause the system to *       hang w/ a reboot beeing the only chance at recover. */#include <linux/config.h>#include <linux/kernel.h>#include <linux/module.h>#include <asm/uaccess.h>#include <linux/types.h>#include <linux/sched.h>#include <linux/init.h>#include <linux/ptrace.h>#include <linux/malloc.h>#include <linux/string.h>#include <linux/timer.h>#include <linux/major.h>#include <linux/fs.h>#include <linux/ioctl.h>#include <asm/io.h>#include <asm/system.h>#include <asm/segment.h>#include <stdarg.h>#include <linux/pci.h>#ifndef CONFIG_PCI#error Enable PCI in your kernel config#endif#include <linux/mtd/mtd.h>#include <linux/mtd/pmc551.h>#include <linux/mtd/compatmac.h>#if LINUX_VERSION_CODE > 0x20300#define PCI_BASE_ADDRESS(dev) (dev->resource[0].start)#else#define PCI_BASE_ADDRESS(dev) (dev->base_address[0])#endifstatic struct mtd_info *pmc551list = NULL;static int pmc551_erase (struct mtd_info *mtd, struct erase_info *instr){        struct mypriv *priv = mtd->priv;        u32 start_addr_highbits;        u32 end_addr_highbits;        u32 start_addr_lowbits;        u32 end_addr_lowbits;        unsigned long end;        end = instr->addr + instr->len;        /* Is it too much memory?  The second check find if we wrap around           past the end of a u32. */        if ((end > mtd->size) || (end < instr->addr)) {                return -EINVAL;        }        start_addr_highbits = instr->addr & PMC551_ADDR_HIGH_MASK;        end_addr_highbits = end & PMC551_ADDR_HIGH_MASK;        start_addr_lowbits = instr->addr & PMC551_ADDR_LOW_MASK;        end_addr_lowbits = end & PMC551_ADDR_LOW_MASK;        pci_write_config_dword ( priv->dev,                                 PMC551_PCI_MEM_MAP0,                                 (priv->mem_map0_base_val                                  | start_addr_highbits));        if (start_addr_highbits == end_addr_highbits) {                /* The whole thing fits within one access, so just one shot                   will do it. */                memset(priv->start + start_addr_lowbits,                       0xff,                       instr->len);        } else {                /* We have to do multiple writes to get all the data                   written. */                memset(priv->start + start_addr_lowbits,                       0xff,                       priv->aperture_size - start_addr_lowbits);                start_addr_highbits += priv->aperture_size;                while (start_addr_highbits != end_addr_highbits) {                        pci_write_config_dword ( priv->dev,                                                 PMC551_PCI_MEM_MAP0,                                                 (priv->mem_map0_base_val                                                  | start_addr_highbits));                        memset(priv->start,                               0xff,                               priv->aperture_size);                        start_addr_highbits += priv->aperture_size;                }                priv->curr_mem_map0_val = (priv->mem_map0_base_val                                           | start_addr_highbits);                pci_write_config_dword ( priv->dev,                                         PMC551_PCI_MEM_MAP0,                                         priv->curr_mem_map0_val);                memset(priv->start,                       0xff,                       end_addr_lowbits);        }	instr->state = MTD_ERASE_DONE;        if (instr->callback) {                (*(instr->callback))(instr);	}        return 0;}static void pmc551_unpoint (struct mtd_info *mtd, u_char *addr){}static int pmc551_read (struct mtd_info *mtd,                        loff_t from,                        size_t len,                        size_t *retlen,                        u_char *buf){        struct mypriv *priv = (struct mypriv *)mtd->priv;        u32 start_addr_highbits;        u32 end_addr_highbits;        u32 start_addr_lowbits;        u32 end_addr_lowbits;        unsigned long end;        u_char *copyto = buf;        /* Is it past the end? */        if (from > mtd->size) {                return -EINVAL;        }        end = from + len;        start_addr_highbits = from & PMC551_ADDR_HIGH_MASK;        end_addr_highbits = end & PMC551_ADDR_HIGH_MASK;        start_addr_lowbits = from & PMC551_ADDR_LOW_MASK;        end_addr_lowbits = end & PMC551_ADDR_LOW_MASK;        /* Only rewrite the first value if it doesn't match our current           values.  Most operations are on the same page as the previous           value, so this is a pretty good optimization. */        if (priv->curr_mem_map0_val !=                        (priv->mem_map0_base_val | start_addr_highbits)) {                priv->curr_mem_map0_val = (priv->mem_map0_base_val                                           | start_addr_highbits);                pci_write_config_dword ( priv->dev,                                         PMC551_PCI_MEM_MAP0,                                         priv->curr_mem_map0_val);        }        if (start_addr_highbits == end_addr_highbits) {                /* The whole thing fits within one access, so just one shot                   will do it. */                memcpy(copyto,                       priv->start + start_addr_lowbits,                       len);                copyto += len;        } else {                /* We have to do multiple writes to get all the data                   written. */                memcpy(copyto,                       priv->start + start_addr_lowbits,                       priv->aperture_size - start_addr_lowbits);                copyto += priv->aperture_size - start_addr_lowbits;                start_addr_highbits += priv->aperture_size;                while (start_addr_highbits != end_addr_highbits) {                        pci_write_config_dword ( priv->dev,                                                 PMC551_PCI_MEM_MAP0,                                                 (priv->mem_map0_base_val                                                  | start_addr_highbits));                        memcpy(copyto,                               priv->start,                               priv->aperture_size);                        copyto += priv->aperture_size;                        start_addr_highbits += priv->aperture_size;                        if (start_addr_highbits >= mtd->size) {                                /* Make sure we have the right value here. */                                priv->curr_mem_map0_val                                = (priv->mem_map0_base_val                                   | start_addr_highbits);                                goto out;                        }                }                priv->curr_mem_map0_val = (priv->mem_map0_base_val                                           | start_addr_highbits);                pci_write_config_dword ( priv->dev,                                         PMC551_PCI_MEM_MAP0,                                         priv->curr_mem_map0_val);                memcpy(copyto,                       priv->start,                       end_addr_lowbits);                copyto += end_addr_lowbits;        }out:        *retlen = copyto - buf;        return 0;}static int pmc551_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf){        struct mypriv *priv = (struct mypriv *)mtd->priv;        u32 start_addr_highbits;        u32 end_addr_highbits;        u32 start_addr_lowbits;        u32 end_addr_lowbits;        unsigned long end;        const u_char *copyfrom = buf;        /* Is it past the end? */        if (to > mtd->size) {                return -EINVAL;        }        end = to + len;        start_addr_highbits = to & PMC551_ADDR_HIGH_MASK;        end_addr_highbits = end & PMC551_ADDR_HIGH_MASK;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -