4d9966a39e
Initialize rid to 0. This doesn't seem to make any difference (the driver doesn't care what rid it gets and no-one seems to check rid's value), but follows standard conventions. Pass in our device_t to ahc_alloc(). We now use device_T softc storage, so passing NULL results in a panic. Set the unit number in our softc so that the driver core can retrieve it. ahc_pci.c: Set the unit number in our softc so that the driver core can retrieve it. aic7770.c: Insert our softc into the list of softcs when initialization is successful. aic7xxx.c: Remove a workaround for an aic7895 bug we will never trigger. Add additional diagnostic info to ahc_dump_card_state(). Always panic the system if a sequencer assertion fails. AHC_SCB_BTT is a "flag" not a "feature". Check the right field in the softc. Replace a hard coded number with a constant. Guard against looping forever in ahc_pause_and_flushwork(). A hot eject or card failure may make the intstat register return 0xFF, so limit the number of interrupts we'll process. Correct the code in ahc_search_qinfifo() that guarantees that the sequencer will see an abort collision if the qinfifo is modified when a DMA is in progress. We now do this fixup after modifying the queue. This guarantees that the HSCB we place at the head of the queue is not the same as the old head. Using "next hscb" (guaranteed not to be the same as the first SCB) before clearing the queue could free up the original head hscb to be used during a remove operation placing it again at the head of the qinfifo. aic7xxx.h: Reduce the maximum number of outstanding commands to 253 from 254. To handle our output queue correctly on machines that only support 32bit stores, we must clear the array 4 bytes at a time. To avoid colliding with a DMA write from the sequencer, we must be sure that 4 slots are empty when we write to clear the queue. This reduces us to 253 SCBs: 1 that just completed and the known three additional empty slots in the queue that preceed it. Yahoo was able to force this race on one of their systems. Interrupts were disabled for such a time that the entire output queue was filled (254 entries complete without any processing), and our 32bit write to clear the status clobbered one entry. Add a feature tag for devices that are removable. aic7xxx.reg: Never use the sequencer interrupt value of 0xF0. We need to guanrantee that an INTSTAT value of 0xFF can only occur during card failure or a hot-eject. Align the busy targets table with the begining of scratch space. This seems to appease a chip bug in the aic7895. aic7xxx.seq: Be sure to disable select-out after a bus free event that occurs early in a selection. If we don't disable select-out, we will believe that it is enabled even though a new selection will never occur. Move the clearing of SELDI to just before a jump. This appeases another chip bug of the aic7895. Make the target mode command loop a bit more efficient. AHC_SCB_BTT is a "flag" not a "feature". Check the right field in the softc. Properly cleanup the last SCB we tested against should we fail to properly find an SCB for a reselection. Add some additional sequencer debugging code. aic7xxx_freebsd.c: Limit the driver to 253 outstanding commands per adapter. Guard against overflow in timeout handling. aic7xxx_inline.h: AHC_SCB_BTT is a "flag" not a "feature". Check the right field in the softc. aic7xxx_pci.c: Set the removable feature for the apa1480 cardbus and the 29160C Compact PCI card. Don't report high byte termination information for narrow cards. Use a PCI read rather than a questionable delay when fetching/setting termination settings.
214 lines
5.5 KiB
C
214 lines
5.5 KiB
C
/*
|
|
* FreeBSD, EISA product support functions
|
|
*
|
|
*
|
|
* Copyright (c) 1994, 1995, 1996, 1997, 1998, 2000 Justin T. Gibbs.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice immediately at the beginning of the file, without modification,
|
|
* this list of conditions, and the following disclaimer.
|
|
* 2. The name of the author may not be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*
|
|
* $Id$
|
|
*
|
|
* $FreeBSD$
|
|
*/
|
|
|
|
#include <dev/aic7xxx/aic7xxx_freebsd.h>
|
|
|
|
#include <dev/eisa/eisaconf.h>
|
|
|
|
static int
|
|
aic7770_probe(device_t dev)
|
|
{
|
|
struct aic7770_identity *entry;
|
|
struct resource *regs;
|
|
uint32_t iobase;
|
|
bus_space_handle_t bsh;
|
|
bus_space_tag_t tag;
|
|
u_int irq;
|
|
u_int intdef;
|
|
u_int hcntrl;
|
|
int shared;
|
|
int rid;
|
|
int error;
|
|
|
|
entry = aic7770_find_device(eisa_get_id(dev));
|
|
if (entry == NULL)
|
|
return (ENXIO);
|
|
device_set_desc(dev, entry->name);
|
|
|
|
iobase = (eisa_get_slot(dev) * EISA_SLOT_SIZE) + AHC_EISA_SLOT_OFFSET;
|
|
|
|
eisa_add_iospace(dev, iobase, AHC_EISA_IOSIZE, RESVADDR_NONE);
|
|
|
|
rid = 0;
|
|
regs = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
|
|
0, ~0, 1, RF_ACTIVE);
|
|
if (regs == NULL) {
|
|
device_printf(dev, "Unable to map I/O space?!\n");
|
|
return ENOMEM;
|
|
}
|
|
|
|
tag = rman_get_bustag(regs);
|
|
bsh = rman_get_bushandle(regs);
|
|
error = 0;
|
|
|
|
/* Pause the card preseving the IRQ type */
|
|
hcntrl = bus_space_read_1(tag, bsh, HCNTRL) & IRQMS;
|
|
bus_space_write_1(tag, bsh, HCNTRL, hcntrl | PAUSE);
|
|
while ((bus_space_read_1(tag, bsh, HCNTRL) & PAUSE) == 0)
|
|
;
|
|
|
|
/* Make sure we have a valid interrupt vector */
|
|
intdef = bus_space_read_1(tag, bsh, INTDEF);
|
|
shared = (intdef & EDGE_TRIG) ? EISA_TRIGGER_EDGE : EISA_TRIGGER_LEVEL;
|
|
irq = intdef & VECTOR;
|
|
switch (irq) {
|
|
case 9:
|
|
case 10:
|
|
case 11:
|
|
case 12:
|
|
case 14:
|
|
case 15:
|
|
break;
|
|
default:
|
|
printf("aic7770 at slot %d: illegal irq setting %d\n",
|
|
eisa_get_slot(dev), intdef);
|
|
error = ENXIO;
|
|
}
|
|
|
|
if (error == 0)
|
|
eisa_add_intr(dev, irq, shared);
|
|
|
|
bus_release_resource(dev, SYS_RES_IOPORT, rid, regs);
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
aic7770_attach(device_t dev)
|
|
{
|
|
struct aic7770_identity *entry;
|
|
struct ahc_softc *ahc;
|
|
char *name;
|
|
int error;
|
|
|
|
entry = aic7770_find_device(eisa_get_id(dev));
|
|
if (entry == NULL)
|
|
return (ENXIO);
|
|
|
|
/*
|
|
* Allocate a softc for this card and
|
|
* set it up for attachment by our
|
|
* common detect routine.
|
|
*/
|
|
name = malloc(strlen(device_get_nameunit(dev)) + 1, M_DEVBUF, M_NOWAIT);
|
|
if (name == NULL)
|
|
return (ENOMEM);
|
|
strcpy(name, device_get_nameunit(dev));
|
|
ahc = ahc_alloc(dev, name);
|
|
if (ahc == NULL)
|
|
return (ENOMEM);
|
|
|
|
ahc_set_unit(ahc, device_get_unit(dev));
|
|
|
|
/* Allocate a dmatag for our SCB DMA maps */
|
|
/* XXX Should be a child of the PCI bus dma tag */
|
|
error = bus_dma_tag_create(/*parent*/NULL, /*alignment*/1,
|
|
/*boundary*/0,
|
|
/*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
|
|
/*highaddr*/BUS_SPACE_MAXADDR,
|
|
/*filter*/NULL, /*filterarg*/NULL,
|
|
/*maxsize*/MAXBSIZE, /*nsegments*/AHC_NSEG,
|
|
/*maxsegsz*/AHC_MAXTRANSFER_SIZE,
|
|
/*flags*/BUS_DMA_ALLOCNOW,
|
|
&ahc->parent_dmat);
|
|
|
|
if (error != 0) {
|
|
printf("ahc_eisa_attach: Could not allocate DMA tag "
|
|
"- error %d\n", error);
|
|
ahc_free(ahc);
|
|
return (ENOMEM);
|
|
}
|
|
ahc->dev_softc = dev;
|
|
error = aic7770_config(ahc, entry);
|
|
if (error != 0) {
|
|
ahc_free(ahc);
|
|
return (error);
|
|
}
|
|
|
|
ahc_attach(ahc);
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
aic7770_map_registers(struct ahc_softc *ahc)
|
|
{
|
|
struct resource *regs;
|
|
int rid;
|
|
|
|
rid = 0;
|
|
regs = bus_alloc_resource(ahc->dev_softc, SYS_RES_IOPORT,
|
|
&rid, 0, ~0, 1, RF_ACTIVE);
|
|
if (regs == NULL) {
|
|
device_printf(ahc->dev_softc, "Unable to map I/O space?!\n");
|
|
return ENOMEM;
|
|
}
|
|
ahc->platform_data->regs_res_type = SYS_RES_IOPORT;
|
|
ahc->platform_data->regs_res_id = rid,
|
|
ahc->platform_data->regs = regs;
|
|
ahc->tag = rman_get_bustag(regs);
|
|
ahc->bsh = rman_get_bushandle(regs);
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
aic7770_map_int(struct ahc_softc *ahc)
|
|
{
|
|
int zero;
|
|
|
|
zero = 0;
|
|
ahc->platform_data->irq =
|
|
bus_alloc_resource(ahc->dev_softc, SYS_RES_IRQ, &zero,
|
|
0, ~0, 1, RF_ACTIVE);
|
|
if (ahc->platform_data->irq == NULL)
|
|
return (ENOMEM);
|
|
ahc->platform_data->irq_res_type = SYS_RES_IRQ;
|
|
return (0);
|
|
}
|
|
|
|
static device_method_t ahc_eisa_methods[] = {
|
|
/* Device interface */
|
|
DEVMETHOD(device_probe, aic7770_probe),
|
|
DEVMETHOD(device_attach, aic7770_attach),
|
|
DEVMETHOD(device_detach, ahc_detach),
|
|
{ 0, 0 }
|
|
};
|
|
|
|
static driver_t ahc_eisa_driver = {
|
|
"ahc",
|
|
ahc_eisa_methods,
|
|
sizeof(struct ahc_softc)
|
|
};
|
|
|
|
static devclass_t ahc_devclass;
|
|
|
|
DRIVER_MODULE(ahc, eisa, ahc_eisa_driver, ahc_devclass, 0, 0);
|