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
@ -227,7 +227,7 @@ static int
|
|||||||
mlx_sglist_map(struct mlx_softc *sc)
|
mlx_sglist_map(struct mlx_softc *sc)
|
||||||
{
|
{
|
||||||
size_t segsize;
|
size_t segsize;
|
||||||
int error;
|
int error, ncmd;
|
||||||
|
|
||||||
debug_called(1);
|
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
|
* 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 */
|
error = bus_dma_tag_create(sc->mlx_parent_dmat, /* parent */
|
||||||
1, 0, /* alignment, boundary */
|
1, 0, /* alignment, boundary */
|
||||||
BUS_SPACE_MAXADDR, /* lowaddr */
|
BUS_SPACE_MAXADDR, /* lowaddr */
|
||||||
@ -301,21 +308,18 @@ mlx_attach(struct mlx_softc *sc)
|
|||||||
sc->mlx_findcomplete = mlx_v3_findcomplete;
|
sc->mlx_findcomplete = mlx_v3_findcomplete;
|
||||||
sc->mlx_intaction = mlx_v3_intaction;
|
sc->mlx_intaction = mlx_v3_intaction;
|
||||||
sc->mlx_fw_handshake = mlx_v3_fw_handshake;
|
sc->mlx_fw_handshake = mlx_v3_fw_handshake;
|
||||||
sc->mlx_sg_nseg = MLX_NSEG_OLD;
|
|
||||||
break;
|
break;
|
||||||
case MLX_IFTYPE_4:
|
case MLX_IFTYPE_4:
|
||||||
sc->mlx_tryqueue = mlx_v4_tryqueue;
|
sc->mlx_tryqueue = mlx_v4_tryqueue;
|
||||||
sc->mlx_findcomplete = mlx_v4_findcomplete;
|
sc->mlx_findcomplete = mlx_v4_findcomplete;
|
||||||
sc->mlx_intaction = mlx_v4_intaction;
|
sc->mlx_intaction = mlx_v4_intaction;
|
||||||
sc->mlx_fw_handshake = mlx_v4_fw_handshake;
|
sc->mlx_fw_handshake = mlx_v4_fw_handshake;
|
||||||
sc->mlx_sg_nseg = MLX_NSEG_NEW;
|
|
||||||
break;
|
break;
|
||||||
case MLX_IFTYPE_5:
|
case MLX_IFTYPE_5:
|
||||||
sc->mlx_tryqueue = mlx_v5_tryqueue;
|
sc->mlx_tryqueue = mlx_v5_tryqueue;
|
||||||
sc->mlx_findcomplete = mlx_v5_findcomplete;
|
sc->mlx_findcomplete = mlx_v5_findcomplete;
|
||||||
sc->mlx_intaction = mlx_v5_intaction;
|
sc->mlx_intaction = mlx_v5_intaction;
|
||||||
sc->mlx_fw_handshake = mlx_v5_fw_handshake;
|
sc->mlx_fw_handshake = mlx_v5_fw_handshake;
|
||||||
sc->mlx_sg_nseg = MLX_NSEG_NEW;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
mlx_free(sc);
|
mlx_free(sc);
|
||||||
@ -376,7 +380,7 @@ mlx_attach(struct mlx_softc *sc)
|
|||||||
BUS_SPACE_MAXADDR, /* lowaddr */
|
BUS_SPACE_MAXADDR, /* lowaddr */
|
||||||
BUS_SPACE_MAXADDR, /* highaddr */
|
BUS_SPACE_MAXADDR, /* highaddr */
|
||||||
NULL, NULL, /* filter, filterarg */
|
NULL, NULL, /* filter, filterarg */
|
||||||
MAXBSIZE, sc->mlx_sg_nseg, /* maxsize, nsegments */
|
MAXBSIZE, MLX_NSEG, /* maxsize, nsegments */
|
||||||
BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */
|
BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */
|
||||||
0, /* flags */
|
0, /* flags */
|
||||||
&sc->mlx_buffer_dmat);
|
&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);
|
error = mlx_sglist_map(sc);
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
device_printf(sc->mlx_dev, "can't make initial s/g list mapping\n");
|
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);
|
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) {
|
if ((sc->mlx_enq2 = mlx_enquire(sc, MLX_CMD_ENQUIRY2, sizeof(struct mlx_enquiry2), NULL)) == NULL) {
|
||||||
device_printf(sc->mlx_dev, "ENQUIRY2 failed\n");
|
device_printf(sc->mlx_dev, "ENQUIRY2 failed\n");
|
||||||
mlx_free(sc);
|
mlx_free(sc);
|
||||||
return(ENXIO);
|
return(ENXIO);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* We don't (yet) know where the event log is up to.
|
|
||||||
*/
|
|
||||||
sc->mlx_currevent = -1;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Do quirk/feature related things.
|
* 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
|
* Create the final scatter/gather mappings now that we have characterised the controller.
|
||||||
* the controller actually supports.
|
|
||||||
*/
|
*/
|
||||||
sc->mlx_maxiop = sc->mlx_enq2->me_max_commands;
|
|
||||||
error = mlx_sglist_map(sc);
|
error = mlx_sglist_map(sc);
|
||||||
if (error != 0) {
|
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);
|
mlx_free(sc);
|
||||||
return(error);
|
return(error);
|
||||||
}
|
}
|
||||||
@ -1953,13 +1956,19 @@ static int
|
|||||||
mlx_getslot(struct mlx_command *mc)
|
mlx_getslot(struct mlx_command *mc)
|
||||||
{
|
{
|
||||||
struct mlx_softc *sc = mc->mc_sc;
|
struct mlx_softc *sc = mc->mc_sc;
|
||||||
int s, slot;
|
int s, slot, limit;
|
||||||
|
|
||||||
debug_called(1);
|
debug_called(1);
|
||||||
|
|
||||||
/* enforce slot-usage limit */
|
/*
|
||||||
if (sc->mlx_busycmds >= ((mc->mc_flags & MLX_CMD_PRIORITY) ?
|
* Enforce slot-usage limit, if we have the required information.
|
||||||
sc->mlx_maxiop : sc->mlx_maxiop - 4))
|
*/
|
||||||
|
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);
|
return(EBUSY);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1968,19 +1977,19 @@ mlx_getslot(struct mlx_command *mc)
|
|||||||
* XXX linear search is slow
|
* XXX linear search is slow
|
||||||
*/
|
*/
|
||||||
s = splbio();
|
s = splbio();
|
||||||
for (slot = 0; slot < sc->mlx_maxiop; slot++) {
|
for (slot = 0; slot < limit; slot++) {
|
||||||
debug(2, "try slot %d", slot);
|
debug(2, "try slot %d", slot);
|
||||||
if (sc->mlx_busycmd[slot] == NULL)
|
if (sc->mlx_busycmd[slot] == NULL)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (slot < sc->mlx_maxiop) {
|
if (slot < limit) {
|
||||||
sc->mlx_busycmd[slot] = mc;
|
sc->mlx_busycmd[slot] = mc;
|
||||||
sc->mlx_busycmds++;
|
sc->mlx_busycmds++;
|
||||||
}
|
}
|
||||||
splx(s);
|
splx(s);
|
||||||
|
|
||||||
/* out of slots? */
|
/* out of slots? */
|
||||||
if (slot >= sc->mlx_maxiop)
|
if (slot >= limit)
|
||||||
return(EBUSY);
|
return(EBUSY);
|
||||||
|
|
||||||
debug(2, "got slot %d", slot);
|
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);
|
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 */
|
/* 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 */
|
/* save s/g table information in command */
|
||||||
mc->mc_nsgent = nsegments;
|
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;
|
mc->mc_dataphys = segs[0].ds_addr;
|
||||||
|
|
||||||
/* populate s/g table */
|
/* populate s/g table */
|
||||||
@ -2146,6 +2159,7 @@ mlx_done(struct mlx_softc *sc)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
splx(s);
|
||||||
|
|
||||||
/* if we've completed any commands, try posting some more */
|
/* if we've completed any commands, try posting some more */
|
||||||
if (result)
|
if (result)
|
||||||
|
@ -236,6 +236,7 @@ mlxd_attach(device_t dev)
|
|||||||
device_t parent;
|
device_t parent;
|
||||||
char *state;
|
char *state;
|
||||||
dev_t dsk;
|
dev_t dsk;
|
||||||
|
int s1, s2;
|
||||||
|
|
||||||
debug_called(1);
|
debug_called(1);
|
||||||
|
|
||||||
@ -272,8 +273,13 @@ mlxd_attach(device_t dev)
|
|||||||
dsk->si_drv1 = sc;
|
dsk->si_drv1 = sc;
|
||||||
sc->mlxd_dev_t = dsk;
|
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);
|
return (0);
|
||||||
}
|
}
|
||||||
|
@ -185,7 +185,7 @@ mlx_pci_attach(device_t dev)
|
|||||||
BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
|
BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
|
||||||
BUS_SPACE_MAXADDR, /* highaddr */
|
BUS_SPACE_MAXADDR, /* highaddr */
|
||||||
NULL, NULL, /* filter, filterarg */
|
NULL, NULL, /* filter, filterarg */
|
||||||
MAXBSIZE, MLX_NSEG_NEW, /* maxsize, nsegments */
|
MAXBSIZE, MLX_NSEG, /* maxsize, nsegments */
|
||||||
BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */
|
BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */
|
||||||
BUS_DMA_ALLOCNOW, /* flags */
|
BUS_DMA_ALLOCNOW, /* flags */
|
||||||
&sc->mlx_parent_dmat);
|
&sc->mlx_parent_dmat);
|
||||||
|
@ -40,14 +40,15 @@
|
|||||||
#define debug_called(level)
|
#define debug_called(level)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We could actually use all 17/33 segments, but using only 16/32 means that
|
* Regardless of the actual capacity of the controller, we will allocate space
|
||||||
* each scatter/gather map is 128/256 bytes in size, and thus we don't have to worry about
|
* for 64 s/g entries. Typically controllers support 17 or 33 entries (64k or
|
||||||
* maps crossing page boundaries.
|
* 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 64
|
||||||
#define MLX_NSEG_NEW 32 /* max scatter/gather segments we use 4.x and later */
|
|
||||||
#define MLX_NSLOTS 256 /* max number of command slots */
|
#define MLX_NSLOTS 256 /* max number of command slots */
|
||||||
|
|
||||||
#define MLX_MAXDRIVES 32 /* max number of system drives */
|
#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 */
|
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_dma_tag_t mlx_sg_dmat; /* s/g buffer DMA tag */
|
||||||
bus_dmamap_t mlx_sg_dmamap; /* map for s/g buffers */
|
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 */
|
/* controller limits and features */
|
||||||
struct mlx_enquiry2 *mlx_enq2;
|
struct mlx_enquiry2 *mlx_enq2;
|
||||||
int mlx_maxiop; /* hard maximum number of commands */
|
|
||||||
int mlx_feature; /* controller features/quirks */
|
int mlx_feature; /* controller features/quirks */
|
||||||
#define MLX_FEAT_PAUSEWORKS (1<<0) /* channel pause works as expected */
|
#define MLX_FEAT_PAUSEWORKS (1<<0) /* channel pause works as expected */
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user