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
#config PCI_EPIC
# bool "EPIC/SAGA PCI support"
# depends on PCI
# default y
# help
# Say Y here for V-class PCI, DMA/IOMMU, IRQ subsystem support.
config SUPERIO
bool "SuperIO (SuckyIO) support"
......
......@@ -364,11 +364,11 @@ ccio_alloc_range(struct ioc *ioc, unsigned long pages_needed)
CCIO_FIND_FREE_MAPPING(ioc, res_idx, mask, 64);
#endif
} else {
panic(__FILE__ ": %s() Too many pages to map. pages_needed: %ld\n",
__FUNCTION__, pages_needed);
panic("%s: %s() Too many pages to map. pages_needed: %ld\n",
__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__);
resource_found:
......@@ -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);
#endif
} else {
panic(__FILE__ ":%s() Too many pages to unmap.\n",
panic("%s:%s() Too many pages to unmap.\n", __FILE__,
__FUNCTION__);
}
}
......@@ -1447,7 +1447,8 @@ ccio_ioc_init(struct ioc *ioc)
ioc->pdir_base = (u64 *)__get_free_pages(GFP_KERNEL,
get_order(ioc->pdir_size));
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);
......@@ -1461,7 +1462,8 @@ ccio_ioc_init(struct ioc *ioc)
ioc->res_map = (u8 *)__get_free_pages(GFP_KERNEL,
get_order(ioc->res_size));
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);
......@@ -1627,11 +1629,11 @@ int ccio_request_resource(const struct parisc_device *dev,
if (!ioc) {
parent = &iomem_resource;
} else if ((ioc->mmio_region->start <= dev->hpa) &&
(dev->hpa < ioc->mmio_region->end)) {
} else if ((ioc->mmio_region->start <= res->start) &&
(res->end <= ioc->mmio_region->end)) {
parent = ioc->mmio_region;
} else if (((ioc->mmio_region + 1)->start <= dev->hpa) &&
(dev->hpa < (ioc->mmio_region + 1)->end)) {
} else if (((ioc->mmio_region + 1)->start <= res->start) &&
(res->end <= (ioc->mmio_region + 1)->end)) {
parent = ioc->mmio_region + 1;
} else {
return -EBUSY;
......
......@@ -175,7 +175,7 @@ static int dino_current_bus = 0;
static int dino_cfg_read(struct pci_bus *bus, unsigned int devfn, int where,
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 v = DINO_CFG_TOK(local_bus, devfn, where & ~3);
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,
static int dino_cfg_write(struct pci_bus *bus, unsigned int devfn, int where,
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 v = DINO_CFG_TOK(local_bus, devfn, where & ~3);
unsigned long base_addr = d->hba.base_addr;
......@@ -468,14 +468,14 @@ static void __init
dino_card_setup(struct pci_bus *bus, unsigned long base_addr)
{
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;
char name[128];
int size;
res = &dino_dev->hba.lmmio_space;
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);
if(res->name)
strcpy((char *)res->name, name);
......@@ -489,7 +489,7 @@ dino_card_setup(struct pci_bus *bus, unsigned long base_addr)
struct list_head *ln, *tmp_ln;
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 */
list_for_each_safe(ln, tmp_ln, &bus->devices) {
struct pci_dev *dev = pci_dev_b(ln);
......@@ -560,11 +560,11 @@ dino_fixup_bus(struct pci_bus *bus)
{
struct list_head *ln;
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);
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 */
if (is_card_dino(&dino_dev->hba.dev->id)) {
......@@ -572,15 +572,23 @@ dino_fixup_bus(struct pci_bus *bus)
} else if(bus->parent == NULL) {
/* must have a dino above it, reparent the resources
* into the dino window */
int i;
struct resource *res = &dino_dev->hba.lmmio_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) {
int i;
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)
continue;
......@@ -642,11 +650,10 @@ dino_fixup_bus(struct pci_bus *bus)
* care about an expansion rom on parisc, since it
* usually contains (x86) bios code) */
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) {
#define DINO_FIX_UNASSIGNED_INTERRUPTS
#ifdef DINO_FIX_UNASSIGNED_INTERRUPTS
/* This code tries to assign an unassigned
......@@ -660,7 +667,7 @@ dino_fixup_bus(struct pci_bus *bus)
dino_cfg_read(dev->bus, dev->devfn, PCI_INTERRUPT_PIN, 1, &irq_pin);
dev->irq = (irq_pin + PCI_SLOT(dev->devfn) - 1) % 4 ;
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);
#else
dev->irq = 65535;
......@@ -741,9 +748,9 @@ dino_card_init(struct dino_device *dino_dev)
static int __init
dino_bridge_init(struct dino_device *dino_dev, const char *name)
{
unsigned long io_addr, bpos;
int result;
struct resource *res;
unsigned long io_addr;
int result, i, count=0;
struct resource *res, *prevres = NULL;
/*
* Decoding IO_ADDR_EN only works for Built-in Dino
* since PDC has already initialized this.
......@@ -755,21 +762,51 @@ dino_bridge_init(struct dino_device *dino_dev, const char *name)
return -ENODEV;
}
for (bpos = 0; (io_addr & (1 << bpos)) == 0; bpos++)
;
res = &dino_dev->hba.lmmio_space;
res->flags = IORESOURCE_MEM;
for (i = 0; i < 32; i++) {
unsigned long start, end;
if((io_addr & (1 << i)) == 0)
continue;
res->start = (unsigned long)(signed int)(0xf0000000 | (bpos << 23));
res->end = res->start + 8 * 1024 * 1024 - 1;
start = (unsigned long)(signed int)(0xf0000000 | (i << 23));
end = start + 8 * 1024 * 1024 - 1;
result = ccio_request_resource(dino_dev->hba.dev, res);
if (result < 0) {
printk(KERN_ERR "%s: failed to claim PCI Bus address space!\n", name);
return result;
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->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;
for(i = 0; i < DINO_MAX_LMMIO_RESOURCES; i++) {
if(res[i].flags == 0)
break;
result = ccio_request_resource(dino_dev->hba.dev, &res[i]);
if (result < 0) {
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 0;
}
......@@ -850,10 +887,8 @@ static int __init dino_common_init(struct parisc_device *dev,
res = &dino_dev->hba.io_space;
if (dev->id.hversion == 0x680 || is_card_dino(&dev->id)) {
res->name = "Dino I/O Port";
dino_dev->hba.lmmio_space.name = "Dino LMMIO";
} else {
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->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/module.h>
#include <linux/init.h>
......
......@@ -610,19 +610,19 @@ iosapic_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
struct vector_info *vi = (struct vector_info *)dev_id;
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",
irq, vi->vi_irqline, vi->vi_eoi_addr);
irq, vi->irqline, vi->eoi_addr);
/* 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.
** 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;
}
......@@ -636,10 +636,6 @@ iosapic_fixup_irq(void *isi_obj, struct pci_dev *pcidev)
struct vector_info *vi;
int isi_line; /* line used by device */
int tmp;
int return_irq;
#ifdef CONFIG_SUPERIO
int superio_irq = -1;
#endif
if (NULL == isi) {
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)
}
#ifdef CONFIG_SUPERIO
/*
* HACK ALERT! (non-compliant PCI device support)
*
* All SuckyIO interrupts are routed through the PIC's on function 1.
* But SuckyIO OHCI USB controller gets an IRT entry anyway because
* 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)) {
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.
* Only let the USB controller hookup the rest
* of the interrupt routing when it comes through.
* Note that interrupts for all three functions
* actually come through the PIC's on function 1!
*/
pcidev->irq = superio_irq;
return superio_irq;
}
/* We must call superio_fixup_irq() to register the pdev */
pcidev->irq = superio_fixup_irq(pcidev);
/* Don't return if need to program the IOSAPIC's IRT... */
if (PCI_FUNC(pcidev->devfn) != SUPERIO_USB_FN)
return pcidev->irq;
}
#endif /* CONFIG_SUPERIO */
/* lookup IRT entry for isi/slot/pin set */
irte = iosapic_xlate_pin(isi, pcidev);
if (NULL == irte) {
printk("iosapic: no IRTE for %s (IRQ not connected?)\n",
pci_name(pcidev));
return(-1);
}
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)
irte->dest_iosapic_intin,
(u32) irte->dest_iosapic_addr);
isi_line = irte->dest_iosapic_intin;
pcidev->irq = isi->isi_region->data.irqbase + isi_line;
/* get vector info for this input line */
ASSERT(NULL != isi->isi_vector);
vi = &(isi->isi_vector[isi_line]);
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 */
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
** 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)
** Right now we assign an IRQ to every PCI device present regardless
** 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");
/* enable_irq() will use txn_* to program IRdT */
vi->vi_txn_addr = txn_alloc_addr(vi->vi_txn_irq);
vi->vi_txn_data = txn_alloc_data(vi->vi_txn_irq, 8);
ASSERT(vi->vi_txn_data < 256); /* matches 8 above */
vi->txn_addr = txn_alloc_addr(vi->txn_irq);
vi->txn_data = txn_alloc_data(vi->txn_irq, 8);
ASSERT(vi->txn_data < 256); /* matches 8 above */
tmp = request_irq(vi->vi_txn_irq, iosapic_interrupt, 0,
vi->vi_name, vi);
tmp = request_irq(vi->txn_irq, iosapic_interrupt, 0,
vi->name, vi);
ASSERT(tmp == 0);
vi->vi_eoi_addr = (u32 *) (isi->isi_hpa + IOSAPIC_REG_EOI);
vi->vi_eoi_data = cpu_to_le32(vi->vi_irqline);
vi->eoi_addr = (u32 *) (isi->isi_hpa + IOSAPIC_REG_EOI);
vi->eoi_data = cpu_to_le32(vi->irqline);
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",
PCI_SLOT(pcidev->devfn),
PCI_FUNC(pcidev->devfn), pcidev->vendor, pcidev->device, isi_line, return_irq);
PCI_SLOT(pcidev->devfn), PCI_FUNC(pcidev->irq),
pcidev->vendor, pcidev->device, isi_line, pcidev->irq);
return return_irq;
return pcidev->irq;
}
static void
iosapic_rd_irt_entry(struct vector_info *vi , u32 *dp0, u32 *dp1)
{
struct iosapic_info *isp = vi->vi_ios;
u8 idx = vi->vi_irqline;
struct iosapic_info *isp = vi->iosapic;
u8 idx = vi->irqline;
/* point the window register to the lower word */
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)
static void
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(0 != isp->isi_hpa);
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,
dp0, dp1);
/* 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);
/* Read the window register to flush the writes down to HW */
dp0 = READ_U32(isp->isi_hpa+IOSAPIC_REG_WINDOW);
/* 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);
/* Read the window register to flush the writes down to HW */
......@@ -790,8 +780,8 @@ static void
iosapic_set_irt_data( struct vector_info *vi, u32 *dp0, u32 *dp1)
{
u32 mode = 0;
struct irt_entry *p = vi->vi_irte;
ASSERT(NULL != vi->vi_irte);
struct irt_entry *p = vi->irte;
ASSERT(NULL != vi->irte);
if ((p->polarity_trigger & IRT_PO_MASK) == IRT_ACTIVE_LO)
mode |= IOSAPIC_IRDT_PO_LOW;
......@@ -804,8 +794,8 @@ iosapic_set_irt_data( struct vector_info *vi, u32 *dp0, u32 *dp1)
** PA doesn't support EXTINT or LPRIO bits.
*/
ASSERT(vi->vi_txn_data);
*dp0 = mode | (u32) vi->vi_txn_data;
ASSERT(vi->txn_data);
*dp0 = mode | (u32) vi->txn_data;
/*
** 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)
if (is_pdc_pat()) {
/*
** 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 {
/*
** eg if base_addr == 0xfffa0000),
......@@ -825,8 +815,8 @@ iosapic_set_irt_data( struct vector_info *vi, u32 *dp0, u32 *dp1)
** eid 0x0ff00000 -> 0x00ff0000
** id 0x000ff000 -> 0xff000000
*/
*dp1 = (((u32)vi->vi_txn_addr & 0x0ff00000) >> 4) |
(((u32)vi->vi_txn_addr & 0x000ff000) << 12);
*dp1 = (((u32)vi->txn_addr & 0x0ff00000) >> 4) |
(((u32)vi->txn_addr & 0x000ff000) << 12);
}
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.
IOSAPIC_UNLOCK(&iosapic_lock);
/* 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)
u32 d0, d1;
ASSERT(NULL != vi);
ASSERT(NULL != vi->vi_irte);
ASSERT(NULL != vi->irte);
/* data is initialized by fixup_irq */
ASSERT(0 < vi->vi_txn_irq);
ASSERT(0UL != vi->vi_txn_data);
ASSERT(0 < vi->txn_irq);
ASSERT(0UL != vi->txn_data);
iosapic_set_irt_data(vi, &d0, &d1);
iosapic_wr_irt_entry(vi, d0, d1);
......@@ -895,15 +885,15 @@ iosapic_enable_irq(void *dev, int irq)
#ifdef DEBUG_IOSAPIC_IRT
{
u32 *t = (u32 *) ((ulong) vi->vi_eoi_addr & ~0xffUL);
printk("iosapic_enable_irq(): regs %p", vi->vi_eoi_addr);
while (t < vi->vi_eoi_addr) printk(" %x", READ_U32(t++));
u32 *t = (u32 *) ((ulong) vi->eoi_addr & ~0xffUL);
printk("iosapic_enable_irq(): regs %p", vi->eoi_addr);
while (t < vi->eoi_addr) printk(" %x", READ_U32(t++));
printk("\n");
}
printk("iosapic_enable_irq(): sel ");
{
struct iosapic_info *isp = vi->vi_ios;
struct iosapic_info *isp = vi->iosapic;
for (d0=0x10; d0<0x1e; d0++) {
/* point the window register to the lower word */
......@@ -924,7 +914,7 @@ printk("\n");
** Issueing I/O SAPIC an EOI causes an interrupt iff IRQ line is
** 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)
** Initialize vector array
*/
for (cnt=0; cnt < isi->isi_num_vectors; cnt++, vip++) {
vip->vi_irqline = (unsigned char) cnt;
vip->vi_ios = isi;
sprintf(vip->vi_name, "%s-L%d", isi->isi_name, cnt);
vip->irqline = (unsigned char) cnt;
vip->iosapic = isi;
sprintf(vip->name, "%s-L%d", isi->isi_name, cnt);
}
isi->isi_region = alloc_irq_region(isi->isi_num_vectors,
......@@ -1071,13 +1061,13 @@ iosapic_prt_vi(struct vector_info *vi)
{
ASSERT(NULL != vi);
printk(KERN_DEBUG MODULE_NAME ": vector_info[%d] is at %p\n", vi->vi_irqline, vi);
printk(KERN_DEBUG "\t\tvi_status: %.4x\n", vi->vi_status);
printk(KERN_DEBUG "\t\tvi_txn_irq: %d\n", vi->vi_txn_irq);
printk(KERN_DEBUG "\t\tvi_txn_addr: %lx\n", vi->vi_txn_addr);
printk(KERN_DEBUG "\t\tvi_txn_data: %lx\n", vi->vi_txn_data);
printk(KERN_DEBUG "\t\tvi_eoi_addr: %p\n", vi->vi_eoi_addr);
printk(KERN_DEBUG "\t\tvi_eoi_data: %x\n", vi->vi_eoi_data);
printk(KERN_DEBUG MODULE_NAME ": vector_info[%d] is at %p\n", vi->irqline, vi);
printk(KERN_DEBUG "\t\tstatus: %.4x\n", vi->status);
printk(KERN_DEBUG "\t\ttxn_irq: %d\n", vi->txn_irq);
printk(KERN_DEBUG "\t\ttxn_addr: %lx\n", vi->txn_addr);
printk(KERN_DEBUG "\t\ttxn_data: %lx\n", vi->txn_data);
printk(KERN_DEBUG "\t\teoi_addr: %p\n", vi->eoi_addr);
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.
** If stuff needs to be used by another driver, move it to a common file.
......@@ -107,16 +130,16 @@ struct iosapic_irt {
#endif
struct vector_info {
struct iosapic_info *vi_ios; /* I/O SAPIC this vector is on */
struct irt_entry *vi_irte; /* IRT entry */
u32 *vi_eoi_addr; /* precalculate EOI reg address */
u32 vi_eoi_data; /* IA64: ? PA: swapped txn_data */
int vi_txn_irq; /* virtual IRQ number for processor */
ulong vi_txn_addr; /* IA64: id_eid PA: partial HPA */
ulong vi_txn_data; /* IA64: vector PA: EIR bit */
u8 vi_status; /* status/flags */
u8 vi_irqline; /* INTINn(IRQ) */
char vi_name[32]; /* user visible identity */
struct iosapic_info *iosapic; /* I/O SAPIC this vector is on */
struct irt_entry *irte; /* IRT entry */
u32 *eoi_addr; /* precalculate EOI reg address */
u32 eoi_data; /* IA64: ? PA: swapped txn_data */
int txn_irq; /* virtual IRQ number for processor */
ulong txn_addr; /* IA64: id_eid PA: partial HPA */
ulong txn_data; /* IA64: vector PA: EIR bit */
u8 status; /* status/flags */
u8 irqline; /* INTINn(IRQ) */
char name[32]; /* user visible identity */
};
......
......@@ -185,8 +185,6 @@ struct lba_device {
void *iosapic_obj;
#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 */
#endif
......@@ -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)
{
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 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
with risk we will miss PCI bus errors. */
*data = lba_rd_cfg(d, tok, pos, size);
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)))
......@@ -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)
{
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 tok = LBA_CFG_TOK(local_bus,devfn);
......@@ -695,20 +693,23 @@ lba_fixup_bus(struct pci_bus *bus)
{
struct list_head *ln;
#ifdef FBB_SUPPORT
u16 fbb_enable = PCI_STATUS_FAST_BACK;
u16 status;
#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);
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.
** 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;
DBG("lba_fixup_bus() %s [%lx/%lx]/%x\n",
......@@ -725,59 +726,29 @@ lba_fixup_bus(struct pci_bus *bus)
BUG();
lba_dump_res(&ioport_resource, 2);
}
err = request_resource(&iomem_resource, &(ldev->hba.lmmio_space));
if (err < 0) {
BUG();
lba_dump_res(&iomem_resource, 2);
}
bus->resource[0] = &(ldev->hba.io_space);
bus->resource[1] = &(ldev->hba.lmmio_space);
} else {
/* KLUGE ALERT!
** PCI-PCI Bridge resource munging.
** This hack should go away in the near future.
** 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;
#ifdef __LP64__
if (ldev->hba.gmmio_space.flags) {
err = request_resource(&iomem_resource, &(ldev->hba.gmmio_space));
if (err < 0) {
BUG();
lba_dump_res(&iomem_resource, 2);
}
bus->resource[2] = &(ldev->hba.gmmio_space);
}
#if 0
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;
}
/* Turn off downstream PF memory address range by default */
bus->resource[2]->start = 1024*1024;
bus->resource[2]->end = bus->resource[2]->start - 1;
/* advertize Host bridge resources to PCI bus */
bus->resource[0] = &(ldev->hba.io_space);
bus->resource[1] = &(ldev->hba.lmmio_space);
}
list_for_each(ln, &bus->devices) {
int i;
struct pci_dev *dev = pci_dev_b(ln);
......@@ -785,7 +756,7 @@ lba_fixup_bus(struct pci_bus *bus)
DBG("lba_fixup_bus() %s\n", pci_name(dev));
/* 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];
/* If resource not allocated - skip it */
......@@ -817,7 +788,7 @@ lba_fixup_bus(struct pci_bus *bus)
** No one on the bus can be allowed to use them.
*/
(void) pci_read_config_word(dev, PCI_STATUS, &status);
fbb_enable &= status;
bus->bridge_ctl &= ~(status & PCI_STATUS_FAST_BACK);
#endif
#ifdef __LP64__
......@@ -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.end = p->end;
break;
case PAT_LMMIO:
/* used to fix up pre-initialized MEM BARs */
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)
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;
/* MMIO space > 4GB phys addr; for 64-bit BAR */
r = &(lba_dev->hba.gmmio_space);
r->name = "LBA GMMIO";
r->start = p->start;
r->end = p->end;
r->flags = IORESOURCE_MEM;
r->parent = r->sibling = r->child = NULL;
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.
** base of 64MB PIOP region
*/
/* save base of 64MB PIOP region */
lba_dev->iop_base = p->start;
r = &(lba_dev->hba.io_space);
......@@ -1106,6 +1083,7 @@ lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
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",
......@@ -1259,7 +1237,11 @@ lba_hw_init(struct lba_device *d)
#endif /* DEBUG_LBA_PAT */
#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
/* PDC_PAT_BUG: exhibited in rev 40.48 on L2000 */
......
......@@ -3,7 +3,7 @@
*
* (c) Copyright 2000 Red Hat Software
* (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>
*
* This program is free software; you can redistribute it and/or modify
......@@ -56,6 +56,7 @@ static int led_heartbeat = 1;
static int led_diskio = 1;
static int led_lanrxtx = 1;
static char lcd_text[32];
static char lcd_text_default[] = "Linux " UTS_RELEASE;
#if 0
#define DPRINTK(x) printk x
......@@ -196,19 +197,11 @@ static int led_proc_write(struct file *file, const char *buf,
break;
case LED_HASLCD:
while (*cur && cur[strlen(cur)-1] == '\n')
cur[strlen(cur)-1] = 0;
if (*cur == 0)
{
/* 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;
lcd_print(cur);
}
cur = lcd_text_default;
lcd_print(cur);
break;
default:
return 0;
......@@ -438,11 +431,7 @@ static __inline__ int led_get_diskio_activity(void)
#define HEARTBEAT_2ND_RANGE_START (HZ*22/100)
#define HEARTBEAT_2ND_RANGE_END (HEARTBEAT_2ND_RANGE_START + HEARTBEAT_LEN)
#if HZ==100
#define NORMALIZED_COUNT(count) (count)
#else
#define NORMALIZED_COUNT(count) (count/(HZ/100))
#endif
#define NORMALIZED_COUNT(count) (count/(HZ/100))
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)
printk(KERN_INFO "LCD display at %p,%p registered\n",
LCD_CMD_REG , LCD_DATA_REG);
led_func_ptr = led_LCD_driver;
lcd_print( "Linux " UTS_RELEASE );
lcd_print( lcd_text_default );
led_type = LED_HASLCD;
break;
......
......@@ -44,6 +44,11 @@
#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.
** Don't even think about messing with it unless you have
......@@ -217,7 +222,7 @@ struct ioc {
} saved[DELAYED_RESOURCE_CNT];
#endif
#ifdef CONFIG_PROC_FS
#ifdef SBA_COLLECT_STATS
#define SBA_SEARCH_SAMPLE 0x100
unsigned long avg_search[SBA_SEARCH_SAMPLE];
unsigned long avg_idx; /* current index into avg_search */
......@@ -560,7 +565,7 @@ static int
sba_alloc_range(struct ioc *ioc, size_t size)
{
unsigned int pages_needed = size >> IOVP_SHIFT;
#ifdef CONFIG_PROC_FS
#ifdef SBA_COLLECT_STATS
unsigned long cr_start = mfctl(16);
#endif
unsigned long pide;
......@@ -579,7 +584,8 @@ sba_alloc_range(struct ioc *ioc, size_t size)
if (pide >= (ioc->res_size << 3)) {
pide = sba_search_bitmap(ioc, pages_needed);
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
......@@ -594,7 +600,7 @@ sba_alloc_range(struct ioc *ioc, size_t size)
(uint) ((unsigned long) ioc->res_hint - (unsigned long) ioc->res_map),
ioc->res_bitshift );
#ifdef CONFIG_PROC_FS
#ifdef SBA_COLLECT_STATS
{
unsigned long cr_end = mfctl(16);
unsigned long tmp = cr_end - cr_start;
......@@ -636,7 +642,7 @@ sba_free_range(struct ioc *ioc, dma_addr_t iova, size_t size)
__FUNCTION__, (uint) iova, size,
bits_not_wanted, m, pide, res_ptr, *res_ptr);
#ifdef CONFIG_PROC_FS
#ifdef SBA_COLLECT_STATS
ioc->used_pages -= bits_not_wanted;
#endif
......@@ -854,7 +860,7 @@ sba_map_single(struct device *dev, void *addr, size_t size,
sba_check_pdir(ioc,"Check before sba_map_single()");
#endif
#ifdef CONFIG_PROC_FS
#ifdef SBA_COLLECT_STATS
ioc->msingle_calls++;
ioc->msingle_pages += size >> IOVP_SHIFT;
#endif
......@@ -929,7 +935,7 @@ sba_unmap_single(struct device *dev, dma_addr_t iova, size_t size,
spin_lock_irqsave(&ioc->res_lock, flags);
#ifdef CONFIG_PROC_FS
#ifdef SBA_COLLECT_STATS
ioc->usingle_calls++;
ioc->usingle_pages += size >> IOVP_SHIFT;
#endif
......@@ -1057,7 +1063,7 @@ sba_fill_pdir(
printk(KERN_DEBUG " %2d : %08lx/%05x %p/%05x\n",
nents,
(unsigned long) sg_dma_address(startsg), cnt,
sg_virt_address(startsg), startsg->length
sg_virt_addr(startsg), startsg->length
);
#else
DBG_RUN_SG(" %d : %08lx/%05x %p/%05x\n",
......@@ -1093,7 +1099,7 @@ sba_fill_pdir(
cnt += dma_offset;
dma_offset=0; /* only want offset on first chunk */
cnt = ROUNDUP(cnt, IOVP_SIZE);
#ifdef CONFIG_PROC_FS
#ifdef SBA_COLLECT_STATS
ioc->msg_pages += cnt >> IOVP_SHIFT;
#endif
do {
......@@ -1300,7 +1306,7 @@ sba_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
}
#endif
#ifdef CONFIG_PROC_FS
#ifdef SBA_COLLECT_STATS
ioc->msg_calls++;
#endif
......@@ -1365,7 +1371,7 @@ sba_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents,
ioc = GET_IOC(dev);
ASSERT(ioc);
#ifdef CONFIG_PROC_FS
#ifdef SBA_COLLECT_STATS
ioc->usg_calls++;
#endif
......@@ -1378,7 +1384,7 @@ sba_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents,
while (sg_dma_len(sglist) && nents--) {
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->usingle_calls--; /* kluge since call is unmap_sg() */
#endif
......@@ -1680,6 +1686,21 @@ sba_hw_init(struct sba_device *sba_dev)
int num_ioc;
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);
DBG_INIT("%s() hpa 0x%lx ioc_ctl 0x%Lx ->",
__FUNCTION__, sba_dev->sba_hpa, ioc_ctl);
......@@ -1766,7 +1787,8 @@ sba_common_init(struct sba_device *sba_dev)
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);
......@@ -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 ioc *ioc = &sba_dev->ioc[0]; /* FIXME: Multi-IOC support! */
int total_pages = (int) (ioc->res_size << 3); /* 8 bits per byte */
#ifdef SBA_COLLECT_STATS
unsigned long i = 0, avg = 0, min, max;
#endif
sprintf(buf, "%s rev %d.%d\n",
sba_dev->name,
......@@ -1841,12 +1865,13 @@ static int sba_proc_info(char *buf, char **start, off_t offset, int len)
(int) ((ioc->res_size << 3) * sizeof(u64)), /* 8 bits/byte */
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,
total_pages - ioc->used_pages, ioc->used_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];
for (i = 0; i < SBA_SEARCH_SAMPLE; i++) {
......@@ -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",
buf, ioc->usg_calls, ioc->usg_pages,
(int) ((ioc->usg_pages * 1000)/ioc->usg_calls));
#endif
return strlen(buf);
}
......
......@@ -9,7 +9,8 @@
* (C) Copyright 2000 Linuxcare Canada, Inc.
* (C) Copyright 2000 Martin K. Petersen <mkp@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
* modify it under the terms of the GNU General Public License as
......@@ -73,24 +74,16 @@
#include <asm/irq.h>
#include <asm/superio.h>
static struct superio_device sio_dev = {
.iosapic_irq = -1
};
static struct superio_device sio_dev;
#undef DEBUG_INIT
void
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;
}
#undef DEBUG_SUPERIO_INIT
sio_dev.iosapic_irq = irq;
}
#ifdef DEBUG_SUPERIO_INIT
#define DBG_INIT(x...) printk(x)
#else
#define DBG_INIT(x...)
#endif
static irqreturn_t
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 */
do_irq(&sio->irq_region->action[local_irq],
sio->irq_region->data.irqbase + local_irq,
regs);
......@@ -153,34 +145,39 @@ superio_init(struct superio_device *sio)
{
struct pci_dev *pdev = sio->lio_pdev;
u16 word;
u8 i;
if (!pdev || sio->iosapic_irq == -1) {
printk(KERN_ERR "All SuperIO functions not found!\n");
BUG();
if (sio->suckyio_irq_enabled)
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",
pci_name(pdev),sio->iosapic_irq);
pci_name(pdev),pdev->irq);
/* 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;
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;
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;
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;
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;
printk (KERN_INFO "SuperIO: ACPI at 0x%x\n", sio->acpi_base);
......@@ -192,24 +189,53 @@ superio_init(struct superio_device *sio)
pci_read_config_word (pdev, PCI_COMMAND, &word);
word |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_IO;
pci_write_config_word (pdev, PCI_COMMAND, word);
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.
/*
* 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.
*/
/* Set PIC interrupts to edge triggered */
pci_write_config_byte (pdev, TRIGGER_1, 0x0);
pci_write_config_byte (pdev, TRIGGER_2, 0x0);
/* Disable all interrupt routing */
for (i = IR_LOW ; i < IR_HIGH ; i++)
pci_write_config_byte (pdev, i, 0x0);
/* 0x64 - 0x67 :
DMA Rtg 2
DMA Rtg 3
DMA Chan Ctl
TRIGGER_1 == 0x82 USB & IDE level triggered, rest to edge
*/
pci_write_config_dword (pdev, 0x64, 0x82000000U);
/* 0x68 - 0x6b :
TRIGGER_2 == 0x00 all edge triggered (not used)
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);
/* 0x6c - 0x6f :
CFG_IR_INTAB == 0x00
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 */
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 (0x01,IC_PIC1+1); /* ICW4: x86 mode */
......@@ -228,19 +254,8 @@ superio_init(struct superio_device *sio)
outb (0x68,IC_PIC1+0); /* OCW3: OCW3 select | ESMM | SMM */
/* Write master mask reg */
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 */
outb(1, sio->acpi_base + USB_REG_CR);
if (inb(sio->acpi_base + USB_REG_CR) & 1)
......@@ -248,20 +263,18 @@ superio_init(struct superio_device *sio)
else
printk(KERN_ERR "USB regulator not initialized!\n");
pci_enable_device(pdev);
if (request_irq(sio->iosapic_irq,superio_interrupt,SA_INTERRUPT,
"SuperIO",(void *)sio)) {
if (request_irq(pdev->irq, superio_interrupt, SA_INTERRUPT,
"SuperIO", (void *)sio)) {
printk(KERN_ERR "SuperIO: could not get irq\n");
BUG();
return;
}
sio->iosapic_irq_enabled = 1;
sio->suckyio_irq_enabled = 1;
}
static void
superio_disable_irq(void *dev, int local_irq)
{
......@@ -283,30 +296,21 @@ superio_disable_irq(void *dev, int local_irq)
static void
superio_enable_irq(void *dev, int local_irq)
{
struct superio_device *sio = (struct superio_device *)dev;
u8 r8;
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();
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 */
r8 = inb(IC_PIC1+1);
r8 &= ~(1 << local_irq);
outb (r8,IC_PIC1+1);
}
static void
superio_mask_irq(void *dev, int local_irq)
{
......@@ -326,7 +330,7 @@ static struct irq_region_ops superio_irq_ops = {
.unmask_irq = superio_unmask_irq
};
#ifdef DEBUG_INIT
#ifdef DEBUG_SUPERIO_INIT
static unsigned short expected_device[3] = {
PCI_DEVICE_ID_NS_87415,
PCI_DEVICE_ID_NS_87560_LIO,
......@@ -338,7 +342,7 @@ int superio_fixup_irq(struct pci_dev *pcidev)
{
int local_irq;
#ifdef DEBUG_INIT
#ifdef DEBUG_SUPERIO_INIT
int fn;
fn = PCI_FUNC(pcidev->devfn);
......@@ -375,9 +379,10 @@ int superio_fixup_irq(struct pci_dev *pcidev)
local_irq = IDE_IRQ;
break;
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;
case PCI_DEVICE_ID_NS_87560_USB: /* Function 2 */
sio_dev.usb_pdev = pcidev; /* save for superio_init() */
local_irq = USB_IRQ;
break;
default:
......@@ -411,20 +416,29 @@ superio_serial_init(void)
{
#ifdef CONFIG_SERIAL_8250
int retval;
extern void serial8250_console_init(void); /* drivers/serial/8250.c */
if (!sio_dev.irq_region)
return; /* superio not present */
if (!sio_dev.iosapic_irq_enabled)
superio_init(&sio_dev);
if (!serial) {
printk(KERN_WARNING "SuperIO: Could not get memory for serial struct.\n");
return;
}
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");
return;
}
serial8250_console_init();
serial[1].iobase = sio_dev.sp2_base;
serial[1].irq = sio_dev.irq_region->data.irqbase + SP2_IRQ;
retval = early_serial_setup(&serial[1]);
if (retval < 0)
......@@ -432,30 +446,20 @@ superio_serial_init(void)
#endif /* CONFIG_SERIAL_8250 */
}
EXPORT_SYMBOL(superio_serial_init);
#ifdef CONFIG_PARPORT_PC
void __devinit
static void __devinit
superio_parport_init(void)
{
if (!sio_dev.irq_region)
return; /* superio not present */
if (!sio_dev.iosapic_irq_enabled)
superio_init(&sio_dev);
if (!parport_pc_probe_port(sio_dev.pp_base,
0 /*base_hi*/,
sio_dev.irq_region->data.irqbase + PAR_IRQ,
PARPORT_DMA_NONE /* dma */,
NULL /*struct pci_dev* */))
#ifdef CONFIG_PARPORT_PC
if (!parport_pc_probe_port(sio_dev.pp_base,
0 /*base_hi*/,
sio_dev.irq_region->data.irqbase + PAR_IRQ,
PARPORT_DMA_NONE /* dma */,
NULL /*struct pci_dev* */) )
printk(KERN_WARNING "SuperIO: Probing parallel port failed.\n");
}
EXPORT_SYMBOL(superio_parport_init);
#endif /* CONFIG_PARPORT_PC */
}
int
......@@ -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)
{
#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),
dev->vendor, dev->device,
dev->subsystem_vendor, dev->subsystem_device,
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) {
#ifdef CONFIG_PARPORT_PC
if (dev->device == PCI_DEVICE_ID_NS_87560_LIO) { /* Function 1 */
superio_parport_init();
#endif
#ifdef CONFIG_SERIAL_8250
superio_serial_init();
#endif
/* REVISIT : superio_fdc_init() ? */
/* REVISIT XXX : superio_fdc_init() ? */
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 {
/* don't claim this device; let whatever either driver
* do it
*/
return -1;
DBG_INIT("superio_probe: WTF? Fire Extinguisher?\n");
}
/* Let appropriate other driver claim this device. */
return -ENODEV;
}
static struct pci_device_id superio_tbl[] = {
......@@ -524,10 +527,6 @@ static void __exit superio_exit(void)
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_exit(superio_exit);
......@@ -24,6 +24,7 @@
#include <linux/serial.h>
#include <linux/console.h>
#include <linux/slab.h>
#include <linux/delay.h> /* for udelay */
#include <asm/io.h>
#include <asm/parisc-device.h>
......@@ -47,15 +48,17 @@
#define MUX_STATUS(status) ((status & 0xF000) == 0x8000)
#define MUX_BREAK(status) ((status & 0xF000) == 0x2000)
#define UART_NR 8
struct mux_card {
struct uart_port ports[UART_NR];
struct uart_driver drv;
struct mux_card *next;
};
static struct mux_card mux_card_head = {
.next = NULL,
#define MUX_NR 256
static unsigned int port_cnt = 0;
static struct uart_port mux_ports[MUX_NR];
static struct uart_driver mux_driver = {
.owner = THIS_MODULE,
.driver_name = "ttyB",
.dev_name = "ttyB",
.major = MUX_MAJOR,
.minor = 0,
.nr = MUX_NR,
};
static struct timer_list mux_timer;
......@@ -181,7 +184,7 @@ static void mux_write(struct uart_port *port)
return;
}
count = (port->fifosize >> 1) - UART_GET_FIFO_CNT(port);
count = (port->fifosize) - UART_GET_FIFO_CNT(port);
do {
UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
......@@ -191,6 +194,9 @@ static void mux_write(struct uart_port *port)
} while(--count > 0);
while(UART_GET_FIFO_CNT(port))
udelay(1);
if(uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
......@@ -361,28 +367,46 @@ static int mux_verify_port(struct uart_port *port, struct serial_struct *ser)
static void mux_poll(unsigned long unused)
{
int i;
struct mux_card *card = &mux_card_head;
while(card) {
for(i = 0; i < UART_NR; ++i) {
if(!card->ports[i].info)
continue;
for(i = 0; i < port_cnt; ++i) {
if(!mux_ports[i].info)
continue;
mux_read(&card->ports[i]);
mux_write(&card->ports[i]);
}
card = card->next;
mux_read(&mux_ports[i]);
mux_write(&mux_ports[i]);
}
mod_timer(&mux_timer, jiffies + MUX_POLL_DELAY);
}
#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 = {
.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,
};
#define MUX_CONSOLE &mux_console
#else
#define MUX_CONSOLE NULL
......@@ -416,77 +440,53 @@ static struct uart_ops mux_pops = {
*/
static int __init mux_probe(struct parisc_device *dev)
{
int i, j, ret, ports, port_cnt = 0;
u8 iodc_data[8];
int i, status, ports;
u8 iodc_data[32];
unsigned long bytecnt;
struct uart_port *port;
struct mux_card *card = &mux_card_head;
ret = pdc_iodc_read(&bytecnt, dev->hpa, 0, iodc_data, 8);
if(ret != PDC_OK) {
status = pdc_iodc_read(&bytecnt, dev->hpa, 0, iodc_data, 32);
if(status != PDC_OK) {
printk(KERN_ERR "Serial mux: Unable to read IODC.\n");
return 1;
}
ports = GET_MUX_PORTS(iodc_data);
printk(KERN_INFO "Serial mux driver (%d ports) Revision: 0.2\n",
ports);
if(!card->drv.nr) {
init_timer(&mux_timer);
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;
}
printk(KERN_INFO "Serial mux driver (%d ports) Revision: 0.3\n", ports);
card->drv.owner = THIS_MODULE;
card->drv.driver_name = "ttyB";
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;
if(!port_cnt) {
mux_driver.cons = MUX_CONSOLE;
ret = uart_register_driver(&card->drv);
if(ret) {
status = uart_register_driver(&mux_driver);
if(status) {
printk(KERN_ERR "Serial mux: Unable to register driver.\n");
return 1;
}
for(j = 0; j < UART_NR; ++j) {
port = &card->ports[j];
port->iobase = 0;
port->mapbase = dev->hpa + MUX_OFFSET + (j * MUX_LINE_OFFSET);
port->membase = ioremap(port->mapbase, MUX_LINE_OFFSET);
port->iotype = SERIAL_IO_MEM;
port->type = PORT_MUX;
port->irq = SERIAL_IRQ_NONE;
port->uartclk = 0;
port->fifosize = MUX_FIFO_SIZE;
port->ops = &mux_pops;
port->flags = UPF_BOOT_AUTOCONF;
port->line = j;
ret = uart_add_one_port(&card->drv, port);
BUG_ON(ret);
}
port_cnt += UART_NR;
init_timer(&mux_timer);
mux_timer.function = mux_poll;
}
for(i = 0; i < ports; ++i, ++port_cnt) {
port = &mux_ports[port_cnt];
port->iobase = 0;
port->mapbase = dev->hpa + MUX_OFFSET + (i * MUX_LINE_OFFSET);
port->membase = ioremap(port->mapbase, MUX_LINE_OFFSET);
port->iotype = SERIAL_IO_MEM;
port->type = PORT_MUX;
port->irq = SERIAL_IRQ_NONE;
port->uartclk = 0;
port->fifosize = MUX_FIFO_SIZE;
port->ops = &mux_pops;
port->flags = UPF_BOOT_AUTOCONF;
port->line = port_cnt;
status = uart_add_one_port(&mux_driver, port);
BUG_ON(status);
}
#ifdef CONFIG_SERIAL_MUX_CONSOLE
register_console(&mux_console);
#endif
return 0;
}
......@@ -497,7 +497,7 @@ static struct parisc_device_id mux_tbl[] = {
MODULE_DEVICE_TABLE(parisc, mux_tbl);
static struct parisc_driver mux_driver = {
static struct parisc_driver serial_mux_driver = {
.name = "Serial MUX",
.id_table = mux_tbl,
.probe = mux_probe,
......@@ -510,7 +510,7 @@ static struct parisc_driver mux_driver = {
*/
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)
static void __exit mux_exit(void)
{
int i;
struct mux_card *card = &mux_card_head;
for (i = 0; i < UART_NR; i++) {
uart_remove_one_port(&card->drv, &card->ports[i]);
for (i = 0; i < port_cnt; i++) {
uart_remove_one_port(&mux_driver, &mux_ports[i]);
}
uart_unregister_driver(&card->drv);
uart_unregister_driver(&mux_driver);
}
module_init(mux_init);
......
......@@ -588,18 +588,18 @@ sti_select_font(struct sti_cooked_rom *rom,
static void __init
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[1],
rom->revno[0] >> 4,
rom->revno[0] & 0x0f);
DPRINTK((" supports %d monitors\n", rom->num_mons));
DPRINTK((" font start %08x\n", rom->font_start));
DPRINTK((" region list %08x\n", rom->region_list));
DPRINTK((" init_graph %08x\n", rom->init_graph));
DPRINTK((" bus support %02x\n", rom->bus_support));
DPRINTK((" ext bus support %02x\n", rom->ext_bus_support));
DPRINTK((" alternate code type %d\n", rom->alt_code_type));
DPRINTK((" supports %d monitors\n", rom->num_mons));
DPRINTK((" font start %08x\n", rom->font_start));
DPRINTK((" region list %08x\n", rom->region_list));
DPRINTK((" init_graph %08x\n", rom->init_graph));
DPRINTK((" bus support %02x\n", rom->bus_support));
DPRINTK((" ext bus support %02x\n", rom->ext_bus_support));
DPRINTK((" alternate code type %d\n", rom->alt_code_type));
}
......@@ -869,14 +869,14 @@ sti_try_rom_generic(unsigned long address, unsigned long hpa, struct pci_dev *pd
ok = 0;
if ((sig & 0xff) == 0x01) {
printk(KERN_INFO "STI byte mode ROM at %08lx, hpa at %08lx\n",
address, hpa);
DPRINTK((" byte mode ROM at %08lx, hpa at %08lx\n",
address, hpa));
ok = sti_read_rom(0, sti, address);
}
if ((sig & 0xffff) == 0x0303) {
printk(KERN_INFO "STI word mode ROM at %08lx, hpa at %08lx\n",
address, hpa);
DPRINTK((" word mode ROM at %08lx, hpa at %08lx\n",
address, hpa));
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
sti_dump_globcfg(sti->glob_cfg, sti->sti_mem_request);
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;
num_sti_roms++;
......
......@@ -3,7 +3,7 @@
* Low level Frame buffer driver for HP workstations with
* 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>
*
* Based on:
......@@ -39,10 +39,10 @@
*/
/* TODO:
* - remove the static fb_info to support multiple cards
* - 1bpp mode is completely untested
* - add support for h/w acceleration
* - add hardware cursor
* - automatically disable double buffering (e.g. on RDI precisionbook laptop)
*/
......@@ -51,6 +51,8 @@
* #undef FALLBACK_TO_1BPP to reject support for unsupported cards */
#undef FALLBACK_TO_1BPP
#undef DEBUG_STIFB_REGS /* debug sti register accesses */
#include <linux/config.h>
#include <linux/module.h>
......@@ -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_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 DISABLE 0
......@@ -390,7 +411,7 @@ ARTIST_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
WRITE_WORD(val, fb, REG_6)
#define NGLE_LONG_FB_ADDRESS(fbaddrbase, x, y) ( \
(u32) (fbaddrbase) + \
(u32) (fbaddrbase) + \
( (unsigned int) ( (y) << 13 ) | \
(unsigned int) ( (x) << 2 ) ) \
)
......@@ -449,6 +470,13 @@ SETUP_ATTR_ACCESS(struct stifb_info *fb, unsigned BufferNumber)
static void
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((width<<16) | height, fb, REG_9);
WRITE_WORD(0x05000000, fb, REG_6);
......@@ -730,7 +758,7 @@ hyperResetPlanes(struct stifb_info *fb, int enable)
controlPlaneReg = 0x00000F00; /* 0x00000100 should be enought, but lets clear all 4 bits */
switch (enable) {
case 1: /* ENABLE */
case ENABLE:
/* clear screen */
if (IS_24_DEVICE(fb))
ngleDepth24_ClearImagePlanes(fb);
......@@ -750,7 +778,7 @@ hyperResetPlanes(struct stifb_info *fb, int enable)
hyperUndoITE(fb);
break;
case 0: /* DISABLE */
case DISABLE:
/* clear screen */
if (IS_24_DEVICE(fb))
ngleDepth24_ClearImagePlanes(fb);
......@@ -974,6 +1002,8 @@ stifb_setcolreg(u_int regno, u_int red, u_int green,
green >>= 8;
blue >>= 8;
DEBUG_OFF();
START_IMAGE_COLORMAP_ACCESS(fb);
if (fb->info.var.grayscale) {
......@@ -1005,6 +1035,8 @@ stifb_setcolreg(u_int regno, u_int red, u_int green,
FINISH_IMAGE_COLORMAP_ACCESS(fb);
}
DEBUG_ON();
return 0;
}
......@@ -1144,17 +1176,28 @@ stifb_init_fb(struct sti_struct *sti, int force_bpp)
/* only supported cards are allowed */
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_HCRX:
case S9000_ID_TIMBER:
case S9000_ID_A1659A:
case S9000_ID_A1439A:
case CRT_ID_VISUALIZE_EG:
break;
default:
printk(KERN_WARNING "stifb: Unsupported gfx card id 0x%08x\n",
fb->id);
goto out_err1;
printk(KERN_WARNING "stifb: '%s' (id: 0x%08x) not supported.\n",
sti->outptr.dev_name, fb->id);
goto out_err0;
}
/* default to 8 bpp on most graphic chips */
......@@ -1232,7 +1275,7 @@ stifb_init_fb(struct sti_struct *sti, int force_bpp)
"stifb: Unsupported graphics card (id=0x%08x) "
"- skipping.\n",
fb->id);
goto out_err1;
goto out_err0;
#endif
}
......@@ -1306,12 +1349,13 @@ stifb_init_fb(struct sti_struct *sti, int force_bpp)
sti->info = info; /* save for unregister_framebuffer() */
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,
fix->id,
var->xres,
var->yres,
var->bits_per_pixel,
sti->outptr.dev_name,
fb->id,
fix->mmio_start);
......@@ -1324,16 +1368,24 @@ stifb_init_fb(struct sti_struct *sti, int force_bpp)
release_mem_region(fix->smem_start, fix->smem_len);
out_err1:
fb_dealloc_cmap(&info->cmap);
out_err0:
kfree(fb);
return -ENXIO;
}
static int stifb_disabled __initdata;
int __init
stifb_init(void)
{
struct sti_struct *sti;
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++) {
sti = sti_get_rom(i);
if (!sti)
......@@ -1379,6 +1431,11 @@ stifb_setup(char *options)
if (!options || !*options)
return 0;
if (strncmp(options, "off", 3) == 0) {
stifb_disabled = 1;
options += 3;
}
if (strncmp(options, "bpp", 3) == 0) {
options += 3;
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