diff options
author | scottl <scottl@FreeBSD.org> | 2005-01-28 05:02:13 +0000 |
---|---|---|
committer | scottl <scottl@FreeBSD.org> | 2005-01-28 05:02:13 +0000 |
commit | bad78b265c4a0765532ab7d2ac5493c0a2e39191 (patch) | |
tree | 16fadd7614f98d4101435336cd7d5d0a95bbb58d /sys/dev/ips/ips.c | |
parent | a52d6034c25c293be752e89574f77b0c7059ae46 (diff) | |
download | FreeBSD-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.c | 146 |
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; } |