📄 ops-pmcmsp.c
字号:
/* * PMC-Sierra MSP board specific pci_ops * * Copyright 2001 MontaVista Software Inc. * Copyright 2005-2007 PMC-Sierra, Inc * * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net * * Much of the code is derived from the original DDB5074 port by * Geert Uytterhoeven <geert@sonycom.com> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * */#define PCI_COUNTERS 1#include <linux/types.h>#include <linux/pci.h>#include <linux/interrupt.h>#if defined(CONFIG_PROC_FS) && defined(PCI_COUNTERS)#include <linux/proc_fs.h>#include <linux/seq_file.h>#endif /* CONFIG_PROC_FS && PCI_COUNTERS */#include <linux/kernel.h>#include <linux/init.h>#include <asm/byteorder.h>#if defined(CONFIG_PMC_MSP7120_GW) || defined(CONFIG_PMC_MSP7120_EVAL)#include <asm/mipsmtregs.h>#endif#include <msp_prom.h>#include <msp_cic_int.h>#include <msp_pci.h>#include <msp_regs.h>#include <msp_regops.h>#define PCI_ACCESS_READ 0#define PCI_ACCESS_WRITE 1#if defined(CONFIG_PROC_FS) && defined(PCI_COUNTERS)static char proc_init;extern struct proc_dir_entry *proc_bus_pci_dir;unsigned int pci_int_count[32];static void pci_proc_init(void);/***************************************************************************** * * FUNCTION: read_msp_pci_counts * _________________________________________________________________________ * * DESCRIPTION: Prints the count of how many times each PCI * interrupt has asserted. Can be invoked by the * /proc filesystem. * * INPUTS: page - part of STDOUT calculation * off - part of STDOUT calculation * count - part of STDOUT calculation * data - unused * * OUTPUTS: start - new start location * eof - end of file pointer * * RETURNS: len - STDOUT length * ****************************************************************************/static int read_msp_pci_counts(char *page, char **start, off_t off, int count, int *eof, void *data){ int i; int len = 0; unsigned int intcount, total = 0; for (i = 0; i < 32; ++i) { intcount = pci_int_count[i]; if (intcount != 0) { len += sprintf(page + len, "[%d] = %u\n", i, intcount); total += intcount; } } len += sprintf(page + len, "total = %u\n", total); if (len <= off+count) *eof = 1; *start = page + off; len -= off; if (len > count) len = count; if (len < 0) len = 0; return len;}/***************************************************************************** * * FUNCTION: gen_pci_cfg_wr * _________________________________________________________________________ * * DESCRIPTION: Generates a configuration write cycle for debug purposes. * The IDSEL line asserted and location and data written are * immaterial. Just want to be able to prove that a * configuration write can be correctly generated on the * PCI bus. Intent is that this function by invocable from * the /proc filesystem. * * INPUTS: page - part of STDOUT calculation * off - part of STDOUT calculation * count - part of STDOUT calculation * data - unused * * OUTPUTS: start - new start location * eof - end of file pointer * * RETURNS: len - STDOUT length * ****************************************************************************/static int gen_pci_cfg_wr(char *page, char **start, off_t off, int count, int *eof, void *data){ unsigned char where = 0; /* Write to static Device/Vendor ID */ unsigned char bus_num = 0; /* Bus 0 */ unsigned char dev_fn = 0xF; /* Arbitrary device number */ u32 wr_data = 0xFF00AA00; /* Arbitrary data */ struct msp_pci_regs *preg = (void *)PCI_BASE_REG; int len = 0; unsigned long value; int intr; len += sprintf(page + len, "PMC MSP PCI: Beginning\n"); if (proc_init == 0) { pci_proc_init(); proc_init = ~0; } len += sprintf(page + len, "PMC MSP PCI: Before Cfg Wr\n"); /* * Generate PCI Configuration Write Cycle */ /* Clear cause register bits */ preg->if_status = ~(BPCI_IFSTATUS_BC0F | BPCI_IFSTATUS_BC1F); /* Setup address that is to appear on PCI bus */ preg->config_addr = BPCI_CFGADDR_ENABLE | (bus_num << BPCI_CFGADDR_BUSNUM_SHF) | (dev_fn << BPCI_CFGADDR_FUNCTNUM_SHF) | (where & 0xFC); value = cpu_to_le32(wr_data); /* Launch the PCI configuration write cycle */ *PCI_CONFIG_SPACE_REG = value; /* * Check if the PCI configuration cycle (rd or wr) succeeded, by * checking the status bits for errors like master or target abort. */ intr = preg->if_status; len += sprintf(page + len, "PMC MSP PCI: After Cfg Wr\n"); /* Handle STDOUT calculations */ if (len <= off+count) *eof = 1; *start = page + off; len -= off; if (len > count) len = count; if (len < 0) len = 0; return len;}/***************************************************************************** * * FUNCTION: pci_proc_init * _________________________________________________________________________ * * DESCRIPTION: Create entries in the /proc filesystem for debug access. * * INPUTS: none * * OUTPUTS: none * * RETURNS: none * ****************************************************************************/static void pci_proc_init(void){ create_proc_read_entry("pmc_msp_pci_rd_cnt", 0, NULL, read_msp_pci_counts, NULL); create_proc_read_entry("pmc_msp_pci_cfg_wr", 0, NULL, gen_pci_cfg_wr, NULL);}#endif /* CONFIG_PROC_FS && PCI_COUNTERS */DEFINE_SPINLOCK(bpci_lock);/***************************************************************************** * * STRUCT: pci_io_resource * _________________________________________________________________________ * * DESCRIPTION: Defines the address range that pciauto() will use to * assign to the I/O BARs of PCI devices. * * Use the start and end addresses of the MSP7120 PCI Host * Controller I/O space, in the form that they appear on the * PCI bus AFTER MSP7120 has performed address translation. * * For I/O accesses, MSP7120 ignores OATRAN and maps I/O * accesses into the bottom 0xFFF region of address space, * so that is the range to put into the pci_io_resource * struct. * * In MSP4200, the start address was 0x04 instead of the * expected 0x00. Will just assume there was a good reason * for this! * * NOTES: Linux, by default, will assign I/O space to the lowest * region of address space. Since MSP7120 and Linux, * by default, have no offset in between how they map, the * io_offset element of pci_controller struct should be set * to zero. * ELEMENTS: * name - String used for a meaningful name. * * start - Start address of MSP7120's I/O space, as MSP7120 presents * the address on the PCI bus. * * end - End address of MSP7120's I/O space, as MSP7120 presents * the address on the PCI bus. * * flags - Attributes indicating the type of resource. In this case, * indicate I/O space. * ****************************************************************************/static struct resource pci_io_resource = { .name = "pci IO space", .start = 0x04, .end = 0x0FFF, .flags = IORESOURCE_IO /* I/O space */};/***************************************************************************** * * STRUCT: pci_mem_resource * _________________________________________________________________________ * * DESCRIPTION: Defines the address range that pciauto() will use to * assign to the memory BARs of PCI devices. * * The .start and .end values are dependent upon how address * translation is performed by the OATRAN regiser. * * The values to use for .start and .end are the values * in the form they appear on the PCI bus AFTER MSP7120 has * performed OATRAN address translation. * * ELEMENTS: * name - String used for a meaningful name. * * start - Start address of MSP7120's memory space, as MSP7120 presents * the address on the PCI bus. * * end - End address of MSP7120's memory space, as MSP7120 presents * the address on the PCI bus. * * flags - Attributes indicating the type of resource. In this case, * indicate memory space. * ****************************************************************************/static struct resource pci_mem_resource = { .name = "pci memory space", .start = MSP_PCI_SPACE_BASE, .end = MSP_PCI_SPACE_END, .flags = IORESOURCE_MEM /* memory space */};/***************************************************************************** * * FUNCTION: bpci_interrupt * _________________________________________________________________________ * * DESCRIPTION: PCI status interrupt handler. Updates the count of how * many times each status bit has been set, then clears * the status bits. If the appropriate macros are defined, * these counts can be viewed via the /proc filesystem. * * INPUTS: irq - unused * dev_id - unused * pt_regs - unused * * OUTPUTS: none * * RETURNS: PCIBIOS_SUCCESSFUL - success * ****************************************************************************/static int bpci_interrupt(int irq, void *dev_id){ struct msp_pci_regs *preg = (void *)PCI_BASE_REG; unsigned int stat = preg->if_status;#if defined(CONFIG_PROC_FS) && defined(PCI_COUNTERS) int i; for (i = 0; i < 32; ++i) { if ((1 << i) & stat) ++pci_int_count[i]; }#endif /* PROC_FS && PCI_COUNTERS */ /* printk("PCI ISR: Status=%08X\n", stat); */ /* write to clear all asserted interrupts */ preg->if_status = stat; return PCIBIOS_SUCCESSFUL;}/*****************************************************************************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -