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:
parent
1fdb6e6c69
commit
baff09db2c
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=60074
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user