summaryrefslogtreecommitdiffstats
path: root/sys/dev/ips/ips.c
diff options
context:
space:
mode:
authorscottl <scottl@FreeBSD.org>2005-01-28 05:02:13 +0000
committerscottl <scottl@FreeBSD.org>2005-01-28 05:02:13 +0000
commitbad78b265c4a0765532ab7d2ac5493c0a2e39191 (patch)
tree16fadd7614f98d4101435336cd7d5d0a95bbb58d /sys/dev/ips/ips.c
parenta52d6034c25c293be752e89574f77b0c7059ae46 (diff)
downloadFreeBSD-src-bad78b265c4a0765532ab7d2ac5493c0a2e39191.zip
FreeBSD-src-bad78b265c4a0765532ab7d2ac5493c0a2e39191.tar.gz
Lock the IPS driver and bring it out from under Giant. Also do some
significant clean up and optimizations: - don't call bioq_disksort() on every command, the hardware will do that for us. - remove all of the complicated bio deferral code. bio's that can't be serviced immediately can just wait on the bioq. - Only reserve one command object for doing control commands to the card. This simplifies a lot of code and significantly reduces the size of the command struct. - Allocate commands out of a slab instead of embedding them into the softc. - Call the command action method directly instead of having ips_get_free_cmd() call it indirectly. MFC After: 1 week
Diffstat (limited to 'sys/dev/ips/ips.c')
-rw-r--r--sys/dev/ips/ips.c146
1 files changed, 56 insertions, 90 deletions
diff --git a/sys/dev/ips/ips.c b/sys/dev/ips/ips.c
index b1a8297..d1aa459 100644
--- a/sys/dev/ips/ips.c
+++ b/sys/dev/ips/ips.c
@@ -101,7 +101,7 @@ static void ips_cmd_dmaload(void *cmdptr, bus_dma_segment_t *segments,int segnum
}
/* is locking needed? what locking guarentees are there on removal? */
-static __inline__ int ips_cmdqueue_free(ips_softc_t *sc)
+static int ips_cmdqueue_free(ips_softc_t *sc)
{
int i, error = -1;
ips_command_t *command;
@@ -112,7 +112,6 @@ static __inline__ int ips_cmdqueue_free(ips_softc_t *sc)
for(i = 0; i < sc->max_cmds; i++){
command = &sc->commandarray[i];
- sema_destroy(&command->cmd_sema);
if(command->command_phys_addr == 0)
continue;
@@ -121,22 +120,32 @@ static __inline__ int ips_cmdqueue_free(ips_softc_t *sc)
bus_dmamem_free(sc->command_dmatag,
command->command_buffer,
command->command_dmamap);
+ if (command->data_dmamap != NULL)
+ bus_dmamap_destroy(command->data_dmatag,
+ command->data_dmamap);
}
error = 0;
sc->state |= IPS_OFFLINE;
}
+ sc->staticcmd = NULL;
+ free(sc->commandarray, M_DEVBUF);
splx(mask);
return error;
}
/* places all ips command structs on the free command queue. No locking as if someone else tries
* to access this during init, we have bigger problems */
-static __inline__ int ips_cmdqueue_init(ips_softc_t *sc)
+static int ips_cmdqueue_init(ips_softc_t *sc)
{
int i;
ips_command_t *command;
+
+ sc->commandarray = (ips_command_t *)malloc(sizeof(ips_command_t) *
+ sc->max_cmds, M_DEVBUF, M_NOWAIT|M_ZERO);
+ if (sc->commandarray == NULL)
+ return (ENOMEM);
+
SLIST_INIT(&sc->free_cmd_list);
- STAILQ_INIT(&sc->cmd_wait_list);
for(i = 0; i < sc->max_cmds; i++){
command = &sc->commandarray[i];
command->id = i;
@@ -154,8 +163,14 @@ static __inline__ int ips_cmdqueue_init(ips_softc_t *sc)
goto error;
}
- sema_init(&command->cmd_sema, 0, "IPS Command Semaphore");
- SLIST_INSERT_HEAD(&sc->free_cmd_list, command, next);
+ if (i != 0) {
+ command->data_dmatag = sc->sg_dmatag;
+ if (bus_dmamap_create(command->data_dmatag, 0,
+ &command->data_dmamap))
+ goto error;
+ SLIST_INSERT_HEAD(&sc->free_cmd_list, command, next);
+ } else
+ sc->staticcmd = command;
}
sc->state &= ~IPS_OFFLINE;
return 0;
@@ -164,75 +179,12 @@ error:
return ENOMEM;
}
-static int ips_add_waiting_command(ips_softc_t *sc, int (*callback)(ips_command_t *), void *data, unsigned long flags)
-{
- intrmask_t mask;
- ips_command_t *command;
- ips_wait_list_t *waiter;
- unsigned long memflags = 0;
- if(IPS_NOWAIT_FLAG & flags)
- memflags = M_NOWAIT;
- waiter = malloc(sizeof(ips_wait_list_t), M_IPSBUF, memflags);
- if(!waiter)
- return ENOMEM;
- mask = splbio();
- if(sc->state & IPS_OFFLINE){
- splx(mask);
- free(waiter, M_IPSBUF);
- return EIO;
- }
- command = SLIST_FIRST(&sc->free_cmd_list);
- if(command && !(sc->state & IPS_TIMEOUT)){
- SLIST_REMOVE_HEAD(&sc->free_cmd_list, next);
- (sc->used_commands)++;
- splx(mask);
- clear_ips_command(command);
- bzero(command->command_buffer, IPS_COMMAND_LEN);
- free(waiter, M_IPSBUF);
- command->arg = data;
- return callback(command);
- }
- DEVICE_PRINTF(1, sc->dev, "adding command to the wait queue\n");
- waiter->callback = callback;
- waiter->data = data;
- STAILQ_INSERT_TAIL(&sc->cmd_wait_list, waiter, next);
- splx(mask);
- return 0;
-}
-
-static void ips_run_waiting_command(ips_softc_t *sc)
-{
- ips_wait_list_t *waiter;
- ips_command_t *command;
- int (*callback)(ips_command_t*);
- intrmask_t mask;
-
- mask = splbio();
- waiter = STAILQ_FIRST(&sc->cmd_wait_list);
- command = SLIST_FIRST(&sc->free_cmd_list);
- if(!waiter || !command){
- splx(mask);
- return;
- }
- DEVICE_PRINTF(1, sc->dev, "removing command from wait queue\n");
- SLIST_REMOVE_HEAD(&sc->free_cmd_list, next);
- STAILQ_REMOVE_HEAD(&sc->cmd_wait_list, next);
- (sc->used_commands)++;
- splx(mask);
- clear_ips_command(command);
- bzero(command->command_buffer, IPS_COMMAND_LEN);
- command->arg = waiter->data;
- callback = waiter->callback;
- free(waiter, M_IPSBUF);
- callback(command);
- return;
-}
/* returns a free command struct if one is available.
* It also blanks out anything that may be a wild pointer/value.
* Also, command buffers are not freed. They are
* small so they are saved and kept dmamapped and loaded.
*/
-int ips_get_free_cmd(ips_softc_t *sc, int (*callback)(ips_command_t *), void *data, unsigned long flags)
+int ips_get_free_cmd(ips_softc_t *sc, ips_command_t **cmd, unsigned long flags)
{
intrmask_t mask;
ips_command_t *command;
@@ -242,20 +194,25 @@ int ips_get_free_cmd(ips_softc_t *sc, int (*callback)(ips_command_t *), void *da
splx(mask);
return EIO;
}
- command = SLIST_FIRST(&sc->free_cmd_list);
- if(!command || (sc->state & IPS_TIMEOUT)){
- splx(mask);
- if(flags & IPS_NOWAIT_FLAG)
+ if ((flags & IPS_STATIC_FLAG) == 0) {
+ command = SLIST_FIRST(&sc->free_cmd_list);
+ if(!command || (sc->state & IPS_TIMEOUT)){
+ splx(mask);
+ return EBUSY;
+ }
+ SLIST_REMOVE_HEAD(&sc->free_cmd_list, next);
+ (sc->used_commands)++;
+ } else {
+ if (sc->state & IPS_STATIC_BUSY)
return EAGAIN;
- return ips_add_waiting_command(sc, callback, data, flags);
+ command = sc->staticcmd;
+ sc->state |= IPS_STATIC_BUSY;
}
- SLIST_REMOVE_HEAD(&sc->free_cmd_list, next);
- (sc->used_commands)++;
splx(mask);
clear_ips_command(command);
bzero(command->command_buffer, IPS_COMMAND_LEN);
- command->arg = data;
- return callback(command);
+ *cmd = command;
+ return 0;
}
/* adds a command back to the free command queue */
@@ -264,14 +221,16 @@ void ips_insert_free_cmd(ips_softc_t *sc, ips_command_t *command)
intrmask_t mask;
mask = splbio();
- if (sema_value(&command->cmd_sema) != 0)
+ if (sema_value(&sc->cmd_sema) != 0)
panic("ips: command returned non-zero semaphore");
- SLIST_INSERT_HEAD(&sc->free_cmd_list, command, next);
- (sc->used_commands)--;
+ if (command != sc->staticcmd) {
+ SLIST_INSERT_HEAD(&sc->free_cmd_list, command, next);
+ (sc->used_commands)--;
+ } else {
+ sc->state &= ~IPS_STATIC_BUSY;
+ }
splx(mask);
- if(!(sc->state & IPS_TIMEOUT))
- ips_run_waiting_command(sc);
}
static const char* ips_diskdev_statename(u_int8_t state)
{
@@ -348,6 +307,8 @@ static void ips_timeout(void *arg)
ips_softc_t *sc = arg;
int i, state = 0;
ips_command_t *command;
+
+ mtx_lock(&sc->queue_mtx);
command = &sc->commandarray[0];
mask = splbio();
for(i = 0; i < sc->max_cmds; i++){
@@ -376,10 +337,10 @@ static void ips_timeout(void *arg)
would go to the card. This sucks. */
} else
sc->state &= ~IPS_TIMEOUT;
- ips_run_waiting_command(sc);
}
if (sc->state != IPS_OFFLINE)
sc->timer = timeout(ips_timeout, sc, 10*hz);
+ mtx_unlock(&sc->queue_mtx);
splx(mask);
}
@@ -402,8 +363,8 @@ int ips_adapter_init(ips_softc_t *sc)
/* maxsegsize*/ IPS_COMMAND_LEN +
IPS_MAX_SG_LEN,
/* flags */ 0,
- /* lockfunc */ busdma_lock_mutex,
- /* lockarg */ &Giant,
+ /* lockfunc */ NULL,
+ /* lockarg */ NULL,
&sc->command_dmatag) != 0) {
device_printf(sc->dev, "can't alloc command dma tag\n");
goto error;
@@ -420,7 +381,7 @@ int ips_adapter_init(ips_softc_t *sc)
/* maxsegsize*/ IPS_MAX_IOBUF_SIZE,
/* flags */ 0,
/* lockfunc */ busdma_lock_mutex,
- /* lockarg */ &Giant,
+ /* lockarg */ &sc->queue_mtx,
&sc->sg_dmatag) != 0) {
device_printf(sc->dev, "can't alloc SG dma tag\n");
goto error;
@@ -563,11 +524,13 @@ void ips_morpheus_intr(void *void_sc)
int cmdnumber;
ips_cmd_status_t status;
+ mtx_lock(&sc->queue_mtx);
iisr =ips_read_4(sc, MORPHEUS_REG_IISR);
oisr =ips_read_4(sc, MORPHEUS_REG_OISR);
PRINTF(9,"interrupt registers in:%x out:%x\n",iisr, oisr);
if(!(oisr & MORPHEUS_BIT_CMD_IRQ)){
DEVICE_PRINTF(2,sc->dev, "got a non-command irq\n");
+ mtx_unlock(&sc->queue_mtx);
return;
}
while((status.value = ips_read_4(sc, MORPHEUS_REG_OQPR)) != 0xffffffff){
@@ -579,6 +542,7 @@ void ips_morpheus_intr(void *void_sc)
DEVICE_PRINTF(9,sc->dev, "got command %d\n", cmdnumber);
}
+ mtx_unlock(&sc->queue_mtx);
return;
}
@@ -622,8 +586,8 @@ static int ips_copperhead_queue_init(ips_softc_t *sc)
/* numsegs */ 1,
/* maxsegsize*/ sizeof(ips_copper_queue_t),
/* flags */ 0,
- /* lockfunc */ busdma_lock_mutex,
- /* lockarg */ &Giant,
+ /* lockfunc */ NULL,
+ /* lockarg */ NULL,
&dmatag) != 0) {
device_printf(sc->dev, "can't alloc dma tag for statue queue\n");
error = ENOMEM;
@@ -742,6 +706,7 @@ void ips_copperhead_intr(void *void_sc)
int cmdnumber;
ips_cmd_status_t status;
+ mtx_lock(&sc->queue_mtx);
while(ips_read_1(sc, COPPER_REG_HISR) & COPPER_SCE_BIT){
status.value = ips_copperhead_cmd_status(sc);
cmdnumber = status.fields.command_id;
@@ -750,6 +715,7 @@ void ips_copperhead_intr(void *void_sc)
sc->commandarray[cmdnumber].callback(&(sc->commandarray[cmdnumber]));
PRINTF(9, "ips: got command %d\n", cmdnumber);
}
+ mtx_unlock(&sc->queue_mtx);
return;
}
OpenPOWER on IntegriCloud