📄 pci-sd0001.c
字号:
/* * $Id: pci-sd0001.c,v 1.1.2.1 2003/06/24 08:40:50 dwmw2 Exp $ * * linux/arch/sh/kernel/pci-sd0001.c * * Support Hitachi Semcon SD0001 SH3 PCI Host Bridge . * * * Copyright (C) 2000 Hitachi ULSI Systems Co., Ltd. * All Rights Reserved. * * Copyright (C) 2001-2003 Red Hat, Inc. * * Authors: Masayuki Okada (macha@adc.hitachi-ul.co.jp) * David Woodhouse (dwmw2@redhat.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, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include <linux/init.h>#include <linux/pci.h>#include <linux/kernel.h>#include <linux/irq.h>#include <linux/interrupt.h>#include <linux/spinlock.h>#include <linux/delay.h>#include <linux/vmalloc.h>#include <asm/pci.h>#include <asm/io.h>#include <asm/irq.h>#include "pci-sd0001.h"spinlock_t sd0001_indirect_lock = SPIN_LOCK_UNLOCKED;int remap_area_pages(unsigned long address, unsigned long phys_addr, unsigned long size, unsigned long flags);#undef DEBUG#ifdef DEBUG#define DBG(x...) printk(x)#else#define DBG(x...)#endif#define SD0001_INDIR_TIME 1000000 /* 粗儡アクセス窗位略ち呵络搀眶 */static char *err_int_msg [] = { "Detect Master Abort", "Assert Master Abort", "Detect Target Abort", "Assert Target Abort", "Assert PERR", "Detect PERR", "Detect SERR", "Asster SERR", "Bus Timeout", "Bus Retry Over",};/* * PCIバスのバスリセット悸乖 */static void sd0001_bus_reset(void){ sd0001_writel(SD0001_RST_BUSRST, RESET); udelay(64); sd0001_writel(0, RESET);}/* * SD0001ソフトリセット */static void sd0001_chip_reset(void){ sd0001_writel(SD0001_RST_SWRST, RESET);}#define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1))static voidsd0001_int_pcierr (int irq, void *dummy, struct pt_regs *regs){ static char errStrings[30*12]; u32 int_status; u32 mask; u32 indrct_flg; int reset_fatal; int i; int to_cnt = 0; unsigned long flags; spin_lock_irqsave(&sd0001_indirect_lock, flags); if ((int_status = (sd0001_readl(INT_STS1) & SD0001_INT_BUSERR))) { DBG("pciIntErrorHandle Called: status 0x%08x\n", int_status, 0, 0, 0, 0, 0); for (mask = 1 << 20, i = 0, errStrings[0] = '\0'; i < 11; i++, mask <<= 1) { if (int_status & mask) {/* err_int_cnt[i] ++; */ strcat(errStrings, err_int_msg[i]); strcat(errStrings, ", "); } } i = strlen(errStrings); errStrings[i-2]= '\0'; printk(KERN_ERR "PCI Bus 0x%08x(%s) Error\n", int_status, errStrings); reset_fatal = 0; if (int_status & (SD0001_INT_SSERR|SD0001_INT_RPERR |SD0001_INT_SPERR|SD0001_INT_STABT |SD0001_INT_RTABT|SD0001_INT_RMABT)) { /* Clear of Configration Status Bits */ sd0001_writel(4, INDIRECT_ADR); sd0001_writel(0xf9000000, INDIRECT_DATA); sd0001_writel(0x000c0002, INDIRECT_CTL); to_cnt = 0; while (((indrct_flg = sd0001_readl(INDIRECT_STS)) & SD0001_INDRCTF_INDFLG) && (to_cnt++ < SD0001_INDIR_TIME)) ; if (indrct_flg & SD0001_INDRCTF_INDFLG) { panic("SD0001 Fatal Error 1\n"); } else { if (indrct_flg & SD0001_INDRCTF_MABTRCV) { sd0001_writel(SD0001_INDRCTC_FLGRESET, INDIRECT_CTL); reset_fatal = -1; } } int_status = sd0001_readl(INT_STS1) & SD0001_INT_BUSERR; } if (int_status != 0) { sd0001_writel(int_status, INT_STS1); /* 充り哈みクリア */ if (reset_fatal || (sd0001_readl(INT_STS2) & SD0001_INT_BUSERR)) { printk(KERN_CRIT "Fatal Error:SD0001 PCI Status Can't Clear 0x%08x\n", int_status & 0x7fffffff); sd0001_writel(sd0001_readl(INT_ENABLE) & ~int_status, INT_ENABLE); /* Masked Error Interrupt */ } } } spin_unlock_irqrestore(&sd0001_indirect_lock, flags);}static inline u32 convert_dev_to_addr (struct pci_dev *dev, u32 reg){ return (SD0001_CONFIG_ADDR_EN | (dev->bus->number << 16) | ((dev->devfn & 0xff) << 8) | (reg & 0xff) | ((dev->bus->number)?0x00:0x01));}static int sd0001_indirect_RW (u32 addr, u32 cmd, u32 be, u32 rw, u32 *data){ u32 indrct_flg; u32 int_sts; u32 to_cnt = 0; int st = PCIBIOS_SUCCESSFUL; unsigned long flags; spin_lock_irqsave(&sd0001_indirect_lock, flags); if ((cmd & SD0001_INDRCTC_CMD_MASK) == SD0001_INDRCTC_CMD_MEMR || (cmd & SD0001_INDRCTC_CMD_MASK) == SD0001_INDRCTC_CMD_MEMW) sd0001_writel(addr & 0xfffffffc, INDIRECT_ADR); else sd0001_writel(addr, INDIRECT_ADR); if (rw == SD0001_INDRCTC_IOWT || rw == SD0001_INDRCTC_COWT) sd0001_writel(*data, INDIRECT_DATA); sd0001_writel(be | cmd | rw , INDIRECT_CTL); while (((indrct_flg = sd0001_readl(INDIRECT_STS)) & SD0001_INDRCTF_INDFLG) && (to_cnt++ < SD0001_INDIR_TIME)); int_sts = sd0001_readl(INT_STS1) & SD0001_INT_BUSERR; if (indrct_flg & SD0001_INDRCTF_INDFLG) { /* タイムアウト */ printk("SD0001 Fatal Error 2\n"); spin_unlock_irqrestore(&sd0001_indirect_lock, flags); return PCIBIOS_DEVICE_NOT_FOUND; } if (int_sts != 0 || (indrct_flg & SD0001_INDRCTF_MABTRCV) != 0) { if ((st = (indrct_flg & SD0001_INDRCTF_MABTRCV) >> 19) != 0) { sd0001_writel(SD0001_INDRCTC_FLGRESET, INDIRECT_CTL); st |= 0x80000000; } st |= 0x80000000 | int_sts; if ((int_sts & (SD0001_INT_SSERR|SD0001_INT_RPERR |SD0001_INT_SPERR|SD0001_INT_STABT |SD0001_INT_RTABT|SD0001_INT_RMABT)) || (indrct_flg & SD0001_INDRCTF_MABTRCV)) { /* Clear of Configration Status Bits */ sd0001_writel(4, INDIRECT_ADR); sd0001_writel(0xf9000000, INDIRECT_DATA); sd0001_writel(0x000c0002, INDIRECT_CTL); to_cnt = 0; while (((indrct_flg = sd0001_readl(INDIRECT_STS)) & SD0001_INDRCTF_INDFLG) && (to_cnt++ < SD0001_INDIR_TIME)); if (indrct_flg & SD0001_INDRCTF_INDFLG) { /* タイムアウト */ panic("SD0001 Fatal Error 3\n"); } if (indrct_flg & SD0001_INDRCTF_MABTRCV) { sd0001_writel(SD0001_INDRCTC_FLGRESET, INDIRECT_CTL); } } printk(KERN_ERR "PCI Bus Error: status 0x%08x\n", st); if ((int_sts = sd0001_readl(INT_STS1) & SD0001_INT_BUSERR) != 0) { sd0001_writel(int_sts, INT_STS1); /* 充り哈みクリア */ if (sd0001_readl(INT_STS2) & SD0001_INT_BUSERR) { printk(KERN_CRIT "Fatal Error:SD0001 PCI Status Can't Clear 0x%08x\n", sd0001_readl(INT_STS2) & SD0001_INT_BUSERR); sd0001_writel(sd0001_readl(INT_ENABLE) & ~int_sts, INT_ENABLE); /* Masked Error Interrupt */ } } *data = 0xffffffff; } else { if (rw != SD0001_INDRCTC_IOWT && rw != SD0001_INDRCTC_COWT) *data = sd0001_readl(INDIRECT_DATA); } spin_unlock_irqrestore(&sd0001_indirect_lock, flags); return st;}static inlineint sd0001_config_RW (struct pci_dev *dev, u32 reg, u32 be, u32 rw, u32 *data){ u32 reg_addr = convert_dev_to_addr(dev, reg); if (reg_addr == 0) { *data = 0xffffffff; return PCIBIOS_SUCCESSFUL; } return sd0001_indirect_RW (reg_addr, 0, be, rw, data);}static int sd0001_read_config_byte(struct pci_dev *dev, int reg, u8 *val){ int offset; u32 be; int re; union { u32 ldata; u8 bdata[4]; } work; be = SD0001_INDRCTC_BE_BYTE << (reg & 0x03); re = sd0001_config_RW (dev, reg, be, SD0001_INDRCTC_CORD, &work.ldata);#if __LITTLE_ENDIAN__ offset = reg & 0x03;#else /* __LITTLE_ENDIAN__ */ offset = 3 - (reg & 0x03);#endif /* __LITTLE_ENDIAN__ */ *val = work.bdata[offset]; return re;}static int sd0001_read_config_word(struct pci_dev *dev, int reg, u16 *val){ int offset; u32 be; int re; union { u32 ldata; u16 wdata[2]; } work; be = SD0001_INDRCTC_BE_WORD << (reg & 0x02); re = sd0001_config_RW (dev, reg, be, SD0001_INDRCTC_CORD, &work.ldata); #if __LITTLE_ENDIAN__ offset = (reg >> 1) & 0x01;#else /* __LITTLE_ENDIAN__ */ offset = 1 - ((reg >> 1) & 0x01);#endif /* __LITTLE_ENDIAN__ */ *val = work.wdata[offset]; return re;}static int sd0001_read_config_dword(struct pci_dev *dev, int reg, u32 *val){ return sd0001_config_RW (dev, reg, SD0001_INDRCTC_BE_LONG, SD0001_INDRCTC_CORD, val);}static int sd0001_write_config_byte (struct pci_dev *dev, int reg, u8 val){ int offset; u32 be; union { u32 ldata; u8 bdata[4]; } work; be = SD0001_INDRCTC_BE_BYTE << (reg & 0x03);#if __LITTLE_ENDIAN__ offset = reg & 0x03;#else /* __LITTLE_ENDIAN__ */ offset = 3 - (reg & 0x03);#endif /* __LITTLE_ENDIAN__ */ work.bdata[offset] = val; return sd0001_config_RW(dev, reg, be, SD0001_INDRCTC_COWT, &work.ldata); }static int sd0001_write_config_word (struct pci_dev *dev, int reg, u16 val){ int offset; u32 be; union { u32 ldata; u16 wdata[2]; } work; be = SD0001_INDRCTC_BE_WORD << (reg & 0x02);#if __LITTLE_ENDIAN__ offset = (reg >> 1) & 0x01;#else /* __LITTLE_ENDIAN__ */ offset = 1 - ((reg >> 1) & 0x01);#endif /* __LITTLE_ENDIAN__ */ work.wdata[offset] = val; return sd0001_config_RW (dev, reg, be, SD0001_INDRCTC_COWT, &work.ldata);}static int sd0001_write_config_dword (struct pci_dev *dev, int reg, u32 val){ return sd0001_config_RW (dev, reg, SD0001_INDRCTC_BE_LONG, SD0001_INDRCTC_COWT, &val);}static struct pci_ops sd0001_pci_ops = { .read_byte = sd0001_read_config_byte, .read_word = sd0001_read_config_word, .read_dword = sd0001_read_config_dword, .write_byte = sd0001_write_config_byte, .write_word = sd0001_write_config_word, .write_dword = sd0001_write_config_dword};int __init pci_setup_sd0001 (void)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -