Commit d925eab6 authored by Matthew Wilcox's avatar Matthew Wilcox Committed by David S. Miller

[PATCH] PA-RISC driver update for 2.6.2

PA-RISC specific driver updates:

 - Stop pasting __FILE__
 - Improve card-mode Dino support (James Bottomley)
 - Fix dev->bridge rename (James Bottomley)
 - iosapic/SBA/LBA cleanups (Grant Grundler)
 - Improve LED support (Helge Deller)
 - Fix mux driver (Ryan Bradetich)
 - Make STI framebuffer work on RDI PrecisionBook (Helge Deller)
parent 537c1ab3
...@@ -106,6 +106,9 @@ config IOMMU_SBA ...@@ -106,6 +106,9 @@ config IOMMU_SBA
#config PCI_EPIC #config PCI_EPIC
# bool "EPIC/SAGA PCI support" # bool "EPIC/SAGA PCI support"
# depends on PCI # depends on PCI
# default y
# help
# Say Y here for V-class PCI, DMA/IOMMU, IRQ subsystem support.
config SUPERIO config SUPERIO
bool "SuperIO (SuckyIO) support" bool "SuperIO (SuckyIO) support"
......
...@@ -364,11 +364,11 @@ ccio_alloc_range(struct ioc *ioc, unsigned long pages_needed) ...@@ -364,11 +364,11 @@ ccio_alloc_range(struct ioc *ioc, unsigned long pages_needed)
CCIO_FIND_FREE_MAPPING(ioc, res_idx, mask, 64); CCIO_FIND_FREE_MAPPING(ioc, res_idx, mask, 64);
#endif #endif
} else { } else {
panic(__FILE__ ": %s() Too many pages to map. pages_needed: %ld\n", panic("%s: %s() Too many pages to map. pages_needed: %ld\n",
__FUNCTION__, pages_needed); __FILE__, __FUNCTION__, pages_needed);
} }
panic(__FILE__ ": %s() I/O MMU is out of mapping resources.\n", panic("%s: %s() I/O MMU is out of mapping resources.\n", __FILE__,
__FUNCTION__); __FUNCTION__);
resource_found: resource_found:
...@@ -441,7 +441,7 @@ ccio_free_range(struct ioc *ioc, dma_addr_t iova, unsigned long pages_mapped) ...@@ -441,7 +441,7 @@ ccio_free_range(struct ioc *ioc, dma_addr_t iova, unsigned long pages_mapped)
CCIO_FREE_MAPPINGS(ioc, res_idx, mask, 64); CCIO_FREE_MAPPINGS(ioc, res_idx, mask, 64);
#endif #endif
} else { } else {
panic(__FILE__ ":%s() Too many pages to unmap.\n", panic("%s:%s() Too many pages to unmap.\n", __FILE__,
__FUNCTION__); __FUNCTION__);
} }
} }
...@@ -1447,7 +1447,8 @@ ccio_ioc_init(struct ioc *ioc) ...@@ -1447,7 +1447,8 @@ ccio_ioc_init(struct ioc *ioc)
ioc->pdir_base = (u64 *)__get_free_pages(GFP_KERNEL, ioc->pdir_base = (u64 *)__get_free_pages(GFP_KERNEL,
get_order(ioc->pdir_size)); get_order(ioc->pdir_size));
if(NULL == ioc->pdir_base) { if(NULL == ioc->pdir_base) {
panic(__FILE__ ":%s() could not allocate I/O Page Table\n", __FUNCTION__); panic("%s:%s() could not allocate I/O Page Table\n", __FILE__,
__FUNCTION__);
} }
memset(ioc->pdir_base, 0, ioc->pdir_size); memset(ioc->pdir_base, 0, ioc->pdir_size);
...@@ -1461,7 +1462,8 @@ ccio_ioc_init(struct ioc *ioc) ...@@ -1461,7 +1462,8 @@ ccio_ioc_init(struct ioc *ioc)
ioc->res_map = (u8 *)__get_free_pages(GFP_KERNEL, ioc->res_map = (u8 *)__get_free_pages(GFP_KERNEL,
get_order(ioc->res_size)); get_order(ioc->res_size));
if(NULL == ioc->res_map) { if(NULL == ioc->res_map) {
panic(__FILE__ ":%s() could not allocate resource map\n", __FUNCTION__); panic("%s:%s() could not allocate resource map\n", __FILE__,
__FUNCTION__);
} }
memset(ioc->res_map, 0, ioc->res_size); memset(ioc->res_map, 0, ioc->res_size);
...@@ -1627,11 +1629,11 @@ int ccio_request_resource(const struct parisc_device *dev, ...@@ -1627,11 +1629,11 @@ int ccio_request_resource(const struct parisc_device *dev,
if (!ioc) { if (!ioc) {
parent = &iomem_resource; parent = &iomem_resource;
} else if ((ioc->mmio_region->start <= dev->hpa) && } else if ((ioc->mmio_region->start <= res->start) &&
(dev->hpa < ioc->mmio_region->end)) { (res->end <= ioc->mmio_region->end)) {
parent = ioc->mmio_region; parent = ioc->mmio_region;
} else if (((ioc->mmio_region + 1)->start <= dev->hpa) && } else if (((ioc->mmio_region + 1)->start <= res->start) &&
(dev->hpa < (ioc->mmio_region + 1)->end)) { (res->end <= (ioc->mmio_region + 1)->end)) {
parent = ioc->mmio_region + 1; parent = ioc->mmio_region + 1;
} else { } else {
return -EBUSY; return -EBUSY;
......
...@@ -175,7 +175,7 @@ static int dino_current_bus = 0; ...@@ -175,7 +175,7 @@ static int dino_current_bus = 0;
static int dino_cfg_read(struct pci_bus *bus, unsigned int devfn, int where, static int dino_cfg_read(struct pci_bus *bus, unsigned int devfn, int where,
int size, u32 *val) int size, u32 *val)
{ {
struct dino_device *d = DINO_DEV(parisc_walk_tree(bus->dev)); struct dino_device *d = DINO_DEV(parisc_walk_tree(bus->bridge));
u32 local_bus = (bus->parent == NULL) ? 0 : bus->secondary; u32 local_bus = (bus->parent == NULL) ? 0 : bus->secondary;
u32 v = DINO_CFG_TOK(local_bus, devfn, where & ~3); u32 v = DINO_CFG_TOK(local_bus, devfn, where & ~3);
unsigned long base_addr = d->hba.base_addr; unsigned long base_addr = d->hba.base_addr;
...@@ -209,7 +209,7 @@ static int dino_cfg_read(struct pci_bus *bus, unsigned int devfn, int where, ...@@ -209,7 +209,7 @@ static int dino_cfg_read(struct pci_bus *bus, unsigned int devfn, int where,
static int dino_cfg_write(struct pci_bus *bus, unsigned int devfn, int where, static int dino_cfg_write(struct pci_bus *bus, unsigned int devfn, int where,
int size, u32 val) int size, u32 val)
{ {
struct dino_device *d = DINO_DEV(parisc_walk_tree(bus->dev)); struct dino_device *d = DINO_DEV(parisc_walk_tree(bus->bridge));
u32 local_bus = (bus->parent == NULL) ? 0 : bus->secondary; u32 local_bus = (bus->parent == NULL) ? 0 : bus->secondary;
u32 v = DINO_CFG_TOK(local_bus, devfn, where & ~3); u32 v = DINO_CFG_TOK(local_bus, devfn, where & ~3);
unsigned long base_addr = d->hba.base_addr; unsigned long base_addr = d->hba.base_addr;
...@@ -468,14 +468,14 @@ static void __init ...@@ -468,14 +468,14 @@ static void __init
dino_card_setup(struct pci_bus *bus, unsigned long base_addr) dino_card_setup(struct pci_bus *bus, unsigned long base_addr)
{ {
int i; int i;
struct dino_device *dino_dev = DINO_DEV(parisc_walk_tree(bus->dev)); struct dino_device *dino_dev = DINO_DEV(parisc_walk_tree(bus->bridge));
struct resource *res; struct resource *res;
char name[128]; char name[128];
int size; int size;
res = &dino_dev->hba.lmmio_space; res = &dino_dev->hba.lmmio_space;
res->flags = IORESOURCE_MEM; res->flags = IORESOURCE_MEM;
size = snprintf(name, sizeof(name), "Dino LMMIO (%s)", bus->dev->bus_id); size = snprintf(name, sizeof(name), "Dino LMMIO (%s)", bus->bridge->bus_id);
res->name = kmalloc(size+1, GFP_KERNEL); res->name = kmalloc(size+1, GFP_KERNEL);
if(res->name) if(res->name)
strcpy((char *)res->name, name); strcpy((char *)res->name, name);
...@@ -489,7 +489,7 @@ dino_card_setup(struct pci_bus *bus, unsigned long base_addr) ...@@ -489,7 +489,7 @@ dino_card_setup(struct pci_bus *bus, unsigned long base_addr)
struct list_head *ln, *tmp_ln; struct list_head *ln, *tmp_ln;
printk(KERN_ERR "Dino: cannot attach bus %s\n", printk(KERN_ERR "Dino: cannot attach bus %s\n",
bus->dev->bus_id); bus->bridge->bus_id);
/* kill the bus, we can't do anything with it */ /* kill the bus, we can't do anything with it */
list_for_each_safe(ln, tmp_ln, &bus->devices) { list_for_each_safe(ln, tmp_ln, &bus->devices) {
struct pci_dev *dev = pci_dev_b(ln); struct pci_dev *dev = pci_dev_b(ln);
...@@ -560,11 +560,11 @@ dino_fixup_bus(struct pci_bus *bus) ...@@ -560,11 +560,11 @@ dino_fixup_bus(struct pci_bus *bus)
{ {
struct list_head *ln; struct list_head *ln;
struct pci_dev *dev; struct pci_dev *dev;
struct dino_device *dino_dev = DINO_DEV(parisc_walk_tree(bus->dev)); struct dino_device *dino_dev = DINO_DEV(parisc_walk_tree(bus->bridge));
int port_base = HBA_PORT_BASE(dino_dev->hba.hba_num); int port_base = HBA_PORT_BASE(dino_dev->hba.hba_num);
DBG(KERN_WARNING "%s(0x%p) bus %d sysdata 0x%p\n", DBG(KERN_WARNING "%s(0x%p) bus %d sysdata 0x%p\n",
__FUNCTION__, bus, bus->secondary, bus->dev->platform_data); __FUNCTION__, bus, bus->secondary, bus->bridge->platform_data);
/* Firmware doesn't set up card-mode dino, so we have to */ /* Firmware doesn't set up card-mode dino, so we have to */
if (is_card_dino(&dino_dev->hba.dev->id)) { if (is_card_dino(&dino_dev->hba.dev->id)) {
...@@ -572,15 +572,23 @@ dino_fixup_bus(struct pci_bus *bus) ...@@ -572,15 +572,23 @@ dino_fixup_bus(struct pci_bus *bus)
} else if(bus->parent == NULL) { } else if(bus->parent == NULL) {
/* must have a dino above it, reparent the resources /* must have a dino above it, reparent the resources
* into the dino window */ * into the dino window */
int i;
struct resource *res = &dino_dev->hba.lmmio_space;
bus->resource[0] = &(dino_dev->hba.io_space); bus->resource[0] = &(dino_dev->hba.io_space);
bus->resource[1] = &(dino_dev->hba.lmmio_space); for(i = 0; i < DINO_MAX_LMMIO_RESOURCES; i++) {
if(res[i].flags == 0)
break;
bus->resource[i+1] = &res[i];
}
} else if(bus->self) { } else if(bus->self) {
int i; int i;
pci_read_bridge_bases(bus); pci_read_bridge_bases(bus);
for(i = 0; i < PCI_NUM_RESOURCES; i++) { for(i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) {
if((bus->self->resource[i].flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0) if((bus->self->resource[i].flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0)
continue; continue;
...@@ -642,11 +650,10 @@ dino_fixup_bus(struct pci_bus *bus) ...@@ -642,11 +650,10 @@ dino_fixup_bus(struct pci_bus *bus)
* care about an expansion rom on parisc, since it * care about an expansion rom on parisc, since it
* usually contains (x86) bios code) */ * usually contains (x86) bios code) */
dev->resource[PCI_ROM_RESOURCE].flags = 0; dev->resource[PCI_ROM_RESOURCE].flags = 0;
dev->resource[PCI_ROM_RESOURCE].start = 0;
dev->resource[PCI_ROM_RESOURCE].end = 0;
if(dev->irq == 255) { if(dev->irq == 255) {
#define DINO_FIX_UNASSIGNED_INTERRUPTS
#ifdef DINO_FIX_UNASSIGNED_INTERRUPTS #ifdef DINO_FIX_UNASSIGNED_INTERRUPTS
/* This code tries to assign an unassigned /* This code tries to assign an unassigned
...@@ -660,7 +667,7 @@ dino_fixup_bus(struct pci_bus *bus) ...@@ -660,7 +667,7 @@ dino_fixup_bus(struct pci_bus *bus)
dino_cfg_read(dev->bus, dev->devfn, PCI_INTERRUPT_PIN, 1, &irq_pin); dino_cfg_read(dev->bus, dev->devfn, PCI_INTERRUPT_PIN, 1, &irq_pin);
dev->irq = (irq_pin + PCI_SLOT(dev->devfn) - 1) % 4 ; dev->irq = (irq_pin + PCI_SLOT(dev->devfn) - 1) % 4 ;
dino_cfg_write(dev->bus, dev->devfn, PCI_INTERRUPT_LINE, 1, dev->irq); dino_cfg_write(dev->bus, dev->devfn, PCI_INTERRUPT_LINE, 1, dev->irq);
dev->irq += dino_dev->dino_region->data.irqbase dev->irq += dino_dev->dino_region->data.irqbase;
printk(KERN_WARNING "Device %s has undefined IRQ, setting to %d\n", dev->slot_name, irq_pin); printk(KERN_WARNING "Device %s has undefined IRQ, setting to %d\n", dev->slot_name, irq_pin);
#else #else
dev->irq = 65535; dev->irq = 65535;
...@@ -741,9 +748,9 @@ dino_card_init(struct dino_device *dino_dev) ...@@ -741,9 +748,9 @@ dino_card_init(struct dino_device *dino_dev)
static int __init static int __init
dino_bridge_init(struct dino_device *dino_dev, const char *name) dino_bridge_init(struct dino_device *dino_dev, const char *name)
{ {
unsigned long io_addr, bpos; unsigned long io_addr;
int result; int result, i, count=0;
struct resource *res; struct resource *res, *prevres = NULL;
/* /*
* Decoding IO_ADDR_EN only works for Built-in Dino * Decoding IO_ADDR_EN only works for Built-in Dino
* since PDC has already initialized this. * since PDC has already initialized this.
...@@ -755,21 +762,51 @@ dino_bridge_init(struct dino_device *dino_dev, const char *name) ...@@ -755,21 +762,51 @@ dino_bridge_init(struct dino_device *dino_dev, const char *name)
return -ENODEV; return -ENODEV;
} }
for (bpos = 0; (io_addr & (1 << bpos)) == 0; bpos++)
;
res = &dino_dev->hba.lmmio_space; res = &dino_dev->hba.lmmio_space;
for (i = 0; i < 32; i++) {
unsigned long start, end;
if((io_addr & (1 << i)) == 0)
continue;
start = (unsigned long)(signed int)(0xf0000000 | (i << 23));
end = start + 8 * 1024 * 1024 - 1;
DBG("DINO RANGE %d is at 0x%lx-0x%lx\n", count,
start, end);
if(prevres && prevres->end + 1 == start) {
prevres->end = end;
} else {
if(count >= DINO_MAX_LMMIO_RESOURCES) {
printk(KERN_ERR "%s is out of resource windows for range %d (0x%lx-0x%lx)\n", name, count, start, end);
break;
}
prevres = res;
res->start = start;
res->end = end;
res->flags = IORESOURCE_MEM; res->flags = IORESOURCE_MEM;
res->name = kmalloc(64, GFP_KERNEL);
if(res->name)
snprintf((char *)res->name, 64, "%s LMMIO %d",
name, count);
res++;
count++;
}
}
res = &dino_dev->hba.lmmio_space;
res->start = (unsigned long)(signed int)(0xf0000000 | (bpos << 23)); for(i = 0; i < DINO_MAX_LMMIO_RESOURCES; i++) {
res->end = res->start + 8 * 1024 * 1024 - 1; if(res[i].flags == 0)
break;
result = ccio_request_resource(dino_dev->hba.dev, res); result = ccio_request_resource(dino_dev->hba.dev, &res[i]);
if (result < 0) { if (result < 0) {
printk(KERN_ERR "%s: failed to claim PCI Bus address space!\n", name); printk(KERN_ERR "%s: failed to claim PCI Bus address space %d (0x%lx-0x%lx)!\n", name, i, res[i].start, res[i].end);
return result; return result;
} }
}
return 0; return 0;
} }
...@@ -850,10 +887,8 @@ static int __init dino_common_init(struct parisc_device *dev, ...@@ -850,10 +887,8 @@ static int __init dino_common_init(struct parisc_device *dev,
res = &dino_dev->hba.io_space; res = &dino_dev->hba.io_space;
if (dev->id.hversion == 0x680 || is_card_dino(&dev->id)) { if (dev->id.hversion == 0x680 || is_card_dino(&dev->id)) {
res->name = "Dino I/O Port"; res->name = "Dino I/O Port";
dino_dev->hba.lmmio_space.name = "Dino LMMIO";
} else { } else {
res->name = "Cujo I/O Port"; res->name = "Cujo I/O Port";
dino_dev->hba.lmmio_space.name = "Cujo LMMIO";
} }
res->start = HBA_PORT_BASE(dino_dev->hba.hba_num); res->start = HBA_PORT_BASE(dino_dev->hba.hba_num);
res->end = res->start + (HBA_PORT_SPACE_SIZE - 1); res->end = res->start + (HBA_PORT_SPACE_SIZE - 1);
......
/*
* EISA "eeprom" support routines
*
* Copyright (C) 2001 Thomas Bogendoerfer <tsbogend at parisc-linux.org>
*
*
* 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.
*
* 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/config.h> #include <linux/config.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
......
...@@ -610,19 +610,19 @@ iosapic_interrupt(int irq, void *dev_id, struct pt_regs * regs) ...@@ -610,19 +610,19 @@ iosapic_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{ {
struct vector_info *vi = (struct vector_info *)dev_id; struct vector_info *vi = (struct vector_info *)dev_id;
extern void do_irq(struct irqaction *a, int i, struct pt_regs *p); extern void do_irq(struct irqaction *a, int i, struct pt_regs *p);
int irq_num = vi->vi_ios->isi_region->data.irqbase + vi->vi_irqline; int irq_num = vi->iosapic->isi_region->data.irqbase + vi->irqline;
DBG("iosapic_interrupt(): irq %d line %d eoi %p\n", DBG("iosapic_interrupt(): irq %d line %d eoi %p\n",
irq, vi->vi_irqline, vi->vi_eoi_addr); irq, vi->irqline, vi->eoi_addr);
/* FIXME: Need to mask/unmask? processor IRQ is already masked... */ /* FIXME: Need to mask/unmask? processor IRQ is already masked... */
do_irq(&vi->vi_ios->isi_region->action[vi->vi_irqline], irq_num, regs); do_irq(&vi->iosapic->isi_region->action[vi->irqline], irq_num, regs);
/* /*
** PCI only supports level triggered in order to share IRQ lines. ** PCI only supports level triggered in order to share IRQ lines.
** I/O SAPIC must always issue EOI. ** I/O SAPIC must always issue EOI.
*/ */
IOSAPIC_EOI(vi->vi_eoi_addr, vi->vi_eoi_data); IOSAPIC_EOI(vi->eoi_addr, vi->eoi_data);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -636,10 +636,6 @@ iosapic_fixup_irq(void *isi_obj, struct pci_dev *pcidev) ...@@ -636,10 +636,6 @@ iosapic_fixup_irq(void *isi_obj, struct pci_dev *pcidev)
struct vector_info *vi; struct vector_info *vi;
int isi_line; /* line used by device */ int isi_line; /* line used by device */
int tmp; int tmp;
int return_irq;
#ifdef CONFIG_SUPERIO
int superio_irq = -1;
#endif
if (NULL == isi) { if (NULL == isi) {
printk(KERN_WARNING MODULE_NAME ": hpa not registered for %s\n", printk(KERN_WARNING MODULE_NAME ": hpa not registered for %s\n",
...@@ -648,30 +644,29 @@ iosapic_fixup_irq(void *isi_obj, struct pci_dev *pcidev) ...@@ -648,30 +644,29 @@ iosapic_fixup_irq(void *isi_obj, struct pci_dev *pcidev)
} }
#ifdef CONFIG_SUPERIO #ifdef CONFIG_SUPERIO
if (is_superio_device(pcidev)) {
superio_irq = superio_fixup_irq(pcidev);
if (superio_irq == -1)
return(-1);
if (PCI_FUNC(pcidev->devfn) != SUPERIO_USB_FN) {
/* /*
* SuperIO USB controller has an irt entry. * HACK ALERT! (non-compliant PCI device support)
* Only let the USB controller hookup the rest *
* of the interrupt routing when it comes through. * All SuckyIO interrupts are routed through the PIC's on function 1.
* Note that interrupts for all three functions * But SuckyIO OHCI USB controller gets an IRT entry anyway because
* actually come through the PIC's on function 1! * it advertises INT D for INT_PIN. Use that IRT entry to get the
* SuckyIO interrupt routing for PICs on function 1 (*BLEECCHH*).
*/ */
if (is_superio_device(pcidev)) {
/* We must call superio_fixup_irq() to register the pdev */
pcidev->irq = superio_fixup_irq(pcidev);
pcidev->irq = superio_irq; /* Don't return if need to program the IOSAPIC's IRT... */
return superio_irq; if (PCI_FUNC(pcidev->devfn) != SUPERIO_USB_FN)
} return pcidev->irq;
} }
#endif /* CONFIG_SUPERIO */ #endif /* CONFIG_SUPERIO */
/* lookup IRT entry for isi/slot/pin set */ /* lookup IRT entry for isi/slot/pin set */
irte = iosapic_xlate_pin(isi, pcidev); irte = iosapic_xlate_pin(isi, pcidev);
if (NULL == irte) { if (NULL == irte) {
printk("iosapic: no IRTE for %s (IRQ not connected?)\n",
pci_name(pcidev));
return(-1); return(-1);
} }
DBG_IRT("iosapic_fixup_irq(): irte %p %x %x %x %x %x %x %x %x\n", DBG_IRT("iosapic_fixup_irq(): irte %p %x %x %x %x %x %x %x %x\n",
...@@ -685,15 +680,21 @@ iosapic_fixup_irq(void *isi_obj, struct pci_dev *pcidev) ...@@ -685,15 +680,21 @@ iosapic_fixup_irq(void *isi_obj, struct pci_dev *pcidev)
irte->dest_iosapic_intin, irte->dest_iosapic_intin,
(u32) irte->dest_iosapic_addr); (u32) irte->dest_iosapic_addr);
isi_line = irte->dest_iosapic_intin; isi_line = irte->dest_iosapic_intin;
pcidev->irq = isi->isi_region->data.irqbase + isi_line;
/* get vector info for this input line */ /* get vector info for this input line */
ASSERT(NULL != isi->isi_vector); ASSERT(NULL != isi->isi_vector);
vi = &(isi->isi_vector[isi_line]); vi = &(isi->isi_vector[isi_line]);
DBG_IRT("iosapic_fixup_irq: line %d vi 0x%p\n", isi_line, vi); DBG_IRT("iosapic_fixup_irq: line %d vi 0x%p\n", isi_line, vi);
vi->vi_irte = irte;
/* If this IRQ line has already been setup, skip it */
if (vi->irte)
return pcidev->irq;
vi->irte = irte;
/* Allocate processor IRQ */ /* Allocate processor IRQ */
vi->vi_txn_irq = txn_alloc_irq(); vi->txn_irq = txn_alloc_irq();
/* XXX/FIXME The txn_alloc_irq() code and related code should be moved /* XXX/FIXME The txn_alloc_irq() code and related code should be moved
** to enable_irq(). That way we only allocate processor IRQ bits ** to enable_irq(). That way we only allocate processor IRQ bits
...@@ -701,47 +702,36 @@ iosapic_fixup_irq(void *isi_obj, struct pci_dev *pcidev) ...@@ -701,47 +702,36 @@ iosapic_fixup_irq(void *isi_obj, struct pci_dev *pcidev)
** Right now we assign an IRQ to every PCI device present regardless ** Right now we assign an IRQ to every PCI device present regardless
** of whether it's used or not. ** of whether it's used or not.
*/ */
if (vi->vi_txn_irq < 0) if (vi->txn_irq < 0)
panic("I/O sapic: couldn't get TXN IRQ\n"); panic("I/O sapic: couldn't get TXN IRQ\n");
/* enable_irq() will use txn_* to program IRdT */ /* enable_irq() will use txn_* to program IRdT */
vi->vi_txn_addr = txn_alloc_addr(vi->vi_txn_irq); vi->txn_addr = txn_alloc_addr(vi->txn_irq);
vi->vi_txn_data = txn_alloc_data(vi->vi_txn_irq, 8); vi->txn_data = txn_alloc_data(vi->txn_irq, 8);
ASSERT(vi->vi_txn_data < 256); /* matches 8 above */ ASSERT(vi->txn_data < 256); /* matches 8 above */
tmp = request_irq(vi->vi_txn_irq, iosapic_interrupt, 0, tmp = request_irq(vi->txn_irq, iosapic_interrupt, 0,
vi->vi_name, vi); vi->name, vi);
ASSERT(tmp == 0); ASSERT(tmp == 0);
vi->vi_eoi_addr = (u32 *) (isi->isi_hpa + IOSAPIC_REG_EOI); vi->eoi_addr = (u32 *) (isi->isi_hpa + IOSAPIC_REG_EOI);
vi->vi_eoi_data = cpu_to_le32(vi->vi_irqline); vi->eoi_data = cpu_to_le32(vi->irqline);
ASSERT(NULL != isi->isi_region); ASSERT(NULL != isi->isi_region);
/* pcidev->irq still needs to be virtualized. */
return_irq = isi->isi_region->data.irqbase + isi_line;
#ifdef CONFIG_SUPERIO
if (superio_irq != -1) {
superio_inform_irq(return_irq);
return_irq = superio_irq;
}
#endif
pcidev->irq = return_irq;
DBG_IRT("iosapic_fixup_irq() %d:%d %x %x line %d irq %d\n", DBG_IRT("iosapic_fixup_irq() %d:%d %x %x line %d irq %d\n",
PCI_SLOT(pcidev->devfn), PCI_SLOT(pcidev->devfn), PCI_FUNC(pcidev->irq),
PCI_FUNC(pcidev->devfn), pcidev->vendor, pcidev->device, isi_line, return_irq); pcidev->vendor, pcidev->device, isi_line, pcidev->irq);
return return_irq; return pcidev->irq;
} }
static void static void
iosapic_rd_irt_entry(struct vector_info *vi , u32 *dp0, u32 *dp1) iosapic_rd_irt_entry(struct vector_info *vi , u32 *dp0, u32 *dp1)
{ {
struct iosapic_info *isp = vi->vi_ios; struct iosapic_info *isp = vi->iosapic;
u8 idx = vi->vi_irqline; u8 idx = vi->irqline;
/* point the window register to the lower word */ /* point the window register to the lower word */
WRITE_U32(IOSAPIC_IRDT_ENTRY(idx), isp->isi_hpa+IOSAPIC_REG_SELECT); WRITE_U32(IOSAPIC_IRDT_ENTRY(idx), isp->isi_hpa+IOSAPIC_REG_SELECT);
...@@ -756,24 +746,24 @@ iosapic_rd_irt_entry(struct vector_info *vi , u32 *dp0, u32 *dp1) ...@@ -756,24 +746,24 @@ iosapic_rd_irt_entry(struct vector_info *vi , u32 *dp0, u32 *dp1)
static void static void
iosapic_wr_irt_entry(struct vector_info *vi, u32 dp0, u32 dp1) iosapic_wr_irt_entry(struct vector_info *vi, u32 dp0, u32 dp1)
{ {
struct iosapic_info *isp = vi->vi_ios; struct iosapic_info *isp = vi->iosapic;
ASSERT(NULL != isp); ASSERT(NULL != isp);
ASSERT(0 != isp->isi_hpa); ASSERT(0 != isp->isi_hpa);
DBG_IRT("iosapic_wr_irt_entry(): irq %d hpa %p WINDOW %p 0x%x 0x%x\n", DBG_IRT("iosapic_wr_irt_entry(): irq %d hpa %p WINDOW %p 0x%x 0x%x\n",
vi->vi_irqline, vi->irqline,
isp->isi_hpa, isp->isi_hpa+IOSAPIC_REG_WINDOW, isp->isi_hpa, isp->isi_hpa+IOSAPIC_REG_WINDOW,
dp0, dp1); dp0, dp1);
/* point the window register to the lower word */ /* point the window register to the lower word */
WRITE_U32(IOSAPIC_IRDT_ENTRY(vi->vi_irqline), isp->isi_hpa+IOSAPIC_REG_SELECT); WRITE_U32(IOSAPIC_IRDT_ENTRY(vi->irqline), isp->isi_hpa+IOSAPIC_REG_SELECT);
WRITE_U32( dp0, isp->isi_hpa+IOSAPIC_REG_WINDOW); WRITE_U32( dp0, isp->isi_hpa+IOSAPIC_REG_WINDOW);
/* Read the window register to flush the writes down to HW */ /* Read the window register to flush the writes down to HW */
dp0 = READ_U32(isp->isi_hpa+IOSAPIC_REG_WINDOW); dp0 = READ_U32(isp->isi_hpa+IOSAPIC_REG_WINDOW);
/* point the window register to the higher word */ /* point the window register to the higher word */
WRITE_U32(IOSAPIC_IRDT_ENTRY_HI(vi->vi_irqline), isp->isi_hpa+IOSAPIC_REG_SELECT); WRITE_U32(IOSAPIC_IRDT_ENTRY_HI(vi->irqline), isp->isi_hpa+IOSAPIC_REG_SELECT);
WRITE_U32( dp1, isp->isi_hpa+IOSAPIC_REG_WINDOW); WRITE_U32( dp1, isp->isi_hpa+IOSAPIC_REG_WINDOW);
/* Read the window register to flush the writes down to HW */ /* Read the window register to flush the writes down to HW */
...@@ -790,8 +780,8 @@ static void ...@@ -790,8 +780,8 @@ static void
iosapic_set_irt_data( struct vector_info *vi, u32 *dp0, u32 *dp1) iosapic_set_irt_data( struct vector_info *vi, u32 *dp0, u32 *dp1)
{ {
u32 mode = 0; u32 mode = 0;
struct irt_entry *p = vi->vi_irte; struct irt_entry *p = vi->irte;
ASSERT(NULL != vi->vi_irte); ASSERT(NULL != vi->irte);
if ((p->polarity_trigger & IRT_PO_MASK) == IRT_ACTIVE_LO) if ((p->polarity_trigger & IRT_PO_MASK) == IRT_ACTIVE_LO)
mode |= IOSAPIC_IRDT_PO_LOW; mode |= IOSAPIC_IRDT_PO_LOW;
...@@ -804,8 +794,8 @@ iosapic_set_irt_data( struct vector_info *vi, u32 *dp0, u32 *dp1) ...@@ -804,8 +794,8 @@ iosapic_set_irt_data( struct vector_info *vi, u32 *dp0, u32 *dp1)
** PA doesn't support EXTINT or LPRIO bits. ** PA doesn't support EXTINT or LPRIO bits.
*/ */
ASSERT(vi->vi_txn_data); ASSERT(vi->txn_data);
*dp0 = mode | (u32) vi->vi_txn_data; *dp0 = mode | (u32) vi->txn_data;
/* /*
** Extracting id_eid isn't a real clean way of getting it. ** Extracting id_eid isn't a real clean way of getting it.
...@@ -814,9 +804,9 @@ iosapic_set_irt_data( struct vector_info *vi, u32 *dp0, u32 *dp1) ...@@ -814,9 +804,9 @@ iosapic_set_irt_data( struct vector_info *vi, u32 *dp0, u32 *dp1)
if (is_pdc_pat()) { if (is_pdc_pat()) {
/* /*
** PAT PDC just hands it to us "right". ** PAT PDC just hands it to us "right".
** vi_txn_addr comes from cpu_data[x].txn_addr. ** txn_addr comes from cpu_data[x].txn_addr.
*/ */
*dp1 = (u32) (vi->vi_txn_addr); *dp1 = (u32) (vi->txn_addr);
} else { } else {
/* /*
** eg if base_addr == 0xfffa0000), ** eg if base_addr == 0xfffa0000),
...@@ -825,8 +815,8 @@ iosapic_set_irt_data( struct vector_info *vi, u32 *dp0, u32 *dp1) ...@@ -825,8 +815,8 @@ iosapic_set_irt_data( struct vector_info *vi, u32 *dp0, u32 *dp1)
** eid 0x0ff00000 -> 0x00ff0000 ** eid 0x0ff00000 -> 0x00ff0000
** id 0x000ff000 -> 0xff000000 ** id 0x000ff000 -> 0xff000000
*/ */
*dp1 = (((u32)vi->vi_txn_addr & 0x0ff00000) >> 4) | *dp1 = (((u32)vi->txn_addr & 0x0ff00000) >> 4) |
(((u32)vi->vi_txn_addr & 0x000ff000) << 12); (((u32)vi->txn_addr & 0x000ff000) << 12);
} }
DBG_IRT("iosapic_set_irt_data(): 0x%x 0x%x\n", *dp0, *dp1); DBG_IRT("iosapic_set_irt_data(): 0x%x 0x%x\n", *dp0, *dp1);
} }
...@@ -872,7 +862,7 @@ Need more info on how Linux supports shared IRQ lines on a PC. ...@@ -872,7 +862,7 @@ Need more info on how Linux supports shared IRQ lines on a PC.
IOSAPIC_UNLOCK(&iosapic_lock); IOSAPIC_UNLOCK(&iosapic_lock);
/* disable ISR for parent */ /* disable ISR for parent */
disable_irq(vi->vi_txn_irq); disable_irq(vi->txn_irq);
} }
...@@ -883,11 +873,11 @@ iosapic_enable_irq(void *dev, int irq) ...@@ -883,11 +873,11 @@ iosapic_enable_irq(void *dev, int irq)
u32 d0, d1; u32 d0, d1;
ASSERT(NULL != vi); ASSERT(NULL != vi);
ASSERT(NULL != vi->vi_irte); ASSERT(NULL != vi->irte);
/* data is initialized by fixup_irq */ /* data is initialized by fixup_irq */
ASSERT(0 < vi->vi_txn_irq); ASSERT(0 < vi->txn_irq);
ASSERT(0UL != vi->vi_txn_data); ASSERT(0UL != vi->txn_data);
iosapic_set_irt_data(vi, &d0, &d1); iosapic_set_irt_data(vi, &d0, &d1);
iosapic_wr_irt_entry(vi, d0, d1); iosapic_wr_irt_entry(vi, d0, d1);
...@@ -895,15 +885,15 @@ iosapic_enable_irq(void *dev, int irq) ...@@ -895,15 +885,15 @@ iosapic_enable_irq(void *dev, int irq)
#ifdef DEBUG_IOSAPIC_IRT #ifdef DEBUG_IOSAPIC_IRT
{ {
u32 *t = (u32 *) ((ulong) vi->vi_eoi_addr & ~0xffUL); u32 *t = (u32 *) ((ulong) vi->eoi_addr & ~0xffUL);
printk("iosapic_enable_irq(): regs %p", vi->vi_eoi_addr); printk("iosapic_enable_irq(): regs %p", vi->eoi_addr);
while (t < vi->vi_eoi_addr) printk(" %x", READ_U32(t++)); while (t < vi->eoi_addr) printk(" %x", READ_U32(t++));
printk("\n"); printk("\n");
} }
printk("iosapic_enable_irq(): sel "); printk("iosapic_enable_irq(): sel ");
{ {
struct iosapic_info *isp = vi->vi_ios; struct iosapic_info *isp = vi->iosapic;
for (d0=0x10; d0<0x1e; d0++) { for (d0=0x10; d0<0x1e; d0++) {
/* point the window register to the lower word */ /* point the window register to the lower word */
...@@ -924,7 +914,7 @@ printk("\n"); ...@@ -924,7 +914,7 @@ printk("\n");
** Issueing I/O SAPIC an EOI causes an interrupt iff IRQ line is ** Issueing I/O SAPIC an EOI causes an interrupt iff IRQ line is
** asserted. ** asserted.
*/ */
IOSAPIC_EOI(vi->vi_eoi_addr, vi->vi_eoi_data); IOSAPIC_EOI(vi->eoi_addr, vi->eoi_data);
} }
...@@ -1034,9 +1024,9 @@ iosapic_register(unsigned long hpa) ...@@ -1034,9 +1024,9 @@ iosapic_register(unsigned long hpa)
** Initialize vector array ** Initialize vector array
*/ */
for (cnt=0; cnt < isi->isi_num_vectors; cnt++, vip++) { for (cnt=0; cnt < isi->isi_num_vectors; cnt++, vip++) {
vip->vi_irqline = (unsigned char) cnt; vip->irqline = (unsigned char) cnt;
vip->vi_ios = isi; vip->iosapic = isi;
sprintf(vip->vi_name, "%s-L%d", isi->isi_name, cnt); sprintf(vip->name, "%s-L%d", isi->isi_name, cnt);
} }
isi->isi_region = alloc_irq_region(isi->isi_num_vectors, isi->isi_region = alloc_irq_region(isi->isi_num_vectors,
...@@ -1071,13 +1061,13 @@ iosapic_prt_vi(struct vector_info *vi) ...@@ -1071,13 +1061,13 @@ iosapic_prt_vi(struct vector_info *vi)
{ {
ASSERT(NULL != vi); ASSERT(NULL != vi);
printk(KERN_DEBUG MODULE_NAME ": vector_info[%d] is at %p\n", vi->vi_irqline, vi); printk(KERN_DEBUG MODULE_NAME ": vector_info[%d] is at %p\n", vi->irqline, vi);
printk(KERN_DEBUG "\t\tvi_status: %.4x\n", vi->vi_status); printk(KERN_DEBUG "\t\tstatus: %.4x\n", vi->status);
printk(KERN_DEBUG "\t\tvi_txn_irq: %d\n", vi->vi_txn_irq); printk(KERN_DEBUG "\t\ttxn_irq: %d\n", vi->txn_irq);
printk(KERN_DEBUG "\t\tvi_txn_addr: %lx\n", vi->vi_txn_addr); printk(KERN_DEBUG "\t\ttxn_addr: %lx\n", vi->txn_addr);
printk(KERN_DEBUG "\t\tvi_txn_data: %lx\n", vi->vi_txn_data); printk(KERN_DEBUG "\t\ttxn_data: %lx\n", vi->txn_data);
printk(KERN_DEBUG "\t\tvi_eoi_addr: %p\n", vi->vi_eoi_addr); printk(KERN_DEBUG "\t\teoi_addr: %p\n", vi->eoi_addr);
printk(KERN_DEBUG "\t\tvi_eoi_data: %x\n", vi->vi_eoi_data); printk(KERN_DEBUG "\t\teoi_data: %x\n", vi->eoi_data);
} }
......
/*
* Private structs/constants for PARISC IOSAPIC support
*
* Copyright (C) 2000 Hewlett Packard (Grant Grundler)
* Copyright (C) 2000,2003 Grant Grundler (grundler at parisc-linux.org)
* Copyright (C) 2002 Matthew Wilcox (willy at parisc-linux.org)
*
*
* 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.
*
* 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
*/
/* /*
** This file is private to iosapic driver. ** This file is private to iosapic driver.
** If stuff needs to be used by another driver, move it to a common file. ** If stuff needs to be used by another driver, move it to a common file.
...@@ -107,16 +130,16 @@ struct iosapic_irt { ...@@ -107,16 +130,16 @@ struct iosapic_irt {
#endif #endif
struct vector_info { struct vector_info {
struct iosapic_info *vi_ios; /* I/O SAPIC this vector is on */ struct iosapic_info *iosapic; /* I/O SAPIC this vector is on */
struct irt_entry *vi_irte; /* IRT entry */ struct irt_entry *irte; /* IRT entry */
u32 *vi_eoi_addr; /* precalculate EOI reg address */ u32 *eoi_addr; /* precalculate EOI reg address */
u32 vi_eoi_data; /* IA64: ? PA: swapped txn_data */ u32 eoi_data; /* IA64: ? PA: swapped txn_data */
int vi_txn_irq; /* virtual IRQ number for processor */ int txn_irq; /* virtual IRQ number for processor */
ulong vi_txn_addr; /* IA64: id_eid PA: partial HPA */ ulong txn_addr; /* IA64: id_eid PA: partial HPA */
ulong vi_txn_data; /* IA64: vector PA: EIR bit */ ulong txn_data; /* IA64: vector PA: EIR bit */
u8 vi_status; /* status/flags */ u8 status; /* status/flags */
u8 vi_irqline; /* INTINn(IRQ) */ u8 irqline; /* INTINn(IRQ) */
char vi_name[32]; /* user visible identity */ char name[32]; /* user visible identity */
}; };
......
...@@ -185,8 +185,6 @@ struct lba_device { ...@@ -185,8 +185,6 @@ struct lba_device {
void *iosapic_obj; void *iosapic_obj;
#ifdef __LP64__ #ifdef __LP64__
unsigned long lmmio_base; /* PA_VIEW - fixup MEM addresses */
unsigned long gmmio_base; /* PA_VIEW - Not used (yet) */
unsigned long iop_base; /* PA_VIEW - for IO port accessor funcs */ unsigned long iop_base; /* PA_VIEW - for IO port accessor funcs */
#endif #endif
...@@ -508,7 +506,7 @@ lba_rd_cfg(struct lba_device *d, u32 tok, u8 reg, u32 size) ...@@ -508,7 +506,7 @@ lba_rd_cfg(struct lba_device *d, u32 tok, u8 reg, u32 size)
static int lba_cfg_read(struct pci_bus *bus, unsigned int devfn, int pos, int size, u32 *data) static int lba_cfg_read(struct pci_bus *bus, unsigned int devfn, int pos, int size, u32 *data)
{ {
struct lba_device *d = LBA_DEV(parisc_walk_tree(bus->dev)); struct lba_device *d = LBA_DEV(parisc_walk_tree(bus->bridge));
u32 local_bus = (bus->parent == NULL) ? 0 : bus->secondary; u32 local_bus = (bus->parent == NULL) ? 0 : bus->secondary;
u32 tok = LBA_CFG_TOK(local_bus, devfn); u32 tok = LBA_CFG_TOK(local_bus, devfn);
...@@ -518,7 +516,7 @@ static int lba_cfg_read(struct pci_bus *bus, unsigned int devfn, int pos, int si ...@@ -518,7 +516,7 @@ static int lba_cfg_read(struct pci_bus *bus, unsigned int devfn, int pos, int si
with risk we will miss PCI bus errors. */ with risk we will miss PCI bus errors. */
*data = lba_rd_cfg(d, tok, pos, size); *data = lba_rd_cfg(d, tok, pos, size);
DBG_CFG("%s(%x+%2x) -> 0x%x (a)\n", __FUNCTION__, tok, pos, *data); DBG_CFG("%s(%x+%2x) -> 0x%x (a)\n", __FUNCTION__, tok, pos, *data);
return(*data == ~0UL); return(*data == ~0U);
} }
if (LBA_SKIP_PROBE(d) && (!lba_device_present(bus->secondary, devfn, d))) if (LBA_SKIP_PROBE(d) && (!lba_device_present(bus->secondary, devfn, d)))
...@@ -592,7 +590,7 @@ lba_wr_cfg( struct lba_device *d, u32 tok, u8 reg, u32 data, u32 size) ...@@ -592,7 +590,7 @@ lba_wr_cfg( struct lba_device *d, u32 tok, u8 reg, u32 data, u32 size)
static int lba_cfg_write(struct pci_bus *bus, unsigned int devfn, int pos, int size, u32 data) static int lba_cfg_write(struct pci_bus *bus, unsigned int devfn, int pos, int size, u32 data)
{ {
struct lba_device *d = LBA_DEV(parisc_walk_tree(bus->dev)); struct lba_device *d = LBA_DEV(parisc_walk_tree(bus->bridge));
u32 local_bus = (bus->parent == NULL) ? 0 : bus->secondary; u32 local_bus = (bus->parent == NULL) ? 0 : bus->secondary;
u32 tok = LBA_CFG_TOK(local_bus,devfn); u32 tok = LBA_CFG_TOK(local_bus,devfn);
...@@ -695,20 +693,23 @@ lba_fixup_bus(struct pci_bus *bus) ...@@ -695,20 +693,23 @@ lba_fixup_bus(struct pci_bus *bus)
{ {
struct list_head *ln; struct list_head *ln;
#ifdef FBB_SUPPORT #ifdef FBB_SUPPORT
u16 fbb_enable = PCI_STATUS_FAST_BACK;
u16 status; u16 status;
#endif #endif
struct lba_device *ldev = LBA_DEV(parisc_walk_tree(bus->dev)); struct lba_device *ldev = LBA_DEV(parisc_walk_tree(bus->bridge));
int lba_portbase = HBA_PORT_BASE(ldev->hba.hba_num); int lba_portbase = HBA_PORT_BASE(ldev->hba.hba_num);
DBG("lba_fixup_bus(0x%p) bus %d sysdata 0x%p\n", DBG("lba_fixup_bus(0x%p) bus %d sysdata 0x%p\n",
bus, bus->secondary, bus->dev->platform_data); bus, bus->secondary, bus->bridge->platform_data);
/* /*
** Properly Setup MMIO resources for this bus. ** Properly Setup MMIO resources for this bus.
** pci_alloc_primary_bus() mangles this. ** pci_alloc_primary_bus() mangles this.
*/ */
if (NULL == bus->self) { if (bus->self) {
/* PCI-PCI Bridge */
pci_read_bridge_bases(bus);
} else {
/* Host-PCI Bridge */
int err; int err;
DBG("lba_fixup_bus() %s [%lx/%lx]/%x\n", DBG("lba_fixup_bus() %s [%lx/%lx]/%x\n",
...@@ -725,59 +726,29 @@ lba_fixup_bus(struct pci_bus *bus) ...@@ -725,59 +726,29 @@ lba_fixup_bus(struct pci_bus *bus)
BUG(); BUG();
lba_dump_res(&ioport_resource, 2); lba_dump_res(&ioport_resource, 2);
} }
err = request_resource(&iomem_resource, &(ldev->hba.lmmio_space)); err = request_resource(&iomem_resource, &(ldev->hba.lmmio_space));
if (err < 0) { if (err < 0) {
BUG(); BUG();
lba_dump_res(&iomem_resource, 2); lba_dump_res(&iomem_resource, 2);
} }
bus->resource[0] = &(ldev->hba.io_space); #ifdef __LP64__
bus->resource[1] = &(ldev->hba.lmmio_space); if (ldev->hba.gmmio_space.flags) {
} else { err = request_resource(&iomem_resource, &(ldev->hba.gmmio_space));
/* KLUGE ALERT! if (err < 0) {
** PCI-PCI Bridge resource munging. BUG();
** This hack should go away in the near future. lba_dump_res(&iomem_resource, 2);
** It's based on the Alpha port.
*/
int i;
u16 cmd;
for (i = 0; i < 4; i++) {
bus->resource[i] =
&bus->self->resource[PCI_BRIDGE_RESOURCES+i];
bus->resource[i]->name = bus->name;
} }
#if 0 bus->resource[2] = &(ldev->hba.gmmio_space);
bus->resource[0]->flags |= pci_bridge_check_io(bus->self);
#else
bus->resource[0]->flags |= IORESOURCE_IO;
#endif
bus->resource[1]->flags |= IORESOURCE_MEM;
bus->resource[2]->flags = 0; /* Don't support prefetchable */
bus->resource[3]->flags = 0; /* not used */
/*
** If the PPB is enabled (ie already configured) then
** just read those values.
*/
(void) pci_read_config_word(bus->self, PCI_COMMAND, &cmd);
if (cmd & (PCI_COMMAND_MEMORY | PCI_COMMAND_IO)) {
pci_read_bridge_bases(bus);
} else {
/* Not configured.
** For now, propagate HBA limits to the bus;
** PCI will adjust them later.
*/
bus->resource[0]->end = ldev->hba.io_space.end;
bus->resource[1]->end = ldev->hba.lmmio_space.end;
} }
#endif
/* Turn off downstream PF memory address range by default */ /* advertize Host bridge resources to PCI bus */
bus->resource[2]->start = 1024*1024; bus->resource[0] = &(ldev->hba.io_space);
bus->resource[2]->end = bus->resource[2]->start - 1; bus->resource[1] = &(ldev->hba.lmmio_space);
} }
list_for_each(ln, &bus->devices) { list_for_each(ln, &bus->devices) {
int i; int i;
struct pci_dev *dev = pci_dev_b(ln); struct pci_dev *dev = pci_dev_b(ln);
...@@ -785,7 +756,7 @@ lba_fixup_bus(struct pci_bus *bus) ...@@ -785,7 +756,7 @@ lba_fixup_bus(struct pci_bus *bus)
DBG("lba_fixup_bus() %s\n", pci_name(dev)); DBG("lba_fixup_bus() %s\n", pci_name(dev));
/* Virtualize Device/Bridge Resources. */ /* Virtualize Device/Bridge Resources. */
for (i = 0; i < PCI_NUM_RESOURCES; i++) { for (i = 0; i < PCI_BRIDGE_RESOURCES; i++) {
struct resource *res = &dev->resource[i]; struct resource *res = &dev->resource[i];
/* If resource not allocated - skip it */ /* If resource not allocated - skip it */
...@@ -817,7 +788,7 @@ lba_fixup_bus(struct pci_bus *bus) ...@@ -817,7 +788,7 @@ lba_fixup_bus(struct pci_bus *bus)
** No one on the bus can be allowed to use them. ** No one on the bus can be allowed to use them.
*/ */
(void) pci_read_config_word(dev, PCI_STATUS, &status); (void) pci_read_config_word(dev, PCI_STATUS, &status);
fbb_enable &= status; bus->bridge_ctl &= ~(status & PCI_STATUS_FAST_BACK);
#endif #endif
#ifdef __LP64__ #ifdef __LP64__
...@@ -1069,6 +1040,7 @@ lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev) ...@@ -1069,6 +1040,7 @@ lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
lba_dev->hba.bus_num.start = p->start; lba_dev->hba.bus_num.start = p->start;
lba_dev->hba.bus_num.end = p->end; lba_dev->hba.bus_num.end = p->end;
break; break;
case PAT_LMMIO: case PAT_LMMIO:
/* used to fix up pre-initialized MEM BARs */ /* used to fix up pre-initialized MEM BARs */
lba_dev->hba.lmmio_space_offset = p->start - io->start; lba_dev->hba.lmmio_space_offset = p->start - io->start;
...@@ -1080,23 +1052,28 @@ lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev) ...@@ -1080,23 +1052,28 @@ lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
r->flags = IORESOURCE_MEM; r->flags = IORESOURCE_MEM;
r->parent = r->sibling = r->child = NULL; r->parent = r->sibling = r->child = NULL;
break; break;
case PAT_GMMIO: case PAT_GMMIO:
printk(KERN_WARNING MODULE_NAME /* MMIO space > 4GB phys addr; for 64-bit BAR */
" range[%d] : ignoring GMMIO (0x%lx)\n", r = &(lba_dev->hba.gmmio_space);
i, p->start); r->name = "LBA GMMIO";
lba_dev->gmmio_base = p->start; r->start = p->start;
r->end = p->end;
r->flags = IORESOURCE_MEM;
r->parent = r->sibling = r->child = NULL;
break; break;
case PAT_NPIOP: case PAT_NPIOP:
printk(KERN_WARNING MODULE_NAME printk(KERN_WARNING MODULE_NAME
" range[%d] : ignoring NPIOP (0x%lx)\n", " range[%d] : ignoring NPIOP (0x%lx)\n",
i, p->start); i, p->start);
break; break;
case PAT_PIOP: case PAT_PIOP:
/* /*
** Postable I/O port space is per PCI host adapter. ** Postable I/O port space is per PCI host adapter.
** base of 64MB PIOP region
*/ */
/* save base of 64MB PIOP region */
lba_dev->iop_base = p->start; lba_dev->iop_base = p->start;
r = &(lba_dev->hba.io_space); r = &(lba_dev->hba.io_space);
...@@ -1106,6 +1083,7 @@ lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev) ...@@ -1106,6 +1083,7 @@ lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
r->flags = IORESOURCE_IO; r->flags = IORESOURCE_IO;
r->parent = r->sibling = r->child = NULL; r->parent = r->sibling = r->child = NULL;
break; break;
default: default:
printk(KERN_WARNING MODULE_NAME printk(KERN_WARNING MODULE_NAME
" range[%d] : unknown pat range type (0x%lx)\n", " range[%d] : unknown pat range type (0x%lx)\n",
...@@ -1259,7 +1237,11 @@ lba_hw_init(struct lba_device *d) ...@@ -1259,7 +1237,11 @@ lba_hw_init(struct lba_device *d)
#endif /* DEBUG_LBA_PAT */ #endif /* DEBUG_LBA_PAT */
#ifdef __LP64__ #ifdef __LP64__
#warning FIXME add support for PDC_PAT_IO "Get slot status" - OLAR support /*
* FIXME add support for PDC_PAT_IO "Get slot status" - OLAR support
* Only N-Class and up can really make use of Get slot status.
* maybe L-class too but I've never played with it there.
*/
#endif #endif
/* PDC_PAT_BUG: exhibited in rev 40.48 on L2000 */ /* PDC_PAT_BUG: exhibited in rev 40.48 on L2000 */
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* *
* (c) Copyright 2000 Red Hat Software * (c) Copyright 2000 Red Hat Software
* (c) Copyright 2000 Helge Deller <hdeller@redhat.com> * (c) Copyright 2000 Helge Deller <hdeller@redhat.com>
* (c) Copyright 2001-2003 Helge Deller <deller@gmx.de> * (c) Copyright 2001-2004 Helge Deller <deller@gmx.de>
* (c) Copyright 2001 Randolph Chung <tausq@debian.org> * (c) Copyright 2001 Randolph Chung <tausq@debian.org>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -56,6 +56,7 @@ static int led_heartbeat = 1; ...@@ -56,6 +56,7 @@ static int led_heartbeat = 1;
static int led_diskio = 1; static int led_diskio = 1;
static int led_lanrxtx = 1; static int led_lanrxtx = 1;
static char lcd_text[32]; static char lcd_text[32];
static char lcd_text_default[] = "Linux " UTS_RELEASE;
#if 0 #if 0
#define DPRINTK(x) printk x #define DPRINTK(x) printk x
...@@ -196,19 +197,11 @@ static int led_proc_write(struct file *file, const char *buf, ...@@ -196,19 +197,11 @@ static int led_proc_write(struct file *file, const char *buf,
break; break;
case LED_HASLCD: case LED_HASLCD:
if (*cur == 0) while (*cur && cur[strlen(cur)-1] == '\n')
{
/* reset to default */
lcd_print("Linux " UTS_RELEASE);
}
else
{
/* chop off trailing \n.. if the user gives multiple
* \n then it's all their fault.. */
if (*cur && cur[strlen(cur)-1] == '\n')
cur[strlen(cur)-1] = 0; cur[strlen(cur)-1] = 0;
if (*cur == 0)
cur = lcd_text_default;
lcd_print(cur); lcd_print(cur);
}
break; break;
default: default:
return 0; return 0;
...@@ -438,11 +431,7 @@ static __inline__ int led_get_diskio_activity(void) ...@@ -438,11 +431,7 @@ static __inline__ int led_get_diskio_activity(void)
#define HEARTBEAT_2ND_RANGE_START (HZ*22/100) #define HEARTBEAT_2ND_RANGE_START (HZ*22/100)
#define HEARTBEAT_2ND_RANGE_END (HEARTBEAT_2ND_RANGE_START + HEARTBEAT_LEN) #define HEARTBEAT_2ND_RANGE_END (HEARTBEAT_2ND_RANGE_START + HEARTBEAT_LEN)
#if HZ==100 #define NORMALIZED_COUNT(count) (count/(HZ/100))
#define NORMALIZED_COUNT(count) (count)
#else
#define NORMALIZED_COUNT(count) (count/(HZ/100))
#endif
static void led_tasklet_func(unsigned long unused) static void led_tasklet_func(unsigned long unused)
{ {
...@@ -567,7 +556,7 @@ int __init register_led_driver(int model, char *cmd_reg, char *data_reg) ...@@ -567,7 +556,7 @@ int __init register_led_driver(int model, char *cmd_reg, char *data_reg)
printk(KERN_INFO "LCD display at %p,%p registered\n", printk(KERN_INFO "LCD display at %p,%p registered\n",
LCD_CMD_REG , LCD_DATA_REG); LCD_CMD_REG , LCD_DATA_REG);
led_func_ptr = led_LCD_driver; led_func_ptr = led_LCD_driver;
lcd_print( "Linux " UTS_RELEASE ); lcd_print( lcd_text_default );
led_type = LED_HASLCD; led_type = LED_HASLCD;
break; break;
......
...@@ -44,6 +44,11 @@ ...@@ -44,6 +44,11 @@
#define MODULE_NAME "SBA" #define MODULE_NAME "SBA"
#ifdef CONFIG_PROC_FS
/* depends on proc fs support. But costs CPU performance */
#undef SBA_COLLECT_STATS
#endif
/* /*
** The number of debug flags is a clue - this code is fragile. ** The number of debug flags is a clue - this code is fragile.
** Don't even think about messing with it unless you have ** Don't even think about messing with it unless you have
...@@ -217,7 +222,7 @@ struct ioc { ...@@ -217,7 +222,7 @@ struct ioc {
} saved[DELAYED_RESOURCE_CNT]; } saved[DELAYED_RESOURCE_CNT];
#endif #endif
#ifdef CONFIG_PROC_FS #ifdef SBA_COLLECT_STATS
#define SBA_SEARCH_SAMPLE 0x100 #define SBA_SEARCH_SAMPLE 0x100
unsigned long avg_search[SBA_SEARCH_SAMPLE]; unsigned long avg_search[SBA_SEARCH_SAMPLE];
unsigned long avg_idx; /* current index into avg_search */ unsigned long avg_idx; /* current index into avg_search */
...@@ -560,7 +565,7 @@ static int ...@@ -560,7 +565,7 @@ static int
sba_alloc_range(struct ioc *ioc, size_t size) sba_alloc_range(struct ioc *ioc, size_t size)
{ {
unsigned int pages_needed = size >> IOVP_SHIFT; unsigned int pages_needed = size >> IOVP_SHIFT;
#ifdef CONFIG_PROC_FS #ifdef SBA_COLLECT_STATS
unsigned long cr_start = mfctl(16); unsigned long cr_start = mfctl(16);
#endif #endif
unsigned long pide; unsigned long pide;
...@@ -579,7 +584,8 @@ sba_alloc_range(struct ioc *ioc, size_t size) ...@@ -579,7 +584,8 @@ sba_alloc_range(struct ioc *ioc, size_t size)
if (pide >= (ioc->res_size << 3)) { if (pide >= (ioc->res_size << 3)) {
pide = sba_search_bitmap(ioc, pages_needed); pide = sba_search_bitmap(ioc, pages_needed);
if (pide >= (ioc->res_size << 3)) if (pide >= (ioc->res_size << 3))
panic(__FILE__ ": I/O MMU @ %lx is out of mapping resources\n", ioc->ioc_hpa); panic("%s: I/O MMU @ %lx is out of mapping resources\n",
__FILE__, ioc->ioc_hpa);
} }
#ifdef ASSERT_PDIR_SANITY #ifdef ASSERT_PDIR_SANITY
...@@ -594,7 +600,7 @@ sba_alloc_range(struct ioc *ioc, size_t size) ...@@ -594,7 +600,7 @@ sba_alloc_range(struct ioc *ioc, size_t size)
(uint) ((unsigned long) ioc->res_hint - (unsigned long) ioc->res_map), (uint) ((unsigned long) ioc->res_hint - (unsigned long) ioc->res_map),
ioc->res_bitshift ); ioc->res_bitshift );
#ifdef CONFIG_PROC_FS #ifdef SBA_COLLECT_STATS
{ {
unsigned long cr_end = mfctl(16); unsigned long cr_end = mfctl(16);
unsigned long tmp = cr_end - cr_start; unsigned long tmp = cr_end - cr_start;
...@@ -636,7 +642,7 @@ sba_free_range(struct ioc *ioc, dma_addr_t iova, size_t size) ...@@ -636,7 +642,7 @@ sba_free_range(struct ioc *ioc, dma_addr_t iova, size_t size)
__FUNCTION__, (uint) iova, size, __FUNCTION__, (uint) iova, size,
bits_not_wanted, m, pide, res_ptr, *res_ptr); bits_not_wanted, m, pide, res_ptr, *res_ptr);
#ifdef CONFIG_PROC_FS #ifdef SBA_COLLECT_STATS
ioc->used_pages -= bits_not_wanted; ioc->used_pages -= bits_not_wanted;
#endif #endif
...@@ -854,7 +860,7 @@ sba_map_single(struct device *dev, void *addr, size_t size, ...@@ -854,7 +860,7 @@ sba_map_single(struct device *dev, void *addr, size_t size,
sba_check_pdir(ioc,"Check before sba_map_single()"); sba_check_pdir(ioc,"Check before sba_map_single()");
#endif #endif
#ifdef CONFIG_PROC_FS #ifdef SBA_COLLECT_STATS
ioc->msingle_calls++; ioc->msingle_calls++;
ioc->msingle_pages += size >> IOVP_SHIFT; ioc->msingle_pages += size >> IOVP_SHIFT;
#endif #endif
...@@ -929,7 +935,7 @@ sba_unmap_single(struct device *dev, dma_addr_t iova, size_t size, ...@@ -929,7 +935,7 @@ sba_unmap_single(struct device *dev, dma_addr_t iova, size_t size,
spin_lock_irqsave(&ioc->res_lock, flags); spin_lock_irqsave(&ioc->res_lock, flags);
#ifdef CONFIG_PROC_FS #ifdef SBA_COLLECT_STATS
ioc->usingle_calls++; ioc->usingle_calls++;
ioc->usingle_pages += size >> IOVP_SHIFT; ioc->usingle_pages += size >> IOVP_SHIFT;
#endif #endif
...@@ -1057,7 +1063,7 @@ sba_fill_pdir( ...@@ -1057,7 +1063,7 @@ sba_fill_pdir(
printk(KERN_DEBUG " %2d : %08lx/%05x %p/%05x\n", printk(KERN_DEBUG " %2d : %08lx/%05x %p/%05x\n",
nents, nents,
(unsigned long) sg_dma_address(startsg), cnt, (unsigned long) sg_dma_address(startsg), cnt,
sg_virt_address(startsg), startsg->length sg_virt_addr(startsg), startsg->length
); );
#else #else
DBG_RUN_SG(" %d : %08lx/%05x %p/%05x\n", DBG_RUN_SG(" %d : %08lx/%05x %p/%05x\n",
...@@ -1093,7 +1099,7 @@ sba_fill_pdir( ...@@ -1093,7 +1099,7 @@ sba_fill_pdir(
cnt += dma_offset; cnt += dma_offset;
dma_offset=0; /* only want offset on first chunk */ dma_offset=0; /* only want offset on first chunk */
cnt = ROUNDUP(cnt, IOVP_SIZE); cnt = ROUNDUP(cnt, IOVP_SIZE);
#ifdef CONFIG_PROC_FS #ifdef SBA_COLLECT_STATS
ioc->msg_pages += cnt >> IOVP_SHIFT; ioc->msg_pages += cnt >> IOVP_SHIFT;
#endif #endif
do { do {
...@@ -1300,7 +1306,7 @@ sba_map_sg(struct device *dev, struct scatterlist *sglist, int nents, ...@@ -1300,7 +1306,7 @@ sba_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
} }
#endif #endif
#ifdef CONFIG_PROC_FS #ifdef SBA_COLLECT_STATS
ioc->msg_calls++; ioc->msg_calls++;
#endif #endif
...@@ -1365,7 +1371,7 @@ sba_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents, ...@@ -1365,7 +1371,7 @@ sba_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents,
ioc = GET_IOC(dev); ioc = GET_IOC(dev);
ASSERT(ioc); ASSERT(ioc);
#ifdef CONFIG_PROC_FS #ifdef SBA_COLLECT_STATS
ioc->usg_calls++; ioc->usg_calls++;
#endif #endif
...@@ -1378,7 +1384,7 @@ sba_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents, ...@@ -1378,7 +1384,7 @@ sba_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents,
while (sg_dma_len(sglist) && nents--) { while (sg_dma_len(sglist) && nents--) {
sba_unmap_single(dev, sg_dma_address(sglist), sg_dma_len(sglist), direction); sba_unmap_single(dev, sg_dma_address(sglist), sg_dma_len(sglist), direction);
#ifdef CONFIG_PROC_FS #ifdef SBA_COLLECT_STATS
ioc->usg_pages += ((sg_dma_address(sglist) & ~IOVP_MASK) + sg_dma_len(sglist) + IOVP_SIZE - 1) >> PAGE_SHIFT; ioc->usg_pages += ((sg_dma_address(sglist) & ~IOVP_MASK) + sg_dma_len(sglist) + IOVP_SIZE - 1) >> PAGE_SHIFT;
ioc->usingle_calls--; /* kluge since call is unmap_sg() */ ioc->usingle_calls--; /* kluge since call is unmap_sg() */
#endif #endif
...@@ -1680,6 +1686,21 @@ sba_hw_init(struct sba_device *sba_dev) ...@@ -1680,6 +1686,21 @@ sba_hw_init(struct sba_device *sba_dev)
int num_ioc; int num_ioc;
u64 ioc_ctl; u64 ioc_ctl;
if (!is_pdc_pat()) {
/* Shutdown the USB controller on Astro-based workstations.
** Once we reprogram the IOMMU, the next DMA performed by
** USB will HPMC the box.
*/
pdc_io_reset_devices();
/*
** XXX May need something more sophisticated to deal
** with DMA from LAN. Maybe use page zero boot device
** as a handle to talk to PDC about which device to
** shutdown. This also needs to work for is_pdc_pat().
*/
}
ioc_ctl = READ_REG(sba_dev->sba_hpa+IOC_CTRL); ioc_ctl = READ_REG(sba_dev->sba_hpa+IOC_CTRL);
DBG_INIT("%s() hpa 0x%lx ioc_ctl 0x%Lx ->", DBG_INIT("%s() hpa 0x%lx ioc_ctl 0x%Lx ->",
__FUNCTION__, sba_dev->sba_hpa, ioc_ctl); __FUNCTION__, sba_dev->sba_hpa, ioc_ctl);
...@@ -1766,7 +1787,8 @@ sba_common_init(struct sba_device *sba_dev) ...@@ -1766,7 +1787,8 @@ sba_common_init(struct sba_device *sba_dev)
if (NULL == sba_dev->ioc[i].res_map) if (NULL == sba_dev->ioc[i].res_map)
{ {
panic(__FILE__ ":%s() could not allocate resource map\n", __FUNCTION__ ); panic("%s:%s() could not allocate resource map\n",
__FILE__, __FUNCTION__ );
} }
memset(sba_dev->ioc[i].res_map, 0, res_size); memset(sba_dev->ioc[i].res_map, 0, res_size);
...@@ -1829,7 +1851,9 @@ static int sba_proc_info(char *buf, char **start, off_t offset, int len) ...@@ -1829,7 +1851,9 @@ static int sba_proc_info(char *buf, char **start, off_t offset, int len)
struct sba_device *sba_dev = sba_list; struct sba_device *sba_dev = sba_list;
struct ioc *ioc = &sba_dev->ioc[0]; /* FIXME: Multi-IOC support! */ struct ioc *ioc = &sba_dev->ioc[0]; /* FIXME: Multi-IOC support! */
int total_pages = (int) (ioc->res_size << 3); /* 8 bits per byte */ int total_pages = (int) (ioc->res_size << 3); /* 8 bits per byte */
#ifdef SBA_COLLECT_STATS
unsigned long i = 0, avg = 0, min, max; unsigned long i = 0, avg = 0, min, max;
#endif
sprintf(buf, "%s rev %d.%d\n", sprintf(buf, "%s rev %d.%d\n",
sba_dev->name, sba_dev->name,
...@@ -1841,13 +1865,14 @@ static int sba_proc_info(char *buf, char **start, off_t offset, int len) ...@@ -1841,13 +1865,14 @@ static int sba_proc_info(char *buf, char **start, off_t offset, int len)
(int) ((ioc->res_size << 3) * sizeof(u64)), /* 8 bits/byte */ (int) ((ioc->res_size << 3) * sizeof(u64)), /* 8 bits/byte */
total_pages); total_pages);
sprintf(buf, "%sResource bitmap : %d bytes (%d pages)\n",
buf, ioc->res_size, ioc->res_size << 3); /* 8 bits per byte */
#ifdef SBA_COLLECT_STATS
sprintf(buf, "%sIO PDIR entries : %ld free %ld used (%d%%)\n", buf, sprintf(buf, "%sIO PDIR entries : %ld free %ld used (%d%%)\n", buf,
total_pages - ioc->used_pages, ioc->used_pages, total_pages - ioc->used_pages, ioc->used_pages,
(int) (ioc->used_pages * 100 / total_pages)); (int) (ioc->used_pages * 100 / total_pages));
sprintf(buf, "%sResource bitmap : %d bytes (%d pages)\n",
buf, ioc->res_size, ioc->res_size << 3); /* 8 bits per byte */
min = max = ioc->avg_search[0]; min = max = ioc->avg_search[0];
for (i = 0; i < SBA_SEARCH_SAMPLE; i++) { for (i = 0; i < SBA_SEARCH_SAMPLE; i++) {
avg += ioc->avg_search[i]; avg += ioc->avg_search[i];
...@@ -1876,6 +1901,7 @@ static int sba_proc_info(char *buf, char **start, off_t offset, int len) ...@@ -1876,6 +1901,7 @@ static int sba_proc_info(char *buf, char **start, off_t offset, int len)
sprintf(buf, "%spci_unmap_sg() : %12ld calls %12ld pages (avg %d/1000)\n", sprintf(buf, "%spci_unmap_sg() : %12ld calls %12ld pages (avg %d/1000)\n",
buf, ioc->usg_calls, ioc->usg_pages, buf, ioc->usg_calls, ioc->usg_pages,
(int) ((ioc->usg_pages * 1000)/ioc->usg_calls)); (int) ((ioc->usg_pages * 1000)/ioc->usg_calls));
#endif
return strlen(buf); return strlen(buf);
} }
......
...@@ -9,7 +9,8 @@ ...@@ -9,7 +9,8 @@
* (C) Copyright 2000 Linuxcare Canada, Inc. * (C) Copyright 2000 Linuxcare Canada, Inc.
* (C) Copyright 2000 Martin K. Petersen <mkp@linuxcare.com> * (C) Copyright 2000 Martin K. Petersen <mkp@linuxcare.com>
* (C) Copyright 2000 Alex deVries <alex@linuxcare.com> * (C) Copyright 2000 Alex deVries <alex@linuxcare.com>
* (C) Copyright 2001 John Marvin <jsm@fc.hp.com> * (C) Copyright 2001 John Marvin <jsm fc hp com>
* (C) Copyright 2003 Grant Grundler <grundler parisc-linux org>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
...@@ -73,24 +74,16 @@ ...@@ -73,24 +74,16 @@
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/superio.h> #include <asm/superio.h>
static struct superio_device sio_dev = { static struct superio_device sio_dev;
.iosapic_irq = -1
};
#undef DEBUG_INIT
void #undef DEBUG_SUPERIO_INIT
superio_inform_irq(int irq)
{
if (sio_dev.iosapic_irq != -1) {
printk(KERN_ERR "SuperIO: superio_inform_irq called twice! (more than one SuperIO?)\n");
BUG();
return;
}
sio_dev.iosapic_irq = irq; #ifdef DEBUG_SUPERIO_INIT
} #define DBG_INIT(x...) printk(x)
#else
#define DBG_INIT(x...)
#endif
static irqreturn_t static irqreturn_t
superio_interrupt(int irq, void *devp, struct pt_regs *regs) superio_interrupt(int irq, void *devp, struct pt_regs *regs)
...@@ -135,7 +128,6 @@ superio_interrupt(int irq, void *devp, struct pt_regs *regs) ...@@ -135,7 +128,6 @@ superio_interrupt(int irq, void *devp, struct pt_regs *regs)
} }
/* Call the appropriate device's interrupt */ /* Call the appropriate device's interrupt */
do_irq(&sio->irq_region->action[local_irq], do_irq(&sio->irq_region->action[local_irq],
sio->irq_region->data.irqbase + local_irq, sio->irq_region->data.irqbase + local_irq,
regs); regs);
...@@ -153,34 +145,39 @@ superio_init(struct superio_device *sio) ...@@ -153,34 +145,39 @@ superio_init(struct superio_device *sio)
{ {
struct pci_dev *pdev = sio->lio_pdev; struct pci_dev *pdev = sio->lio_pdev;
u16 word; u16 word;
u8 i;
if (!pdev || sio->iosapic_irq == -1) { if (sio->suckyio_irq_enabled)
printk(KERN_ERR "All SuperIO functions not found!\n");
BUG();
return; return;
}
if (!pdev) BUG();
if (!sio->usb_pdev) BUG();
/* use the IRQ iosapic found for USB INT D... */
pdev->irq = sio->usb_pdev->irq;
/* ...then properly fixup the USB to point at suckyio PIC */
sio->usb_pdev->irq = superio_fixup_irq(sio->usb_pdev);
printk (KERN_INFO "SuperIO: Found NS87560 Legacy I/O device at %s (IRQ %i) \n", printk (KERN_INFO "SuperIO: Found NS87560 Legacy I/O device at %s (IRQ %i) \n",
pci_name(pdev),sio->iosapic_irq); pci_name(pdev),pdev->irq);
/* Find our I/O devices */ /* Find our I/O devices */
pci_read_config_word (pdev, SIO_SP1BAR, &sio->sp1_base); pci_read_config_dword (pdev, SIO_SP1BAR, &sio->sp1_base);
sio->sp1_base &= ~1; sio->sp1_base &= ~1;
printk (KERN_INFO "SuperIO: Serial port 1 at 0x%x\n", sio->sp1_base); printk (KERN_INFO "SuperIO: Serial port 1 at 0x%x\n", sio->sp1_base);
pci_read_config_word (pdev, SIO_SP2BAR, &sio->sp2_base); pci_read_config_dword (pdev, SIO_SP2BAR, &sio->sp2_base);
sio->sp2_base &= ~1; sio->sp2_base &= ~1;
printk (KERN_INFO "SuperIO: Serial port 2 at 0x%x\n", sio->sp2_base); printk (KERN_INFO "SuperIO: Serial port 2 at 0x%x\n", sio->sp2_base);
pci_read_config_word (pdev, SIO_PPBAR, &sio->pp_base); pci_read_config_dword (pdev, SIO_PPBAR, &sio->pp_base);
sio->pp_base &= ~1; sio->pp_base &= ~1;
printk (KERN_INFO "SuperIO: Parallel port at 0x%x\n", sio->pp_base); printk (KERN_INFO "SuperIO: Parallel port at 0x%x\n", sio->pp_base);
pci_read_config_word (pdev, SIO_FDCBAR, &sio->fdc_base); pci_read_config_dword (pdev, SIO_FDCBAR, &sio->fdc_base);
sio->fdc_base &= ~1; sio->fdc_base &= ~1;
printk (KERN_INFO "SuperIO: Floppy controller at 0x%x\n", sio->fdc_base); printk (KERN_INFO "SuperIO: Floppy controller at 0x%x\n", sio->fdc_base);
pci_read_config_word (pdev, SIO_ACPIBAR, &sio->acpi_base); pci_read_config_dword (pdev, SIO_ACPIBAR, &sio->acpi_base);
sio->acpi_base &= ~1; sio->acpi_base &= ~1;
printk (KERN_INFO "SuperIO: ACPI at 0x%x\n", sio->acpi_base); printk (KERN_INFO "SuperIO: ACPI at 0x%x\n", sio->acpi_base);
...@@ -192,24 +189,53 @@ superio_init(struct superio_device *sio) ...@@ -192,24 +189,53 @@ superio_init(struct superio_device *sio)
pci_read_config_word (pdev, PCI_COMMAND, &word); pci_read_config_word (pdev, PCI_COMMAND, &word);
word |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_IO; word |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_IO;
pci_write_config_word (pdev, PCI_COMMAND, word); pci_write_config_word (pdev, PCI_COMMAND, word);
pci_set_master (pdev); pci_set_master (pdev);
pci_enable_device(pdev);
/*
* Next project is programming the onboard interrupt controllers.
* PDC hasn't done this for us, since it's using polled I/O.
*
* XXX Use dword writes to avoid bugs in Elroy or Suckyio Config
* space access. PCI is by nature a 32-bit bus and config
* space can be sensitive to that.
*/
/* Next project is programming the onboard interrupt /* 0x64 - 0x67 :
* controllers. PDC hasn't done this for us, since it's using DMA Rtg 2
* polled I/O. DMA Rtg 3
DMA Chan Ctl
TRIGGER_1 == 0x82 USB & IDE level triggered, rest to edge
*/ */
pci_write_config_dword (pdev, 0x64, 0x82000000U);
/* Set PIC interrupts to edge triggered */ /* 0x68 - 0x6b :
pci_write_config_byte (pdev, TRIGGER_1, 0x0); TRIGGER_2 == 0x00 all edge triggered (not used)
pci_write_config_byte (pdev, TRIGGER_2, 0x0); CFG_IR_SER == 0x43 SerPort1 = IRQ3, SerPort2 = IRQ4
CFG_IR_PF == 0x65 ParPort = IRQ5, FloppyCtlr = IRQ6
CFG_IR_IDE == 0x07 IDE1 = IRQ7, reserved
*/
pci_write_config_dword (pdev, TRIGGER_2, 0x07654300U);
/* Disable all interrupt routing */ /* 0x6c - 0x6f :
for (i = IR_LOW ; i < IR_HIGH ; i++) CFG_IR_INTAB == 0x00
pci_write_config_byte (pdev, i, 0x0); CFG_IR_INTCD == 0x10 USB = IRQ1
CFG_IR_PS2 == 0x00
CFG_IR_FXBUS == 0x00
*/
pci_write_config_dword (pdev, CFG_IR_INTAB, 0x00001000U);
/* 0x70 - 0x73 :
CFG_IR_USB == 0x00 not used. USB is connected to INTD.
CFG_IR_ACPI == 0x00 not used.
DMA Priority == 0x4c88 Power on default value. NFC.
*/
pci_write_config_dword (pdev, CFG_IR_USB, 0x4c880000U);
/* PIC1 Initialization Command Word register programming */ /* PIC1 Initialization Command Word register programming */
outb (0x11,IC_PIC1+0); /* ICW1: ICW4 write req | ICW1 */ outb (0x11,IC_PIC1+0); /* ICW1: ICW4 write req | ICW1 */
outb (0x00,IC_PIC1+1); /* ICW2: N/A */ outb (0x00,IC_PIC1+1); /* ICW2: interrupt vector table - not used */
outb (0x04,IC_PIC1+1); /* ICW3: Cascade */ outb (0x04,IC_PIC1+1); /* ICW3: Cascade */
outb (0x01,IC_PIC1+1); /* ICW4: x86 mode */ outb (0x01,IC_PIC1+1); /* ICW4: x86 mode */
...@@ -228,19 +254,8 @@ superio_init(struct superio_device *sio) ...@@ -228,19 +254,8 @@ superio_init(struct superio_device *sio)
outb (0x68,IC_PIC1+0); /* OCW3: OCW3 select | ESMM | SMM */ outb (0x68,IC_PIC1+0); /* OCW3: OCW3 select | ESMM | SMM */
/* Write master mask reg */ /* Write master mask reg */
outb (0xff,IC_PIC1+1); outb (0xff,IC_PIC1+1);
/* Set up interrupt routing */
pci_write_config_byte (pdev, IR_USB, 0x10); /* USB on IRQ1 */
pci_write_config_byte (pdev, IR_SER, 0x43); /* SP1 on IRQ3, SP2 on IRQ4 */
pci_write_config_byte (pdev, IR_PFD, 0x65); /* PAR on IRQ5, FDC on IRQ6 */
pci_write_config_byte (pdev, IR_IDE, 0x07); /* IDE1 on IRQ7 */
/* Set USB and IDE to level triggered interrupts, rest to edge */
pci_write_config_byte (pdev, TRIGGER_1, 0x82); /* IRQ 1 and 7 */
/* Setup USB power regulation */ /* Setup USB power regulation */
outb(1, sio->acpi_base + USB_REG_CR); outb(1, sio->acpi_base + USB_REG_CR);
if (inb(sio->acpi_base + USB_REG_CR) & 1) if (inb(sio->acpi_base + USB_REG_CR) & 1)
...@@ -248,20 +263,18 @@ superio_init(struct superio_device *sio) ...@@ -248,20 +263,18 @@ superio_init(struct superio_device *sio)
else else
printk(KERN_ERR "USB regulator not initialized!\n"); printk(KERN_ERR "USB regulator not initialized!\n");
pci_enable_device(pdev); if (request_irq(pdev->irq, superio_interrupt, SA_INTERRUPT,
"SuperIO", (void *)sio)) {
if (request_irq(sio->iosapic_irq,superio_interrupt,SA_INTERRUPT,
"SuperIO",(void *)sio)) {
printk(KERN_ERR "SuperIO: could not get irq\n"); printk(KERN_ERR "SuperIO: could not get irq\n");
BUG(); BUG();
return; return;
} }
sio->iosapic_irq_enabled = 1; sio->suckyio_irq_enabled = 1;
} }
static void static void
superio_disable_irq(void *dev, int local_irq) superio_disable_irq(void *dev, int local_irq)
{ {
...@@ -283,30 +296,21 @@ superio_disable_irq(void *dev, int local_irq) ...@@ -283,30 +296,21 @@ superio_disable_irq(void *dev, int local_irq)
static void static void
superio_enable_irq(void *dev, int local_irq) superio_enable_irq(void *dev, int local_irq)
{ {
struct superio_device *sio = (struct superio_device *)dev;
u8 r8; u8 r8;
if ((local_irq < 1) || (local_irq == 2) || (local_irq > 7)) { if ((local_irq < 1) || (local_irq == 2) || (local_irq > 7)) {
printk(KERN_ERR "SuperIO: Illegal irq number.\n"); printk(KERN_ERR "SuperIO: Illegal irq number (%d).\n", local_irq);
BUG(); BUG();
return; return;
} }
/*
* It's possible that we haven't initialized the legacy IO
* function yet. If not, do it now.
*/
if (!sio->iosapic_irq_enabled)
superio_init(sio);
/* Unmask interrupt */ /* Unmask interrupt */
r8 = inb(IC_PIC1+1); r8 = inb(IC_PIC1+1);
r8 &= ~(1 << local_irq); r8 &= ~(1 << local_irq);
outb (r8,IC_PIC1+1); outb (r8,IC_PIC1+1);
} }
static void static void
superio_mask_irq(void *dev, int local_irq) superio_mask_irq(void *dev, int local_irq)
{ {
...@@ -326,7 +330,7 @@ static struct irq_region_ops superio_irq_ops = { ...@@ -326,7 +330,7 @@ static struct irq_region_ops superio_irq_ops = {
.unmask_irq = superio_unmask_irq .unmask_irq = superio_unmask_irq
}; };
#ifdef DEBUG_INIT #ifdef DEBUG_SUPERIO_INIT
static unsigned short expected_device[3] = { static unsigned short expected_device[3] = {
PCI_DEVICE_ID_NS_87415, PCI_DEVICE_ID_NS_87415,
PCI_DEVICE_ID_NS_87560_LIO, PCI_DEVICE_ID_NS_87560_LIO,
...@@ -338,7 +342,7 @@ int superio_fixup_irq(struct pci_dev *pcidev) ...@@ -338,7 +342,7 @@ int superio_fixup_irq(struct pci_dev *pcidev)
{ {
int local_irq; int local_irq;
#ifdef DEBUG_INIT #ifdef DEBUG_SUPERIO_INIT
int fn; int fn;
fn = PCI_FUNC(pcidev->devfn); fn = PCI_FUNC(pcidev->devfn);
...@@ -375,9 +379,10 @@ int superio_fixup_irq(struct pci_dev *pcidev) ...@@ -375,9 +379,10 @@ int superio_fixup_irq(struct pci_dev *pcidev)
local_irq = IDE_IRQ; local_irq = IDE_IRQ;
break; break;
case PCI_DEVICE_ID_NS_87560_LIO: /* Function 1 */ case PCI_DEVICE_ID_NS_87560_LIO: /* Function 1 */
sio_dev.lio_pdev = pcidev; /* save for later initialization */ sio_dev.lio_pdev = pcidev; /* save for superio_init() */
return -1; return -1;
case PCI_DEVICE_ID_NS_87560_USB: /* Function 2 */ case PCI_DEVICE_ID_NS_87560_USB: /* Function 2 */
sio_dev.usb_pdev = pcidev; /* save for superio_init() */
local_irq = USB_IRQ; local_irq = USB_IRQ;
break; break;
default: default:
...@@ -411,20 +416,29 @@ superio_serial_init(void) ...@@ -411,20 +416,29 @@ superio_serial_init(void)
{ {
#ifdef CONFIG_SERIAL_8250 #ifdef CONFIG_SERIAL_8250
int retval; int retval;
extern void serial8250_console_init(void); /* drivers/serial/8250.c */
if (!sio_dev.irq_region) if (!sio_dev.irq_region)
return; /* superio not present */ return; /* superio not present */
if (!sio_dev.iosapic_irq_enabled) if (!serial) {
superio_init(&sio_dev); printk(KERN_WARNING "SuperIO: Could not get memory for serial struct.\n");
return;
}
serial[0].iobase = sio_dev.sp1_base; serial[0].iobase = sio_dev.sp1_base;
retval = early_serial_setup(&serial[0]); serial[0].irq = sio_dev.irq_region->data.irqbase + SP1_IRQ;
if (retval < 0) retval = early_serial_setup(&serial[0]);
if (retval < 0) {
printk(KERN_WARNING "SuperIO: Register Serial #0 failed.\n"); printk(KERN_WARNING "SuperIO: Register Serial #0 failed.\n");
return;
}
serial8250_console_init();
serial[1].iobase = sio_dev.sp2_base; serial[1].iobase = sio_dev.sp2_base;
serial[1].irq = sio_dev.irq_region->data.irqbase + SP2_IRQ;
retval = early_serial_setup(&serial[1]); retval = early_serial_setup(&serial[1]);
if (retval < 0) if (retval < 0)
...@@ -432,30 +446,20 @@ superio_serial_init(void) ...@@ -432,30 +446,20 @@ superio_serial_init(void)
#endif /* CONFIG_SERIAL_8250 */ #endif /* CONFIG_SERIAL_8250 */
} }
EXPORT_SYMBOL(superio_serial_init);
static void __devinit
#ifdef CONFIG_PARPORT_PC
void __devinit
superio_parport_init(void) superio_parport_init(void)
{ {
if (!sio_dev.irq_region) #ifdef CONFIG_PARPORT_PC
return; /* superio not present */
if (!sio_dev.iosapic_irq_enabled)
superio_init(&sio_dev);
if (!parport_pc_probe_port(sio_dev.pp_base, if (!parport_pc_probe_port(sio_dev.pp_base,
0 /*base_hi*/, 0 /*base_hi*/,
sio_dev.irq_region->data.irqbase + PAR_IRQ, sio_dev.irq_region->data.irqbase + PAR_IRQ,
PARPORT_DMA_NONE /* dma */, PARPORT_DMA_NONE /* dma */,
NULL /*struct pci_dev* */)) NULL /*struct pci_dev* */) )
printk(KERN_WARNING "SuperIO: Probing parallel port failed.\n"); printk(KERN_WARNING "SuperIO: Probing parallel port failed.\n");
}
EXPORT_SYMBOL(superio_parport_init);
#endif /* CONFIG_PARPORT_PC */ #endif /* CONFIG_PARPORT_PC */
}
int int
...@@ -471,36 +475,35 @@ EXPORT_SYMBOL(superio_get_ide_irq); ...@@ -471,36 +475,35 @@ EXPORT_SYMBOL(superio_get_ide_irq);
static int __devinit superio_probe(struct pci_dev *dev, const struct pci_device_id *id) static int __devinit superio_probe(struct pci_dev *dev, const struct pci_device_id *id)
{ {
#ifdef DEBUG_INIT
printk("superio_probe(%s) ven 0x%x dev 0x%x sv 0x%x sd 0x%x class 0x%x\n", /*
** superio_probe(00:0e.0) ven 0x100b dev 0x2 sv 0x0 sd 0x0 class 0x1018a
** superio_probe(00:0e.1) ven 0x100b dev 0xe sv 0x0 sd 0x0 class 0x68000
** superio_probe(00:0e.2) ven 0x100b dev 0x12 sv 0x0 sd 0x0 class 0xc0310
*/
DBG_INIT("superio_probe(%s) ven 0x%x dev 0x%x sv 0x%x sd 0x%x class 0x%x\n",
pci_name(dev), pci_name(dev),
dev->vendor, dev->device, dev->vendor, dev->device,
dev->subsystem_vendor, dev->subsystem_device, dev->subsystem_vendor, dev->subsystem_device,
dev->class); dev->class);
/*
** superio_probe(00:0e.0) ven 0x100b dev 0x2 sv 0x0 sd 0x0 class 0x1018a
** superio_probe(00:0e.1) ven 0x100b dev 0xe sv 0x0 sd 0x0 class 0x68000
** superio_probe(00:0e.2) ven 0x100b dev 0x12 sv 0x0 sd 0x0 class 0xc0310
*/
#endif
/* superio_fixup_irq(dev); */ superio_init(&sio_dev);
if (dev->device == PCI_DEVICE_ID_NS_87560_LIO) { if (dev->device == PCI_DEVICE_ID_NS_87560_LIO) { /* Function 1 */
#ifdef CONFIG_PARPORT_PC
superio_parport_init(); superio_parport_init();
#endif
#ifdef CONFIG_SERIAL_8250
superio_serial_init(); superio_serial_init();
#endif /* REVISIT XXX : superio_fdc_init() ? */
/* REVISIT : superio_fdc_init() ? */
return 0; return 0;
} else if (dev->device == PCI_DEVICE_ID_NS_87415) { /* Function 0 */
DBG_INIT("superio_probe: ignoring IDE 87415\n");
} else if (dev->device == PCI_DEVICE_ID_NS_87560_USB) { /* Function 2 */
DBG_INIT("superio_probe: ignoring USB OHCI controller\n");
} else { } else {
/* don't claim this device; let whatever either driver DBG_INIT("superio_probe: WTF? Fire Extinguisher?\n");
* do it
*/
return -1;
} }
/* Let appropriate other driver claim this device. */
return -ENODEV;
} }
static struct pci_device_id superio_tbl[] = { static struct pci_device_id superio_tbl[] = {
...@@ -524,10 +527,6 @@ static void __exit superio_exit(void) ...@@ -524,10 +527,6 @@ static void __exit superio_exit(void)
pci_unregister_driver(&superio_driver); pci_unregister_driver(&superio_driver);
} }
/* Make late initcall to ensure the serial and tty layers are initialised
* before we start superio.
*
* FIXME: does this break the superio console?
*/
module_init(superio_modinit); module_init(superio_modinit);
module_exit(superio_exit); module_exit(superio_exit);
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/serial.h> #include <linux/serial.h>
#include <linux/console.h> #include <linux/console.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/delay.h> /* for udelay */
#include <asm/io.h> #include <asm/io.h>
#include <asm/parisc-device.h> #include <asm/parisc-device.h>
...@@ -47,15 +48,17 @@ ...@@ -47,15 +48,17 @@
#define MUX_STATUS(status) ((status & 0xF000) == 0x8000) #define MUX_STATUS(status) ((status & 0xF000) == 0x8000)
#define MUX_BREAK(status) ((status & 0xF000) == 0x2000) #define MUX_BREAK(status) ((status & 0xF000) == 0x2000)
#define UART_NR 8 #define MUX_NR 256
struct mux_card { static unsigned int port_cnt = 0;
struct uart_port ports[UART_NR]; static struct uart_port mux_ports[MUX_NR];
struct uart_driver drv;
struct mux_card *next; static struct uart_driver mux_driver = {
}; .owner = THIS_MODULE,
.driver_name = "ttyB",
static struct mux_card mux_card_head = { .dev_name = "ttyB",
.next = NULL, .major = MUX_MAJOR,
.minor = 0,
.nr = MUX_NR,
}; };
static struct timer_list mux_timer; static struct timer_list mux_timer;
...@@ -181,7 +184,7 @@ static void mux_write(struct uart_port *port) ...@@ -181,7 +184,7 @@ static void mux_write(struct uart_port *port)
return; return;
} }
count = (port->fifosize >> 1) - UART_GET_FIFO_CNT(port); count = (port->fifosize) - UART_GET_FIFO_CNT(port);
do { do {
UART_PUT_CHAR(port, xmit->buf[xmit->tail]); UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
...@@ -191,6 +194,9 @@ static void mux_write(struct uart_port *port) ...@@ -191,6 +194,9 @@ static void mux_write(struct uart_port *port)
} while(--count > 0); } while(--count > 0);
while(UART_GET_FIFO_CNT(port))
udelay(1);
if(uart_circ_chars_pending(xmit) < WAKEUP_CHARS) if(uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port); uart_write_wakeup(port);
...@@ -361,28 +367,46 @@ static int mux_verify_port(struct uart_port *port, struct serial_struct *ser) ...@@ -361,28 +367,46 @@ static int mux_verify_port(struct uart_port *port, struct serial_struct *ser)
static void mux_poll(unsigned long unused) static void mux_poll(unsigned long unused)
{ {
int i; int i;
struct mux_card *card = &mux_card_head;
while(card) { for(i = 0; i < port_cnt; ++i) {
for(i = 0; i < UART_NR; ++i) { if(!mux_ports[i].info)
if(!card->ports[i].info)
continue; continue;
mux_read(&card->ports[i]); mux_read(&mux_ports[i]);
mux_write(&card->ports[i]); mux_write(&mux_ports[i]);
}
card = card->next;
} }
mod_timer(&mux_timer, jiffies + MUX_POLL_DELAY); mod_timer(&mux_timer, jiffies + MUX_POLL_DELAY);
} }
#ifdef CONFIG_SERIAL_MUX_CONSOLE #ifdef CONFIG_SERIAL_MUX_CONSOLE
static void mux_console_write(struct console *co, const char *s, unsigned count)
{
while(count--)
pdc_iodc_putc(*s++);
}
static int mux_console_setup(struct console *co, char *options)
{
return 0;
}
struct tty_driver *mux_console_device(struct console *co, int *index)
{
*index = co->index;
return mux_driver.tty_driver;
}
static struct console mux_console = { static struct console mux_console = {
.name = "ttyB", .name = "ttyB",
.flags = CON_PRINTBUFFER, .write = mux_console_write,
.device = mux_console_device,
.setup = mux_console_setup,
.flags = CON_BOOT|CON_PRINTBUFFER|CON_ENABLED,
.index = 0, .index = 0,
}; };
#define MUX_CONSOLE &mux_console #define MUX_CONSOLE &mux_console
#else #else
#define MUX_CONSOLE NULL #define MUX_CONSOLE NULL
...@@ -416,63 +440,37 @@ static struct uart_ops mux_pops = { ...@@ -416,63 +440,37 @@ static struct uart_ops mux_pops = {
*/ */
static int __init mux_probe(struct parisc_device *dev) static int __init mux_probe(struct parisc_device *dev)
{ {
int i, j, ret, ports, port_cnt = 0; int i, status, ports;
u8 iodc_data[8]; u8 iodc_data[32];
unsigned long bytecnt; unsigned long bytecnt;
struct uart_port *port; struct uart_port *port;
struct mux_card *card = &mux_card_head;
ret = pdc_iodc_read(&bytecnt, dev->hpa, 0, iodc_data, 8); status = pdc_iodc_read(&bytecnt, dev->hpa, 0, iodc_data, 32);
if(ret != PDC_OK) { if(status != PDC_OK) {
printk(KERN_ERR "Serial mux: Unable to read IODC.\n"); printk(KERN_ERR "Serial mux: Unable to read IODC.\n");
return 1; return 1;
} }
ports = GET_MUX_PORTS(iodc_data); ports = GET_MUX_PORTS(iodc_data);
printk(KERN_INFO "Serial mux driver (%d ports) Revision: 0.2\n", printk(KERN_INFO "Serial mux driver (%d ports) Revision: 0.3\n", ports);
ports);
if(!card->drv.nr) { if(!port_cnt) {
init_timer(&mux_timer); mux_driver.cons = MUX_CONSOLE;
mux_timer.function = mux_poll;
} else {
port_cnt += UART_NR;
while(card->next) {
card = card->next;
port_cnt += UART_NR;
}
}
for(i = 0; i < ports / UART_NR; ++i) {
if(card->drv.nr) {
card->next = kmalloc(sizeof(struct mux_card), GFP_KERNEL);
if(!card->next) {
printk(KERN_ERR "Serial mux: Unable to allocate memory.\n");
return 1;
}
memset(card->next, '\0', sizeof(struct mux_card));
card = card->next;
}
card->drv.owner = THIS_MODULE; status = uart_register_driver(&mux_driver);
card->drv.driver_name = "ttyB"; if(status) {
card->drv.dev_name = "ttyB";
card->drv.major = MUX_MAJOR;
card->drv.minor = port_cnt;
card->drv.nr = UART_NR;
card->drv.cons = MUX_CONSOLE;
ret = uart_register_driver(&card->drv);
if(ret) {
printk(KERN_ERR "Serial mux: Unable to register driver.\n"); printk(KERN_ERR "Serial mux: Unable to register driver.\n");
return 1; return 1;
} }
for(j = 0; j < UART_NR; ++j) { init_timer(&mux_timer);
port = &card->ports[j]; mux_timer.function = mux_poll;
}
for(i = 0; i < ports; ++i, ++port_cnt) {
port = &mux_ports[port_cnt];
port->iobase = 0; port->iobase = 0;
port->mapbase = dev->hpa + MUX_OFFSET + (j * MUX_LINE_OFFSET); port->mapbase = dev->hpa + MUX_OFFSET + (i * MUX_LINE_OFFSET);
port->membase = ioremap(port->mapbase, MUX_LINE_OFFSET); port->membase = ioremap(port->mapbase, MUX_LINE_OFFSET);
port->iotype = SERIAL_IO_MEM; port->iotype = SERIAL_IO_MEM;
port->type = PORT_MUX; port->type = PORT_MUX;
...@@ -481,12 +479,14 @@ static int __init mux_probe(struct parisc_device *dev) ...@@ -481,12 +479,14 @@ static int __init mux_probe(struct parisc_device *dev)
port->fifosize = MUX_FIFO_SIZE; port->fifosize = MUX_FIFO_SIZE;
port->ops = &mux_pops; port->ops = &mux_pops;
port->flags = UPF_BOOT_AUTOCONF; port->flags = UPF_BOOT_AUTOCONF;
port->line = j; port->line = port_cnt;
ret = uart_add_one_port(&card->drv, port); status = uart_add_one_port(&mux_driver, port);
BUG_ON(ret); BUG_ON(status);
}
port_cnt += UART_NR;
} }
#ifdef CONFIG_SERIAL_MUX_CONSOLE
register_console(&mux_console);
#endif
return 0; return 0;
} }
...@@ -497,7 +497,7 @@ static struct parisc_device_id mux_tbl[] = { ...@@ -497,7 +497,7 @@ static struct parisc_device_id mux_tbl[] = {
MODULE_DEVICE_TABLE(parisc, mux_tbl); MODULE_DEVICE_TABLE(parisc, mux_tbl);
static struct parisc_driver mux_driver = { static struct parisc_driver serial_mux_driver = {
.name = "Serial MUX", .name = "Serial MUX",
.id_table = mux_tbl, .id_table = mux_tbl,
.probe = mux_probe, .probe = mux_probe,
...@@ -510,7 +510,7 @@ static struct parisc_driver mux_driver = { ...@@ -510,7 +510,7 @@ static struct parisc_driver mux_driver = {
*/ */
static int __init mux_init(void) static int __init mux_init(void)
{ {
return register_parisc_driver(&mux_driver); return register_parisc_driver(&serial_mux_driver);
} }
/** /**
...@@ -521,13 +521,12 @@ static int __init mux_init(void) ...@@ -521,13 +521,12 @@ static int __init mux_init(void)
static void __exit mux_exit(void) static void __exit mux_exit(void)
{ {
int i; int i;
struct mux_card *card = &mux_card_head;
for (i = 0; i < UART_NR; i++) { for (i = 0; i < port_cnt; i++) {
uart_remove_one_port(&card->drv, &card->ports[i]); uart_remove_one_port(&mux_driver, &mux_ports[i]);
} }
uart_unregister_driver(&card->drv); uart_unregister_driver(&mux_driver);
} }
module_init(mux_init); module_init(mux_init);
......
...@@ -588,7 +588,7 @@ sti_select_font(struct sti_cooked_rom *rom, ...@@ -588,7 +588,7 @@ sti_select_font(struct sti_cooked_rom *rom,
static void __init static void __init
sti_dump_rom(struct sti_rom *rom) sti_dump_rom(struct sti_rom *rom)
{ {
printk(KERN_INFO "STI id %04x-%04x, conforms to spec rev. %d.%02x\n", printk(KERN_INFO " id %04x-%04x, conforms to spec rev. %d.%02x\n",
rom->graphics_id[0], rom->graphics_id[0],
rom->graphics_id[1], rom->graphics_id[1],
rom->revno[0] >> 4, rom->revno[0] >> 4,
...@@ -869,14 +869,14 @@ sti_try_rom_generic(unsigned long address, unsigned long hpa, struct pci_dev *pd ...@@ -869,14 +869,14 @@ sti_try_rom_generic(unsigned long address, unsigned long hpa, struct pci_dev *pd
ok = 0; ok = 0;
if ((sig & 0xff) == 0x01) { if ((sig & 0xff) == 0x01) {
printk(KERN_INFO "STI byte mode ROM at %08lx, hpa at %08lx\n", DPRINTK((" byte mode ROM at %08lx, hpa at %08lx\n",
address, hpa); address, hpa));
ok = sti_read_rom(0, sti, address); ok = sti_read_rom(0, sti, address);
} }
if ((sig & 0xffff) == 0x0303) { if ((sig & 0xffff) == 0x0303) {
printk(KERN_INFO "STI word mode ROM at %08lx, hpa at %08lx\n", DPRINTK((" word mode ROM at %08lx, hpa at %08lx\n",
address, hpa); address, hpa));
ok = sti_read_rom(1, sti, address); ok = sti_read_rom(1, sti, address);
} }
...@@ -903,7 +903,7 @@ sti_try_rom_generic(unsigned long address, unsigned long hpa, struct pci_dev *pd ...@@ -903,7 +903,7 @@ sti_try_rom_generic(unsigned long address, unsigned long hpa, struct pci_dev *pd
sti_dump_globcfg(sti->glob_cfg, sti->sti_mem_request); sti_dump_globcfg(sti->glob_cfg, sti->sti_mem_request);
sti_dump_outptr(sti); sti_dump_outptr(sti);
printk(KERN_INFO "STI device: %s\n", sti->outptr.dev_name ); printk(KERN_INFO " graphics card name: %s\n", sti->outptr.dev_name );
sti_roms[num_sti_roms] = sti; sti_roms[num_sti_roms] = sti;
num_sti_roms++; num_sti_roms++;
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* Low level Frame buffer driver for HP workstations with * Low level Frame buffer driver for HP workstations with
* STI (standard text interface) video firmware. * STI (standard text interface) video firmware.
* *
* Copyright (C) 2001-2002 Helge Deller <deller@gmx.de> * Copyright (C) 2001-2004 Helge Deller <deller@gmx.de>
* Portions Copyright (C) 2001 Thomas Bogendoerfer <tsbogend@alpha.franken.de> * Portions Copyright (C) 2001 Thomas Bogendoerfer <tsbogend@alpha.franken.de>
* *
* Based on: * Based on:
...@@ -39,10 +39,10 @@ ...@@ -39,10 +39,10 @@
*/ */
/* TODO: /* TODO:
* - remove the static fb_info to support multiple cards
* - 1bpp mode is completely untested * - 1bpp mode is completely untested
* - add support for h/w acceleration * - add support for h/w acceleration
* - add hardware cursor * - add hardware cursor
* - automatically disable double buffering (e.g. on RDI precisionbook laptop)
*/ */
...@@ -51,6 +51,8 @@ ...@@ -51,6 +51,8 @@
* #undef FALLBACK_TO_1BPP to reject support for unsupported cards */ * #undef FALLBACK_TO_1BPP to reject support for unsupported cards */
#undef FALLBACK_TO_1BPP #undef FALLBACK_TO_1BPP
#undef DEBUG_STIFB_REGS /* debug sti register accesses */
#include <linux/config.h> #include <linux/config.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -154,8 +156,27 @@ static int __initdata stifb_force_bpp[MAX_STI_ROMS]; ...@@ -154,8 +156,27 @@ static int __initdata stifb_force_bpp[MAX_STI_ROMS];
#define READ_BYTE(fb,reg) __raw_readb((fb)->info.fix.mmio_start + (reg)) #define READ_BYTE(fb,reg) __raw_readb((fb)->info.fix.mmio_start + (reg))
#define READ_WORD(fb,reg) __raw_readl((fb)->info.fix.mmio_start + (reg)) #define READ_WORD(fb,reg) __raw_readl((fb)->info.fix.mmio_start + (reg))
#define WRITE_BYTE(value,fb,reg) __raw_writeb((value),(fb)->info.fix.mmio_start + (reg))
#define WRITE_WORD(value,fb,reg) __raw_writel((value),(fb)->info.fix.mmio_start + (reg))
#ifndef DEBUG_STIFB_REGS
# define DEBUG_OFF()
# define DEBUG_ON()
# define WRITE_BYTE(value,fb,reg) __raw_writeb((value),(fb)->info.fix.mmio_start + (reg))
# define WRITE_WORD(value,fb,reg) __raw_writel((value),(fb)->info.fix.mmio_start + (reg))
#else
static int debug_on = 1;
# define DEBUG_OFF() debug_on=0
# define DEBUG_ON() debug_on=1
# define WRITE_BYTE(value,fb,reg) do { if (debug_on) \
printk(KERN_DEBUG "%30s: WRITE_BYTE(0x%06x) = 0x%02x (old=0x%02x)\n", \
__FUNCTION__, reg, value, READ_BYTE(fb,reg)); \
__raw_writeb((value),(fb)->info.fix.mmio_start + (reg)); } while (0)
# define WRITE_WORD(value,fb,reg) do { if (debug_on) \
printk(KERN_DEBUG "%30s: WRITE_WORD(0x%06x) = 0x%08x (old=0x%08x)\n", \
__FUNCTION__, reg, value, READ_WORD(fb,reg)); \
__raw_writel((value),(fb)->info.fix.mmio_start + (reg)); } while (0)
#endif /* DEBUG_STIFB_REGS */
#define ENABLE 1 /* for enabling/disabling screen */ #define ENABLE 1 /* for enabling/disabling screen */
#define DISABLE 0 #define DISABLE 0
...@@ -449,6 +470,13 @@ SETUP_ATTR_ACCESS(struct stifb_info *fb, unsigned BufferNumber) ...@@ -449,6 +470,13 @@ SETUP_ATTR_ACCESS(struct stifb_info *fb, unsigned BufferNumber)
static void static void
SET_ATTR_SIZE(struct stifb_info *fb, int width, int height) SET_ATTR_SIZE(struct stifb_info *fb, int width, int height)
{ {
/* REG_6 seems to have special values when run on a
RDI precisionbook parisc laptop (INTERNAL_EG_DX1024 or
INTERNAL_EG_X1024). The values are:
0x2f0: internal (LCD) & external display enabled
0x2a0: external display only
0x000: zero on standard artist graphic cards
*/
WRITE_WORD(0x00000000, fb, REG_6); WRITE_WORD(0x00000000, fb, REG_6);
WRITE_WORD((width<<16) | height, fb, REG_9); WRITE_WORD((width<<16) | height, fb, REG_9);
WRITE_WORD(0x05000000, fb, REG_6); WRITE_WORD(0x05000000, fb, REG_6);
...@@ -730,7 +758,7 @@ hyperResetPlanes(struct stifb_info *fb, int enable) ...@@ -730,7 +758,7 @@ hyperResetPlanes(struct stifb_info *fb, int enable)
controlPlaneReg = 0x00000F00; /* 0x00000100 should be enought, but lets clear all 4 bits */ controlPlaneReg = 0x00000F00; /* 0x00000100 should be enought, but lets clear all 4 bits */
switch (enable) { switch (enable) {
case 1: /* ENABLE */ case ENABLE:
/* clear screen */ /* clear screen */
if (IS_24_DEVICE(fb)) if (IS_24_DEVICE(fb))
ngleDepth24_ClearImagePlanes(fb); ngleDepth24_ClearImagePlanes(fb);
...@@ -750,7 +778,7 @@ hyperResetPlanes(struct stifb_info *fb, int enable) ...@@ -750,7 +778,7 @@ hyperResetPlanes(struct stifb_info *fb, int enable)
hyperUndoITE(fb); hyperUndoITE(fb);
break; break;
case 0: /* DISABLE */ case DISABLE:
/* clear screen */ /* clear screen */
if (IS_24_DEVICE(fb)) if (IS_24_DEVICE(fb))
ngleDepth24_ClearImagePlanes(fb); ngleDepth24_ClearImagePlanes(fb);
...@@ -974,6 +1002,8 @@ stifb_setcolreg(u_int regno, u_int red, u_int green, ...@@ -974,6 +1002,8 @@ stifb_setcolreg(u_int regno, u_int red, u_int green,
green >>= 8; green >>= 8;
blue >>= 8; blue >>= 8;
DEBUG_OFF();
START_IMAGE_COLORMAP_ACCESS(fb); START_IMAGE_COLORMAP_ACCESS(fb);
if (fb->info.var.grayscale) { if (fb->info.var.grayscale) {
...@@ -1005,6 +1035,8 @@ stifb_setcolreg(u_int regno, u_int red, u_int green, ...@@ -1005,6 +1035,8 @@ stifb_setcolreg(u_int regno, u_int red, u_int green,
FINISH_IMAGE_COLORMAP_ACCESS(fb); FINISH_IMAGE_COLORMAP_ACCESS(fb);
} }
DEBUG_ON();
return 0; return 0;
} }
...@@ -1144,17 +1176,28 @@ stifb_init_fb(struct sti_struct *sti, int force_bpp) ...@@ -1144,17 +1176,28 @@ stifb_init_fb(struct sti_struct *sti, int force_bpp)
/* only supported cards are allowed */ /* only supported cards are allowed */
switch (fb->id) { switch (fb->id) {
case CRT_ID_VISUALIZE_EG:
/* look for a double buffering device like e.g. the
"INTERNAL_EG_DX1024" in the RDI precisionbook laptop
which won't work. The same device in non-double
buffering mode returns "INTERNAL_EG_X1024". */
if (strstr(sti->outptr.dev_name, "EG_DX")) {
printk(KERN_WARNING
"stifb: ignoring '%s'. Disable double buffering in IPL menu.\n",
sti->outptr.dev_name);
goto out_err0;
}
/* fall though */
case S9000_ID_ARTIST: case S9000_ID_ARTIST:
case S9000_ID_HCRX: case S9000_ID_HCRX:
case S9000_ID_TIMBER: case S9000_ID_TIMBER:
case S9000_ID_A1659A: case S9000_ID_A1659A:
case S9000_ID_A1439A: case S9000_ID_A1439A:
case CRT_ID_VISUALIZE_EG:
break; break;
default: default:
printk(KERN_WARNING "stifb: Unsupported gfx card id 0x%08x\n", printk(KERN_WARNING "stifb: '%s' (id: 0x%08x) not supported.\n",
fb->id); sti->outptr.dev_name, fb->id);
goto out_err1; goto out_err0;
} }
/* default to 8 bpp on most graphic chips */ /* default to 8 bpp on most graphic chips */
...@@ -1232,7 +1275,7 @@ stifb_init_fb(struct sti_struct *sti, int force_bpp) ...@@ -1232,7 +1275,7 @@ stifb_init_fb(struct sti_struct *sti, int force_bpp)
"stifb: Unsupported graphics card (id=0x%08x) " "stifb: Unsupported graphics card (id=0x%08x) "
"- skipping.\n", "- skipping.\n",
fb->id); fb->id);
goto out_err1; goto out_err0;
#endif #endif
} }
...@@ -1306,12 +1349,13 @@ stifb_init_fb(struct sti_struct *sti, int force_bpp) ...@@ -1306,12 +1349,13 @@ stifb_init_fb(struct sti_struct *sti, int force_bpp)
sti->info = info; /* save for unregister_framebuffer() */ sti->info = info; /* save for unregister_framebuffer() */
printk(KERN_INFO printk(KERN_INFO
"fb%d: %s %dx%d-%d frame buffer device, id: %04x, mmio: 0x%04lx\n", "fb%d: %s %dx%d-%d frame buffer device, %s, id: %04x, mmio: 0x%04lx\n",
fb->info.node, fb->info.node,
fix->id, fix->id,
var->xres, var->xres,
var->yres, var->yres,
var->bits_per_pixel, var->bits_per_pixel,
sti->outptr.dev_name,
fb->id, fb->id,
fix->mmio_start); fix->mmio_start);
...@@ -1324,16 +1368,24 @@ stifb_init_fb(struct sti_struct *sti, int force_bpp) ...@@ -1324,16 +1368,24 @@ stifb_init_fb(struct sti_struct *sti, int force_bpp)
release_mem_region(fix->smem_start, fix->smem_len); release_mem_region(fix->smem_start, fix->smem_len);
out_err1: out_err1:
fb_dealloc_cmap(&info->cmap); fb_dealloc_cmap(&info->cmap);
out_err0:
kfree(fb); kfree(fb);
return -ENXIO; return -ENXIO;
} }
static int stifb_disabled __initdata;
int __init int __init
stifb_init(void) stifb_init(void)
{ {
struct sti_struct *sti; struct sti_struct *sti;
int i; int i;
if (stifb_disabled) {
printk(KERN_INFO "stifb: disabled by \"stifb=off\" kernel parameter\n");
return -ENXIO;
}
for (i = 1; i < MAX_STI_ROMS; i++) { for (i = 1; i < MAX_STI_ROMS; i++) {
sti = sti_get_rom(i); sti = sti_get_rom(i);
if (!sti) if (!sti)
...@@ -1379,6 +1431,11 @@ stifb_setup(char *options) ...@@ -1379,6 +1431,11 @@ stifb_setup(char *options)
if (!options || !*options) if (!options || !*options)
return 0; return 0;
if (strncmp(options, "off", 3) == 0) {
stifb_disabled = 1;
options += 3;
}
if (strncmp(options, "bpp", 3) == 0) { if (strncmp(options, "bpp", 3) == 0) {
options += 3; options += 3;
for (i = 0; i < MAX_STI_ROMS; i++) { for (i = 0; i < MAX_STI_ROMS; i++) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment