📄 lba_pci.c
字号:
DBG_PORT(KERN_DEBUG "%s(0x%p, 0x%x, 0x%x)\n", __FUNCTION__, d, addr, val); \ WRITE_REG##size(val, LBA_ASTRO_PORT_BASE + addr); \ if (LBA_DEV(d)->hw_rev < 3) \ lba_t32 = READ_U32(d->base_addr + LBA_FUNC_ID); \}LBA_PORT_OUT( 8, 3)LBA_PORT_OUT(16, 2)LBA_PORT_OUT(32, 0)static struct pci_port_ops lba_astro_port_ops = { lba_astro_in8, lba_astro_in16, lba_astro_in32, lba_astro_out8, lba_astro_out16, lba_astro_out32};#ifdef __LP64__#define PIOP_TO_GMMIO(lba, addr) \ ((lba)->iop_base + (((addr)&0xFFFC)<<10) + ((addr)&3))/*********************************************************** LBA PAT "I/O Port" Space Accessor Functions**** This set of accessor functions is intended for use with** "PAT PDC" firmware (ie Prelude/Rhapsody/Piranha boxes).**** This uses the PIOP space located in the first 64MB of GMMIO.** Each rope gets a full 64*KB* (ie 4 bytes per page) this way.** bits 1:0 stay the same. bits 15:2 become 25:12.** Then add the base and we can generate an I/O Port cycle.********************************************************/#undef LBA_PORT_IN#define LBA_PORT_IN(size, mask) \static u##size lba_pat_in##size (struct pci_hba_data *l, u16 addr) \{ \ u##size t; \ ASSERT(bus != NULL); \ DBG_PORT(KERN_DEBUG "%s(0x%p, 0x%x) ->", __FUNCTION__, l, addr); \ t = READ_REG##size(PIOP_TO_GMMIO(LBA_DEV(l), addr)); \ DBG_PORT(" 0x%x\n", t); \ return (t); \}LBA_PORT_IN( 8, 3)LBA_PORT_IN(16, 2)LBA_PORT_IN(32, 0)#undef LBA_PORT_OUT#define LBA_PORT_OUT(size, mask) \static void lba_pat_out##size (struct pci_hba_data *l, u16 addr, u##size val) \{ \ void *where = (void *) PIOP_TO_GMMIO(LBA_DEV(l), addr); \ ASSERT(bus != NULL); \ DBG_PORT(KERN_DEBUG "%s(0x%p, 0x%x, 0x%x)\n", __FUNCTION__, l, addr, val); \ WRITE_REG##size(val, where); \ /* flush the I/O down to the elroy at least */ \ lba_t32 = READ_U32(l->base_addr + LBA_FUNC_ID); \}LBA_PORT_OUT( 8, 3)LBA_PORT_OUT(16, 2)LBA_PORT_OUT(32, 0)static struct pci_port_ops lba_pat_port_ops = { lba_pat_in8, lba_pat_in16, lba_pat_in32, lba_pat_out8, lba_pat_out16, lba_pat_out32};/*** make range information from PDC available to PCI subsystem.** We make the PDC call here in order to get the PCI bus range** numbers. The rest will get forwarded in pcibios_fixup_bus().** We don't have a struct pci_bus assigned to us yet.*/static voidlba_pat_resources( struct hp_device *d, struct lba_device *lba_dev){ pdc_pat_cell_mod_maddr_block_t pa_pdc_cell; /* PA_VIEW */#ifdef DONT_NEED_THIS_FOR_ASTRO pdc_pat_cell_mod_maddr_block_t io_pdc_cell; /* IO_VIEW */ long io_count;#endif long status; /* PDC return status */ long pa_count; int i; /* return cell module (IO view) */ status = pdc_pat_cell_module(& pdc_result, d->pcell_loc, d->mod_index, PA_VIEW, & pa_pdc_cell); pa_count = pa_pdc_cell.mod[1];#ifdef DONT_NEED_THIS_FOR_ASTRO status |= pdc_pat_cell_module(& pdc_result, d->pcell_loc, d->mod_index, IO_VIEW, & io_pdc_cell); io_count = io_pdc_cell.mod[1];#endif /* We've already done this once for device discovery...*/ if (status != PDC_RET_OK) { panic("pdc_pat_cell_module() call failed for LBA!\n"); } if (PAT_GET_ENTITY(pa_pdc_cell.mod_info) != PAT_ENTITY_LBA) { panic("pdc_pat_cell_module() entity returned != PAT_ENTITY_LBA!\n"); } /* ** Inspect the resources PAT tells us about */ for (i = 0; i < pa_count; i++) { struct { unsigned long type; unsigned long start; unsigned long end; /* aka finish */ } *p; struct resource *r; p = (void *) &(pa_pdc_cell.mod[2+i*3]); /* Convert the PAT range data to PCI "struct resource" */ switch(p->type & 0xff) { case PAT_PBNUM: lba_dev->hba.bus_num.start = p->start; lba_dev->hba.bus_num.end = p->end; break; case PAT_LMMIO: /* used to fix up pre-initialized MEM BARs */ lba_dev->lmmio_base = p->start; r = &(lba_dev->hba.mem_space); r->name = "LBA LMMIO"; r->start = p->start; r->end = p->end; r->flags = IORESOURCE_MEM; r->parent = r->sibling = r->child = NULL; break; case PAT_GMMIO: printk(KERN_WARNING MODULE_NAME " range[%d] : ignoring GMMIO (0x%lx)\n", i, p->start); lba_dev->gmmio_base = p->start; break; case PAT_NPIOP: printk(KERN_WARNING MODULE_NAME " range[%d] : ignoring NPIOP (0x%lx)\n", i, p->start); break; case PAT_PIOP: /* ** Postable I/O port space is per PCI host adapter. */ /* save base of 64MB PIOP region */ lba_dev->iop_base = p->start; r = &(lba_dev->hba.io_space); r->name = "LBA I/O Port"; r->start = lba_dev->hba.hba_num << 16; r->end = r->start + 0xffffUL; r->flags = IORESOURCE_IO; r->parent = r->sibling = r->child = NULL; break; default: printk(KERN_WARNING MODULE_NAME " range[%d] : unknown pat range type (0x%lx)\n", i, p->type & 0xff); break; } }}#endif /* __LP64__ */static voidlba_legacy_resources( struct hp_device *d, struct lba_device *lba_dev){ int lba_num; struct resource *r;#ifdef __LP64__ /* ** Used to sign extend instead BAR values are only 32-bit. ** 64-bit BARs have the upper 32-bit's zero'd by firmware. ** "Sprockets" PDC initializes for 32-bit OS. */ lba_dev->lmmio_base = 0xffffffff00000000UL;#endif /* ** With "legacy" firmware, the lowest byte of FW_SCRATCH ** represents bus->secondary and the second byte represents ** bus->subsidiary (i.e. highest PPB programmed by firmware). ** PCI bus walk *should* end up with the same result. ** FIXME: But we don't have sanity checks in PCI or LBA. */ lba_num = READ_REG32(d->hpa + LBA_FW_SCRATCH); r = &(lba_dev->hba.bus_num); r->name = "LBA PCI Busses"; r->start = lba_num & 0xff; r->end = (lba_num>>8) & 0xff; /* Set up local PCI Bus resources - we don't really need ** them for Legacy boxes but it's nice to see in /proc. */ r = &(lba_dev->hba.mem_space); r->name = "LBA PCI LMMIO"; r->flags = IORESOURCE_MEM; r->start = READ_REG32(d->hpa + LBA_LMMIO_BASE); r->end = r->start + ~ (READ_REG32(d->hpa + LBA_LMMIO_MASK)); r = &(lba_dev->hba.io_space); r->name = "LBA PCI I/O Ports"; r->flags = IORESOURCE_IO; r->start = READ_REG32(d->hpa + LBA_IOS_BASE); r->end = r->start + (READ_REG32(d->hpa + LBA_IOS_MASK) ^ 0xffff); lba_num = lba_dev->hba.hba_num << 16; r->start |= lba_num; r->end |= lba_num;}/****************************************************************************** LBA initialization code (HW and SW)**** o identify LBA chip itself** o initialize LBA chip modes (HardFail)** o FIXME: initialize DMA hints for reasonable defaults** o enable configuration functions** o call pci_register_ops() to discover devs (fixup/fixup_bus get invoked)****************************************************************************/static voidlba_hw_init(struct lba_device *d){ u32 stat; /* Set HF mode as the default (vs. -1 mode). */ stat = READ_REG32(d->hba.base_addr + LBA_STAT_CTL); WRITE_REG32(stat | HF_ENABLE, d->hba.base_addr + LBA_STAT_CTL); /* ** FIXME: Hint registers are programmed with default hint ** values by firmware. Hints should be sane even if we ** can't reprogram them the way drivers want. */}static voidlba_common_init(struct lba_device *lba_dev){ pci_bios = &lba_bios_ops; pcibios_register_hba((struct pci_hba_data *)lba_dev); lba_dev->lba_lock = SPIN_LOCK_UNLOCKED; /* ** Set flags which depend on hw_rev */ if (!LBA_TR4PLUS(lba_dev)) { lba_dev->flags |= LBA_FLAG_NO_DMA_DURING_CFG; }}/*** Determine if lba should claim this chip (return 0) or not (return 1).** If so, initialize the chip and tell other partners in crime they** have work to do.*/static __init intlba_driver_callback(struct hp_device *d, struct pa_iodc_driver *dri){ struct lba_device *lba_dev; struct pci_bus *lba_bus; u32 func_class; void *tmp_obj; /* from drivers/pci/setup-bus.c */ extern void __init pbus_set_ranges(struct pci_bus *, struct pbus_set_ranges_data *); /* Read HW Rev First */ func_class = READ_REG32(d->hpa + LBA_FCLASS); func_class &= 0xf; switch (func_class) { case 0: dri->version = "TR1.0"; break; case 1: dri->version = "TR2.0"; break; case 2: dri->version = "TR2.1"; break; case 3: dri->version = "TR2.2"; break; case 4: dri->version = "TR3.0"; break; case 5: dri->version = "TR4.0"; break; default: dri->version = "TR4+"; } printk("%s version %s (0x%x) found at 0x%p\n", dri->name, dri->version, func_class & 0xf, d->hpa); /* Just in case we find some prototypes... */ if (func_class < 2) { printk(KERN_WARNING "Can't support LBA older than TR2.1 " "- continuing under adversity.\n"); } /* ** Tell I/O SAPIC driver we have a IRQ handler/region. */ tmp_obj = iosapic_register(d->hpa+LBA_IOSAPIC_BASE); if (NULL == tmp_obj) { /* iosapic may have failed. But more likely the ** slot isn't occupied and thus has no IRT entries. ** iosapic_register looks for this iosapic in the IRT ** before bothering to allocating data structures ** we don't need. */ DBG(KERN_WARNING MODULE_NAME ": iosapic_register says not used\n"); return (1); } lba_dev = kmalloc(sizeof(struct lba_device), GFP_KERNEL); if (NULL == lba_dev) { printk("lba_init_chip - couldn't alloc lba_device\n"); return(1); } memset(lba_dev, 0, sizeof(struct lba_device)); /* ---------- First : initialize data we already have --------- */ /* ** Need hw_rev to adjust configuration space behavior. ** LBA_TR4PLUS macro uses hw_rev field. */ lba_dev->hw_rev = func_class; lba_dev->hba.base_addr = d->hpa; /* faster access */ lba_dev->iosapic_obj = tmp_obj; /* save interrupt handle */ /* ------------ Second : initialize common stuff ---------- */ lba_common_init(lba_dev); lba_hw_init(lba_dev); /* ---------- Third : setup I/O Port and MMIO resources --------- */#ifdef __LP64__ if (pdc_pat) { /* PDC PAT firmware uses PIOP region of GMMIO space. */ pci_port = &lba_pat_port_ops; /* Go ask PDC PAT what resources this LBA has */ lba_pat_resources(d, lba_dev); } else {#endif /* Sprockets PDC uses NPIOP region */ pci_port = &lba_astro_port_ops; /* Poke the chip a bit for /proc output */ lba_legacy_resources(d, lba_dev);#ifdef __LP64__ }#endif /* ** Tell PCI support another PCI bus was found. ** Walks PCI bus for us too. */ lba_bus = lba_dev->hba.hba_bus = pci_scan_bus( lba_dev->hba.bus_num.start, &lba_cfg_ops, (void *) lba_dev);#ifdef __LP64__ if (pdc_pat) { /* determine window sizes needed by PCI-PCI bridges */ DBG_PAT("LBA pcibios_size_bridge()\n"); pcibios_size_bridge(lba_bus, NULL); /* assign resources to un-initialized devices */ DBG_PAT("LBA pcibios_assign_unassigned_resources()\n"); pcibios_assign_unassigned_resources(lba_bus);#ifdef DEBUG_LBA_PAT DBG_PAT("\nLBA PIOP resource tree\n"); lba_dump_res(&lba_dev->hba.io_space, 2); DBG_PAT("\nLBA LMMIO resource tree\n"); lba_dump_res(&lba_dev->hba.mem_space, 2);#endif /* program *all* PCI-PCI bridge range registers */ DBG_PAT("LBA pbus_set_ranges()\n"); pbus_set_ranges(lba_bus, NULL); }#endif /* __LP64__ */ /* ** Once PCI register ops has walked the bus, access to config ** space is restricted. Avoids master aborts on config cycles. ** Early LBA revs go fatal on *any* master abort. */ if (!LBA_TR4PLUS(lba_dev)) { lba_dev->flags |= LBA_FLAG_SKIP_PROBE; } /* Whew! Finally done! Tell services we got this one covered. */ return 0;}/*** Initialize the IBASE/IMASK registers for LBA (Elroy).** Only called from sba_iommu.c initialization sequence.*/void lba_init_iregs(void *sba_hpa, u32 ibase, u32 imask){ extern struct pci_hba_data *hba_list; /* arch/parisc/kernel/pci.c */ struct pci_hba_data *lba; imask <<= 2; /* adjust for hints - 2 more bits */ ASSERT((ibase & 0x003fffff) == 0); ASSERT((imask & 0x003fffff) == 0); /* FIXME: sba_hpa is intended to search some table to ** determine which LBA's belong to the caller's SBA. ** IS_ASTRO: just assume only one SBA for now. */ ASSERT(NULL != hba_list); DBG(KERN_DEBUG "%s() ibase 0x%x imask 0x%x\n", __FUNCTION__, ibase, imask); for (lba = hba_list; NULL != lba; lba = lba->next) { DBG(KERN_DEBUG "%s() base_addr %p\n", __FUNCTION__, lba->base_addr); WRITE_REG32( imask, lba->base_addr + LBA_IMASK); WRITE_REG32( ibase, lba->base_addr + LBA_IBASE); } DBG(KERN_DEBUG "%s() done\n", __FUNCTION__);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -