Change the way that scatter/gather list tables are allocated so that we

can use all of the s/g entries available on smaller cards.  This is
necessary if we want to be able to handle a non-page-aligned 64k transfer
on 2.x and 3.x firmware.

Fix a missing splx() that may have left us at splbio() for longer than
desired.

Reduce shadowing of controller-supplied parameters a little.
This commit is contained in:
Mike Smith 2000-05-06 08:54:33 +00:00
parent 1fdb6e6c69
commit baff09db2c
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=60074
4 changed files with 58 additions and 39 deletions

View File

@ -227,7 +227,7 @@ static int
mlx_sglist_map(struct mlx_softc *sc)
{
size_t segsize;
int error;
int error, ncmd;
debug_called(1);
@ -239,9 +239,16 @@ mlx_sglist_map(struct mlx_softc *sc)
/*
* Create a single tag describing a region large enough to hold all of
* the s/g lists we will need.
* the s/g lists we will need. If we're called early on, we don't know how
* many commands we're going to be asked to support, so only allocate enough
* for a couple.
*/
segsize = sizeof(struct mlx_sgentry) * sc->mlx_sg_nseg * sc->mlx_maxiop;
if (sc->mlx_enq2 == NULL) {
ncmd = 2;
} else {
ncmd = sc->mlx_enq2->me_max_commands;
}
segsize = sizeof(struct mlx_sgentry) * MLX_NSEG * ncmd;
error = bus_dma_tag_create(sc->mlx_parent_dmat, /* parent */
1, 0, /* alignment, boundary */
BUS_SPACE_MAXADDR, /* lowaddr */
@ -301,21 +308,18 @@ mlx_attach(struct mlx_softc *sc)
sc->mlx_findcomplete = mlx_v3_findcomplete;
sc->mlx_intaction = mlx_v3_intaction;
sc->mlx_fw_handshake = mlx_v3_fw_handshake;
sc->mlx_sg_nseg = MLX_NSEG_OLD;
break;
case MLX_IFTYPE_4:
sc->mlx_tryqueue = mlx_v4_tryqueue;
sc->mlx_findcomplete = mlx_v4_findcomplete;
sc->mlx_intaction = mlx_v4_intaction;
sc->mlx_fw_handshake = mlx_v4_fw_handshake;
sc->mlx_sg_nseg = MLX_NSEG_NEW;
break;
case MLX_IFTYPE_5:
sc->mlx_tryqueue = mlx_v5_tryqueue;
sc->mlx_findcomplete = mlx_v5_findcomplete;
sc->mlx_intaction = mlx_v5_intaction;
sc->mlx_fw_handshake = mlx_v5_fw_handshake;
sc->mlx_sg_nseg = MLX_NSEG_NEW;
break;
default:
mlx_free(sc);
@ -376,7 +380,7 @@ mlx_attach(struct mlx_softc *sc)
BUS_SPACE_MAXADDR, /* lowaddr */
BUS_SPACE_MAXADDR, /* highaddr */
NULL, NULL, /* filter, filterarg */
MAXBSIZE, sc->mlx_sg_nseg, /* maxsize, nsegments */
MAXBSIZE, MLX_NSEG, /* maxsize, nsegments */
BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */
0, /* flags */
&sc->mlx_buffer_dmat);
@ -387,9 +391,8 @@ mlx_attach(struct mlx_softc *sc)
}
/*
* Create an initial set of s/g mappings.
* Create some initial scatter/gather mappings so we can run the probe commands.
*/
sc->mlx_maxiop = 8;
error = mlx_sglist_map(sc);
if (error != 0) {
device_printf(sc->mlx_dev, "can't make initial s/g list mapping\n");
@ -397,18 +400,20 @@ mlx_attach(struct mlx_softc *sc)
return(error);
}
/* send an ENQUIRY2 to the controller */
/*
* We don't (yet) know where the event log is up to.
*/
sc->mlx_currevent = -1;
/*
* Obtain controller feature information
*/
if ((sc->mlx_enq2 = mlx_enquire(sc, MLX_CMD_ENQUIRY2, sizeof(struct mlx_enquiry2), NULL)) == NULL) {
device_printf(sc->mlx_dev, "ENQUIRY2 failed\n");
mlx_free(sc);
return(ENXIO);
}
/*
* We don't (yet) know where the event log is up to.
*/
sc->mlx_currevent = -1;
/*
* Do quirk/feature related things.
*/
@ -456,13 +461,11 @@ mlx_attach(struct mlx_softc *sc)
}
/*
* Create the final set of s/g mappings now that we know how many commands
* the controller actually supports.
* Create the final scatter/gather mappings now that we have characterised the controller.
*/
sc->mlx_maxiop = sc->mlx_enq2->me_max_commands;
error = mlx_sglist_map(sc);
if (error != 0) {
device_printf(sc->mlx_dev, "can't make permanent s/g list mapping\n");
device_printf(sc->mlx_dev, "can't make final s/g list mapping\n");
mlx_free(sc);
return(error);
}
@ -1953,13 +1956,19 @@ static int
mlx_getslot(struct mlx_command *mc)
{
struct mlx_softc *sc = mc->mc_sc;
int s, slot;
int s, slot, limit;
debug_called(1);
/* enforce slot-usage limit */
if (sc->mlx_busycmds >= ((mc->mc_flags & MLX_CMD_PRIORITY) ?
sc->mlx_maxiop : sc->mlx_maxiop - 4))
/*
* Enforce slot-usage limit, if we have the required information.
*/
if (sc->mlx_enq2 != NULL) {
limit = sc->mlx_enq2->me_max_commands;
} else {
limit = 2;
}
if (sc->mlx_busycmds >= ((mc->mc_flags & MLX_CMD_PRIORITY) ? limit : limit - 4))
return(EBUSY);
/*
@ -1968,19 +1977,19 @@ mlx_getslot(struct mlx_command *mc)
* XXX linear search is slow
*/
s = splbio();
for (slot = 0; slot < sc->mlx_maxiop; slot++) {
for (slot = 0; slot < limit; slot++) {
debug(2, "try slot %d", slot);
if (sc->mlx_busycmd[slot] == NULL)
break;
}
if (slot < sc->mlx_maxiop) {
if (slot < limit) {
sc->mlx_busycmd[slot] = mc;
sc->mlx_busycmds++;
}
splx(s);
/* out of slots? */
if (slot >= sc->mlx_maxiop)
if (slot >= limit)
return(EBUSY);
debug(2, "got slot %d", slot);
@ -2001,12 +2010,16 @@ mlx_setup_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error)
debug_called(1);
/* XXX should be unnecessary */
if (sc->mlx_enq2 && (nsegments > sc->mlx_enq2->me_max_sg))
panic("MLX: too many s/g segments (%d, max %d)", nsegments, sc->mlx_enq2->me_max_sg);
/* get base address of s/g table */
sg = sc->mlx_sgtable + (mc->mc_slot * sc->mlx_sg_nseg);
sg = sc->mlx_sgtable + (mc->mc_slot * MLX_NSEG);
/* save s/g table information in command */
mc->mc_nsgent = nsegments;
mc->mc_sgphys = sc->mlx_sgbusaddr + (mc->mc_slot * sc->mlx_sg_nseg * sizeof(struct mlx_sgentry));
mc->mc_sgphys = sc->mlx_sgbusaddr + (mc->mc_slot * MLX_NSEG * sizeof(struct mlx_sgentry));
mc->mc_dataphys = segs[0].ds_addr;
/* populate s/g table */
@ -2146,6 +2159,7 @@ mlx_done(struct mlx_softc *sc)
break;
}
}
splx(s);
/* if we've completed any commands, try posting some more */
if (result)

View File

@ -236,6 +236,7 @@ mlxd_attach(device_t dev)
device_t parent;
char *state;
dev_t dsk;
int s1, s2;
debug_called(1);
@ -272,8 +273,13 @@ mlxd_attach(device_t dev)
dsk->si_drv1 = sc;
sc->mlxd_dev_t = dsk;
/* set maximum I/O size */
dsk->si_iosize_max = sc->mlxd_controller->mlx_enq2->me_maxblk * MLX_BLKSIZE;
/*
* Set maximum I/O size to the lesser of the recommended maximum and the practical
* maximum.
*/
s1 = sc->mlxd_controller->mlx_enq2->me_maxblk * MLX_BLKSIZE;
s2 = (sc->mlxd_controller->mlx_enq2->me_max_sg - 1) * PAGE_SIZE;
dsk->si_iosize_max = imin(s1, s2);
return (0);
}

View File

@ -185,7 +185,7 @@ mlx_pci_attach(device_t dev)
BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
BUS_SPACE_MAXADDR, /* highaddr */
NULL, NULL, /* filter, filterarg */
MAXBSIZE, MLX_NSEG_NEW, /* maxsize, nsegments */
MAXBSIZE, MLX_NSEG, /* maxsize, nsegments */
BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */
BUS_DMA_ALLOCNOW, /* flags */
&sc->mlx_parent_dmat);

View File

@ -40,14 +40,15 @@
#define debug_called(level)
#endif
/*
* We could actually use all 17/33 segments, but using only 16/32 means that
* each scatter/gather map is 128/256 bytes in size, and thus we don't have to worry about
* maps crossing page boundaries.
* Regardless of the actual capacity of the controller, we will allocate space
* for 64 s/g entries. Typically controllers support 17 or 33 entries (64k or
* 128k maximum transfer assuming 4k page size and non-optimal alignment), but
* making that fit cleanly without crossing page boundaries requires rounding up
* to the next power of two.
*/
#define MLX_NSEG_OLD 16 /* max scatter/gather segments we use 3.x and earlier */
#define MLX_NSEG_NEW 32 /* max scatter/gather segments we use 4.x and later */
#define MLX_NSEG 64
#define MLX_NSLOTS 256 /* max number of command slots */
#define MLX_MAXDRIVES 32 /* max number of system drives */
@ -120,11 +121,9 @@ struct mlx_softc
u_int32_t mlx_sgbusaddr; /* s/g table base address in bus space */
bus_dma_tag_t mlx_sg_dmat; /* s/g buffer DMA tag */
bus_dmamap_t mlx_sg_dmamap; /* map for s/g buffers */
int mlx_sg_nseg; /* max number of s/g entries */
/* controller limits and features */
struct mlx_enquiry2 *mlx_enq2;
int mlx_maxiop; /* hard maximum number of commands */
int mlx_feature; /* controller features/quirks */
#define MLX_FEAT_PAUSEWORKS (1<<0) /* channel pause works as expected */