svn commit: r344401 - stable/11/sys/dev/ioat
Alexander Motin
mav at FreeBSD.org
Thu Feb 21 00:44:27 UTC 2019
Author: mav
Date: Thu Feb 21 00:44:26 2019
New Revision: 344401
URL: https://svnweb.freebsd.org/changeset/base/344401
Log:
MFC r302669,302677-302686,303761,304602,304603,305027-305028,305259,
305710,305711,308067-308070,308178,308179,308230,308553,309338,309526,
343125 (by cem): Synchronize ioat(4) with head.
Most of these changes are 3 years old, just never got merged.
Modified:
stable/11/sys/dev/ioat/ioat.c
stable/11/sys/dev/ioat/ioat.h
stable/11/sys/dev/ioat/ioat_hw.h
stable/11/sys/dev/ioat/ioat_internal.h
Directory Properties:
stable/11/ (props changed)
Modified: stable/11/sys/dev/ioat/ioat.c
==============================================================================
--- stable/11/sys/dev/ioat/ioat.c Thu Feb 21 00:17:24 2019 (r344400)
+++ stable/11/sys/dev/ioat/ioat.c Thu Feb 21 00:44:26 2019 (r344401)
@@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$");
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/conf.h>
+#include <sys/fail.h>
#include <sys/ioccom.h>
#include <sys/kernel.h>
#include <sys/lock.h>
@@ -62,7 +63,6 @@ __FBSDID("$FreeBSD$");
#define BUS_SPACE_MAXADDR_40BIT 0xFFFFFFFFFFULL
#endif
#define IOAT_REFLK (&ioat->submit_lock)
-#define IOAT_SHRINK_PERIOD (10 * hz)
static int ioat_probe(device_t device);
static int ioat_attach(device_t device);
@@ -81,23 +81,14 @@ static void ioat_process_events(struct ioat_softc *ioa
static inline uint32_t ioat_get_active(struct ioat_softc *ioat);
static inline uint32_t ioat_get_ring_space(struct ioat_softc *ioat);
static void ioat_free_ring(struct ioat_softc *, uint32_t size,
- struct ioat_descriptor **);
-static void ioat_free_ring_entry(struct ioat_softc *ioat,
- struct ioat_descriptor *desc);
-static struct ioat_descriptor *ioat_alloc_ring_entry(struct ioat_softc *,
- int mflags);
+ struct ioat_descriptor *);
static int ioat_reserve_space(struct ioat_softc *, uint32_t, int mflags);
-static struct ioat_descriptor *ioat_get_ring_entry(struct ioat_softc *ioat,
+static union ioat_hw_descriptor *ioat_get_descriptor(struct ioat_softc *,
uint32_t index);
-static struct ioat_descriptor **ioat_prealloc_ring(struct ioat_softc *,
- uint32_t size, boolean_t need_dscr, int mflags);
-static int ring_grow(struct ioat_softc *, uint32_t oldorder,
- struct ioat_descriptor **);
-static int ring_shrink(struct ioat_softc *, uint32_t oldorder,
- struct ioat_descriptor **);
+static struct ioat_descriptor *ioat_get_ring_entry(struct ioat_softc *,
+ uint32_t index);
static void ioat_halted_debug(struct ioat_softc *, uint32_t);
static void ioat_poll_timer_callback(void *arg);
-static void ioat_shrink_timer_callback(void *arg);
static void dump_descriptor(void *hw_desc);
static void ioat_submit_single(struct ioat_softc *ioat);
static void ioat_comp_update_map(void *arg, bus_dma_segment_t *seg, int nseg,
@@ -134,6 +125,10 @@ int g_ioat_debug_level = 0;
SYSCTL_INT(_hw_ioat, OID_AUTO, debug_level, CTLFLAG_RWTUN, &g_ioat_debug_level,
0, "Set log level (0-3) for ioat(4). Higher is more verbose.");
+unsigned g_ioat_ring_order = 13;
+SYSCTL_UINT(_hw_ioat, OID_AUTO, ring_order, CTLFLAG_RDTUN, &g_ioat_ring_order,
+ 0, "Set IOAT ring order. (1 << this) == ring size.");
+
/*
* OS <-> Driver interface structures
*/
@@ -335,7 +330,6 @@ ioat_detach(device_t device)
ioat_teardown_intr(ioat);
callout_drain(&ioat->poll_timer);
- callout_drain(&ioat->shrink_timer);
pci_disable_busmaster(device);
@@ -353,7 +347,12 @@ ioat_detach(device_t device)
bus_dma_tag_destroy(ioat->comp_update_tag);
}
- bus_dma_tag_destroy(ioat->hw_desc_tag);
+ if (ioat->hw_desc_ring != NULL) {
+ bus_dmamap_unload(ioat->hw_desc_tag, ioat->hw_desc_map);
+ bus_dmamem_free(ioat->hw_desc_tag, ioat->hw_desc_ring,
+ ioat->hw_desc_map);
+ bus_dma_tag_destroy(ioat->hw_desc_tag);
+ }
return (0);
}
@@ -387,8 +386,8 @@ ioat_start_channel(struct ioat_softc *ioat)
/* Submit 'NULL' operation manually to avoid quiescing flag */
desc = ioat_get_ring_entry(ioat, ioat->head);
+ hw_desc = &ioat_get_descriptor(ioat, ioat->head)->dma;
dmadesc = &desc->bus_dmadesc;
- hw_desc = desc->u.dma;
dmadesc->callback_fn = NULL;
dmadesc->callback_arg = NULL;
@@ -425,9 +424,10 @@ static int
ioat3_attach(device_t device)
{
struct ioat_softc *ioat;
- struct ioat_descriptor **ring;
- struct ioat_descriptor *next;
+ struct ioat_descriptor *ring;
struct ioat_dma_hw_descriptor *dma_hw_desc;
+ void *hw_desc;
+ size_t ringsz;
int i, num_descriptors;
int error;
uint8_t xfercap;
@@ -452,7 +452,6 @@ ioat3_attach(device_t device)
mtx_init(&ioat->submit_lock, "ioat_submit", NULL, MTX_DEF);
mtx_init(&ioat->cleanup_lock, "ioat_cleanup", NULL, MTX_DEF);
callout_init(&ioat->poll_timer, 1);
- callout_init(&ioat->shrink_timer, 1);
TASK_INIT(&ioat->reset_task, 0, ioat_reset_hw_task, ioat);
/* Establish lock order for Witness */
@@ -461,7 +460,7 @@ ioat3_attach(device_t device)
mtx_unlock(&ioat->cleanup_lock);
mtx_unlock(&ioat->submit_lock);
- ioat->is_resize_pending = FALSE;
+ ioat->is_submitter_processing = FALSE;
ioat->is_completion_pending = FALSE;
ioat->is_reset_pending = FALSE;
ioat->is_channel_running = FALSE;
@@ -482,37 +481,43 @@ ioat3_attach(device_t device)
if (error != 0)
return (error);
- ioat->ring_size_order = IOAT_MIN_ORDER;
-
+ ioat->ring_size_order = g_ioat_ring_order;
num_descriptors = 1 << ioat->ring_size_order;
+ ringsz = sizeof(struct ioat_dma_hw_descriptor) * num_descriptors;
- bus_dma_tag_create(bus_get_dma_tag(ioat->device), 0x40, 0x0,
- BUS_SPACE_MAXADDR_40BIT, BUS_SPACE_MAXADDR, NULL, NULL,
- sizeof(struct ioat_dma_hw_descriptor), 1,
- sizeof(struct ioat_dma_hw_descriptor), 0, NULL, NULL,
+ error = bus_dma_tag_create(bus_get_dma_tag(ioat->device),
+ 2 * 1024 * 1024, 0x0, (bus_addr_t)BUS_SPACE_MAXADDR_40BIT,
+ BUS_SPACE_MAXADDR, NULL, NULL, ringsz, 1, ringsz, 0, NULL, NULL,
&ioat->hw_desc_tag);
+ if (error != 0)
+ return (error);
+ error = bus_dmamem_alloc(ioat->hw_desc_tag, &hw_desc,
+ BUS_DMA_ZERO | BUS_DMA_WAITOK, &ioat->hw_desc_map);
+ if (error != 0)
+ return (error);
+
+ error = bus_dmamap_load(ioat->hw_desc_tag, ioat->hw_desc_map, hw_desc,
+ ringsz, ioat_dmamap_cb, &ioat->hw_desc_bus_addr, BUS_DMA_WAITOK);
+ if (error)
+ return (error);
+
+ ioat->hw_desc_ring = hw_desc;
+
ioat->ring = malloc(num_descriptors * sizeof(*ring), M_IOAT,
M_ZERO | M_WAITOK);
ring = ioat->ring;
for (i = 0; i < num_descriptors; i++) {
- ring[i] = ioat_alloc_ring_entry(ioat, M_WAITOK);
- if (ring[i] == NULL)
- return (ENOMEM);
-
- ring[i]->id = i;
+ memset(&ring[i].bus_dmadesc, 0, sizeof(ring[i].bus_dmadesc));
+ ring[i].id = i;
}
- for (i = 0; i < num_descriptors - 1; i++) {
- next = ring[i + 1];
- dma_hw_desc = ring[i]->u.dma;
-
- dma_hw_desc->next = next->hw_desc_bus_addr;
+ for (i = 0; i < num_descriptors; i++) {
+ dma_hw_desc = &ioat->hw_desc_ring[i].dma;
+ dma_hw_desc->next = RING_PHYS_ADDR(ioat, i + 1);
}
- ring[i]->u.dma->next = ring[0]->hw_desc_bus_addr;
-
ioat->head = ioat->hw_head = 0;
ioat->tail = 0;
ioat->last_seen = 0;
@@ -662,8 +667,6 @@ ioat_process_events(struct ioat_softc *ioat)
boolean_t pending;
int error;
- CTR0(KTR_IOAT, __func__);
-
mtx_lock(&ioat->cleanup_lock);
/*
@@ -680,31 +683,42 @@ ioat_process_events(struct ioat_softc *ioat)
comp_update = *ioat->comp_update;
status = comp_update & IOAT_CHANSTS_COMPLETED_DESCRIPTOR_MASK;
+ if (status < ioat->hw_desc_bus_addr ||
+ status >= ioat->hw_desc_bus_addr + (1 << ioat->ring_size_order) *
+ sizeof(struct ioat_generic_hw_descriptor))
+ panic("Bogus completion address %jx (channel %u)",
+ (uintmax_t)status, ioat->chan_idx);
+
if (status == ioat->last_seen) {
/*
* If we landed in process_events and nothing has been
* completed, check for a timeout due to channel halt.
*/
- comp_update = ioat_get_chansts(ioat);
goto out;
}
+ CTR4(KTR_IOAT, "%s channel=%u hw_status=0x%lx last_seen=0x%lx",
+ __func__, ioat->chan_idx, comp_update, ioat->last_seen);
- while (1) {
+ while (RING_PHYS_ADDR(ioat, ioat->tail - 1) != status) {
desc = ioat_get_ring_entry(ioat, ioat->tail);
dmadesc = &desc->bus_dmadesc;
- CTR1(KTR_IOAT, "completing desc %d", ioat->tail);
+ CTR5(KTR_IOAT, "channel=%u completing desc idx %u (%p) ok cb %p(%p)",
+ ioat->chan_idx, ioat->tail, dmadesc, dmadesc->callback_fn,
+ dmadesc->callback_arg);
if (dmadesc->callback_fn != NULL)
dmadesc->callback_fn(dmadesc->callback_arg, 0);
completed++;
ioat->tail++;
- if (desc->hw_desc_bus_addr == status)
- break;
}
+ CTR5(KTR_IOAT, "%s channel=%u head=%u tail=%u active=%u", __func__,
+ ioat->chan_idx, ioat->head, ioat->tail, ioat_get_active(ioat));
- ioat->last_seen = desc->hw_desc_bus_addr;
- ioat->stats.descriptors_processed += completed;
+ if (completed != 0) {
+ ioat->last_seen = RING_PHYS_ADDR(ioat, ioat->tail - 1);
+ ioat->stats.descriptors_processed += completed;
+ }
out:
ioat_write_chanctrl(ioat, IOAT_CHANCTRL_RUN);
@@ -719,8 +733,6 @@ out:
pending = (ioat_get_active(ioat) != 0);
if (!pending && ioat->is_completion_pending) {
ioat->is_completion_pending = FALSE;
- callout_reset(&ioat->shrink_timer, IOAT_SHRINK_PERIOD,
- ioat_shrink_timer_callback, ioat);
callout_stop(&ioat->poll_timer);
}
mtx_unlock(&ioat->submit_lock);
@@ -736,6 +748,12 @@ out:
wakeup(&ioat->tail);
}
+ /*
+ * The device doesn't seem to reliably push suspend/halt statuses to
+ * the channel completion memory address, so poll the device register
+ * here.
+ */
+ comp_update = ioat_get_chansts(ioat) & IOAT_CHANSTS_STATUS;
if (!is_ioat_halted(comp_update) && !is_ioat_suspended(comp_update))
return;
@@ -745,19 +763,30 @@ out:
* Fatal programming error on this DMA channel. Flush any outstanding
* work with error status and restart the engine.
*/
- ioat_log_message(0, "Channel halted due to fatal programming error\n");
mtx_lock(&ioat->submit_lock);
mtx_lock(&ioat->cleanup_lock);
ioat->quiescing = TRUE;
+ /*
+ * This is safe to do here because we have both locks and the submit
+ * queue is quiesced. We know that we will drain all outstanding
+ * events, so ioat_reset_hw can't deadlock. It is necessary to
+ * protect other ioat_process_event threads from racing ioat_reset_hw,
+ * reading an indeterminate hw state, and attempting to continue
+ * issuing completions.
+ */
+ ioat->resetting_cleanup = TRUE;
chanerr = ioat_read_4(ioat, IOAT_CHANERR_OFFSET);
- ioat_halted_debug(ioat, chanerr);
+ if (1 <= g_ioat_debug_level)
+ ioat_halted_debug(ioat, chanerr);
ioat->stats.last_halt_chanerr = chanerr;
while (ioat_get_active(ioat) > 0) {
desc = ioat_get_ring_entry(ioat, ioat->tail);
dmadesc = &desc->bus_dmadesc;
- CTR1(KTR_IOAT, "completing err desc %d", ioat->tail);
+ CTR5(KTR_IOAT, "channel=%u completing desc idx %u (%p) err cb %p(%p)",
+ ioat->chan_idx, ioat->tail, dmadesc, dmadesc->callback_fn,
+ dmadesc->callback_arg);
if (dmadesc->callback_fn != NULL)
dmadesc->callback_fn(dmadesc->callback_arg,
@@ -768,7 +797,14 @@ out:
ioat->stats.descriptors_processed++;
ioat->stats.descriptors_error++;
}
+ CTR5(KTR_IOAT, "%s channel=%u head=%u tail=%u active=%u", __func__,
+ ioat->chan_idx, ioat->head, ioat->tail, ioat_get_active(ioat));
+ if (ioat->is_completion_pending) {
+ ioat->is_completion_pending = FALSE;
+ callout_stop(&ioat->poll_timer);
+ }
+
/* Clear error status */
ioat_write_4(ioat, IOAT_CHANERR_OFFSET, chanerr);
@@ -869,6 +905,15 @@ ioat_get_max_io_size(bus_dmaengine_t dmaengine)
return (ioat->max_xfer_size);
}
+uint32_t
+ioat_get_capabilities(bus_dmaengine_t dmaengine)
+{
+ struct ioat_softc *ioat;
+
+ ioat = to_ioat_softc(dmaengine);
+ return (ioat->capabilities);
+}
+
int
ioat_set_interrupt_coalesce(bus_dmaengine_t dmaengine, uint16_t delay)
{
@@ -902,7 +947,8 @@ ioat_acquire(bus_dmaengine_t dmaengine)
ioat = to_ioat_softc(dmaengine);
mtx_lock(&ioat->submit_lock);
- CTR0(KTR_IOAT, __func__);
+ CTR2(KTR_IOAT, "%s channel=%u", __func__, ioat->chan_idx);
+ ioat->acq_head = ioat->head;
}
int
@@ -926,8 +972,22 @@ ioat_release(bus_dmaengine_t dmaengine)
struct ioat_softc *ioat;
ioat = to_ioat_softc(dmaengine);
- CTR0(KTR_IOAT, __func__);
- ioat_write_2(ioat, IOAT_DMACOUNT_OFFSET, (uint16_t)ioat->hw_head);
+ CTR4(KTR_IOAT, "%s channel=%u dispatch1 hw_head=%u head=%u", __func__,
+ ioat->chan_idx, ioat->hw_head & UINT16_MAX, ioat->head);
+ KFAIL_POINT_CODE(DEBUG_FP, ioat_release, /* do nothing */);
+ CTR4(KTR_IOAT, "%s channel=%u dispatch2 hw_head=%u head=%u", __func__,
+ ioat->chan_idx, ioat->hw_head & UINT16_MAX, ioat->head);
+
+ if (ioat->acq_head != ioat->head) {
+ ioat_write_2(ioat, IOAT_DMACOUNT_OFFSET,
+ (uint16_t)ioat->hw_head);
+
+ if (!ioat->is_completion_pending) {
+ ioat->is_completion_pending = TRUE;
+ callout_reset(&ioat->poll_timer, 1,
+ ioat_poll_timer_callback, ioat);
+ }
+ }
mtx_unlock(&ioat->submit_lock);
}
@@ -960,7 +1020,7 @@ ioat_op_generic(struct ioat_softc *ioat, uint8_t op,
return (NULL);
desc = ioat_get_ring_entry(ioat, ioat->head);
- hw_desc = desc->u.generic;
+ hw_desc = &ioat_get_descriptor(ioat, ioat->head)->generic;
hw_desc->u.control_raw = 0;
hw_desc->u.control_generic.op = op;
@@ -988,15 +1048,15 @@ ioat_null(bus_dmaengine_t dmaengine, bus_dmaengine_cal
struct ioat_descriptor *desc;
struct ioat_softc *ioat;
- CTR0(KTR_IOAT, __func__);
ioat = to_ioat_softc(dmaengine);
+ CTR2(KTR_IOAT, "%s channel=%u", __func__, ioat->chan_idx);
desc = ioat_op_generic(ioat, IOAT_OP_COPY, 8, 0, 0, callback_fn,
callback_arg, flags);
if (desc == NULL)
return (NULL);
- hw_desc = desc->u.dma;
+ hw_desc = &ioat_get_descriptor(ioat, desc->id)->dma;
hw_desc->u.control.null = 1;
ioat_submit_single(ioat);
return (&desc->bus_dmadesc);
@@ -1011,7 +1071,6 @@ ioat_copy(bus_dmaengine_t dmaengine, bus_addr_t dst,
struct ioat_descriptor *desc;
struct ioat_softc *ioat;
- CTR0(KTR_IOAT, __func__);
ioat = to_ioat_softc(dmaengine);
if (((src | dst) & (0xffffull << 48)) != 0) {
@@ -1025,11 +1084,13 @@ ioat_copy(bus_dmaengine_t dmaengine, bus_addr_t dst,
if (desc == NULL)
return (NULL);
- hw_desc = desc->u.dma;
+ hw_desc = &ioat_get_descriptor(ioat, desc->id)->dma;
if (g_ioat_debug_level >= 3)
dump_descriptor(hw_desc);
ioat_submit_single(ioat);
+ CTR6(KTR_IOAT, "%s channel=%u desc=%p dest=%lx src=%lx len=%lx",
+ __func__, ioat->chan_idx, &desc->bus_dmadesc, dst, src, len);
return (&desc->bus_dmadesc);
}
@@ -1042,8 +1103,8 @@ ioat_copy_8k_aligned(bus_dmaengine_t dmaengine, bus_ad
struct ioat_descriptor *desc;
struct ioat_softc *ioat;
- CTR0(KTR_IOAT, __func__);
ioat = to_ioat_softc(dmaengine);
+ CTR2(KTR_IOAT, "%s channel=%u", __func__, ioat->chan_idx);
if (((src1 | src2 | dst1 | dst2) & (0xffffull << 48)) != 0) {
ioat_log_message(0, "%s: High 16 bits of src/dst invalid\n",
@@ -1061,7 +1122,7 @@ ioat_copy_8k_aligned(bus_dmaengine_t dmaengine, bus_ad
if (desc == NULL)
return (NULL);
- hw_desc = desc->u.dma;
+ hw_desc = &ioat_get_descriptor(ioat, desc->id)->dma;
if (src2 != src1 + PAGE_SIZE) {
hw_desc->u.control.src_page_break = 1;
hw_desc->next_src_addr = src2;
@@ -1089,8 +1150,8 @@ ioat_copy_crc(bus_dmaengine_t dmaengine, bus_addr_t ds
uint32_t teststore;
uint8_t op;
- CTR0(KTR_IOAT, __func__);
ioat = to_ioat_softc(dmaengine);
+ CTR2(KTR_IOAT, "%s channel=%u", __func__, ioat->chan_idx);
if ((ioat->capabilities & IOAT_DMACAP_MOVECRC) == 0) {
ioat_log_message(0, "%s: Device lacks MOVECRC capability\n",
@@ -1138,7 +1199,7 @@ ioat_copy_crc(bus_dmaengine_t dmaengine, bus_addr_t ds
if (desc == NULL)
return (NULL);
- hw_desc = desc->u.crc32;
+ hw_desc = &ioat_get_descriptor(ioat, desc->id)->crc32;
if ((flags & DMA_CRC_INLINE) == 0)
hw_desc->crc_address = crcptr;
@@ -1168,8 +1229,8 @@ ioat_crc(bus_dmaengine_t dmaengine, bus_addr_t src, bu
uint32_t teststore;
uint8_t op;
- CTR0(KTR_IOAT, __func__);
ioat = to_ioat_softc(dmaengine);
+ CTR2(KTR_IOAT, "%s channel=%u", __func__, ioat->chan_idx);
if ((ioat->capabilities & IOAT_DMACAP_CRC) == 0) {
ioat_log_message(0, "%s: Device lacks CRC capability\n",
@@ -1217,7 +1278,7 @@ ioat_crc(bus_dmaengine_t dmaengine, bus_addr_t src, bu
if (desc == NULL)
return (NULL);
- hw_desc = desc->u.crc32;
+ hw_desc = &ioat_get_descriptor(ioat, desc->id)->crc32;
if ((flags & DMA_CRC_INLINE) == 0)
hw_desc->crc_address = crcptr;
@@ -1245,8 +1306,8 @@ ioat_blockfill(bus_dmaengine_t dmaengine, bus_addr_t d
struct ioat_descriptor *desc;
struct ioat_softc *ioat;
- CTR0(KTR_IOAT, __func__);
ioat = to_ioat_softc(dmaengine);
+ CTR2(KTR_IOAT, "%s channel=%u", __func__, ioat->chan_idx);
if ((ioat->capabilities & IOAT_DMACAP_BFILL) == 0) {
ioat_log_message(0, "%s: Device lacks BFILL capability\n",
@@ -1265,7 +1326,7 @@ ioat_blockfill(bus_dmaengine_t dmaengine, bus_addr_t d
if (desc == NULL)
return (NULL);
- hw_desc = desc->u.fill;
+ hw_desc = &ioat_get_descriptor(ioat, desc->id)->fill;
if (g_ioat_debug_level >= 3)
dump_descriptor(hw_desc);
@@ -1290,60 +1351,6 @@ ioat_get_ring_space(struct ioat_softc *ioat)
return ((1 << ioat->ring_size_order) - ioat_get_active(ioat) - 1);
}
-static struct ioat_descriptor *
-ioat_alloc_ring_entry(struct ioat_softc *ioat, int mflags)
-{
- struct ioat_generic_hw_descriptor *hw_desc;
- struct ioat_descriptor *desc;
- int error, busdmaflag;
-
- error = ENOMEM;
- hw_desc = NULL;
-
- if ((mflags & M_WAITOK) != 0)
- busdmaflag = BUS_DMA_WAITOK;
- else
- busdmaflag = BUS_DMA_NOWAIT;
-
- desc = malloc(sizeof(*desc), M_IOAT, mflags);
- if (desc == NULL)
- goto out;
-
- bus_dmamem_alloc(ioat->hw_desc_tag, (void **)&hw_desc,
- BUS_DMA_ZERO | busdmaflag, &ioat->hw_desc_map);
- if (hw_desc == NULL)
- goto out;
-
- memset(&desc->bus_dmadesc, 0, sizeof(desc->bus_dmadesc));
- desc->u.generic = hw_desc;
-
- error = bus_dmamap_load(ioat->hw_desc_tag, ioat->hw_desc_map, hw_desc,
- sizeof(*hw_desc), ioat_dmamap_cb, &desc->hw_desc_bus_addr,
- busdmaflag);
- if (error)
- goto out;
-
-out:
- if (error) {
- ioat_free_ring_entry(ioat, desc);
- return (NULL);
- }
- return (desc);
-}
-
-static void
-ioat_free_ring_entry(struct ioat_softc *ioat, struct ioat_descriptor *desc)
-{
-
- if (desc == NULL)
- return;
-
- if (desc->u.generic)
- bus_dmamem_free(ioat->hw_desc_tag, desc->u.generic,
- ioat->hw_desc_map);
- free(desc, M_IOAT);
-}
-
/*
* Reserves space in this IOAT descriptor ring by ensuring enough slots remain
* for 'num_descs'.
@@ -1363,114 +1370,70 @@ ioat_free_ring_entry(struct ioat_softc *ioat, struct i
static int
ioat_reserve_space(struct ioat_softc *ioat, uint32_t num_descs, int mflags)
{
- struct ioat_descriptor **new_ring;
- uint32_t order;
+ boolean_t dug;
int error;
mtx_assert(&ioat->submit_lock, MA_OWNED);
error = 0;
+ dug = FALSE;
- if (num_descs < 1 || num_descs > (1 << IOAT_MAX_ORDER)) {
+ if (num_descs < 1 || num_descs >= (1 << ioat->ring_size_order)) {
error = EINVAL;
goto out;
}
- if (ioat->quiescing) {
- error = ENXIO;
- goto out;
- }
for (;;) {
+ if (ioat->quiescing) {
+ error = ENXIO;
+ goto out;
+ }
+
if (ioat_get_ring_space(ioat) >= num_descs)
goto out;
- order = ioat->ring_size_order;
- if (ioat->is_resize_pending || order == IOAT_MAX_ORDER) {
- if ((mflags & M_WAITOK) != 0) {
- msleep(&ioat->tail, &ioat->submit_lock, 0,
- "ioat_rsz", 0);
- continue;
- }
+ CTR3(KTR_IOAT, "%s channel=%u starved (%u)", __func__,
+ ioat->chan_idx, num_descs);
- error = EAGAIN;
- break;
- }
-
- ioat->is_resize_pending = TRUE;
- for (;;) {
+ if (!dug && !ioat->is_submitter_processing) {
+ ioat->is_submitter_processing = TRUE;
mtx_unlock(&ioat->submit_lock);
- new_ring = ioat_prealloc_ring(ioat, 1 << (order + 1),
- TRUE, mflags);
+ CTR2(KTR_IOAT, "%s channel=%u attempting to process events",
+ __func__, ioat->chan_idx);
+ ioat_process_events(ioat);
mtx_lock(&ioat->submit_lock);
- KASSERT(ioat->ring_size_order == order,
- ("is_resize_pending should protect order"));
-
- if (new_ring == NULL) {
- KASSERT((mflags & M_WAITOK) == 0,
- ("allocation failed"));
- error = EAGAIN;
- break;
- }
-
- error = ring_grow(ioat, order, new_ring);
- if (error == 0)
- break;
+ dug = TRUE;
+ KASSERT(ioat->is_submitter_processing == TRUE,
+ ("is_submitter_processing"));
+ ioat->is_submitter_processing = FALSE;
+ wakeup(&ioat->tail);
+ continue;
}
- ioat->is_resize_pending = FALSE;
- wakeup(&ioat->tail);
- if (error)
+
+ if ((mflags & M_WAITOK) == 0) {
+ error = EAGAIN;
break;
+ }
+ CTR2(KTR_IOAT, "%s channel=%u blocking on completions",
+ __func__, ioat->chan_idx);
+ msleep(&ioat->tail, &ioat->submit_lock, 0,
+ "ioat_full", 0);
+ continue;
}
out:
mtx_assert(&ioat->submit_lock, MA_OWNED);
+ KASSERT(!ioat->quiescing || error == ENXIO,
+ ("reserved during quiesce"));
return (error);
}
-static struct ioat_descriptor **
-ioat_prealloc_ring(struct ioat_softc *ioat, uint32_t size, boolean_t need_dscr,
- int mflags)
-{
- struct ioat_descriptor **ring;
- uint32_t i;
- int error;
-
- KASSERT(size > 0 && powerof2(size), ("bogus size"));
-
- ring = malloc(size * sizeof(*ring), M_IOAT, M_ZERO | mflags);
- if (ring == NULL)
- return (NULL);
-
- if (need_dscr) {
- error = ENOMEM;
- for (i = size / 2; i < size; i++) {
- ring[i] = ioat_alloc_ring_entry(ioat, mflags);
- if (ring[i] == NULL)
- goto out;
- ring[i]->id = i;
- }
- }
- error = 0;
-
-out:
- if (error != 0 && ring != NULL) {
- ioat_free_ring(ioat, size, ring);
- ring = NULL;
- }
- return (ring);
-}
-
static void
ioat_free_ring(struct ioat_softc *ioat, uint32_t size,
- struct ioat_descriptor **ring)
+ struct ioat_descriptor *ring)
{
- uint32_t i;
- for (i = 0; i < size; i++) {
- if (ring[i] != NULL)
- ioat_free_ring_entry(ioat, ring[i]);
- }
free(ring, M_IOAT);
}
@@ -1478,164 +1441,20 @@ static struct ioat_descriptor *
ioat_get_ring_entry(struct ioat_softc *ioat, uint32_t index)
{
- return (ioat->ring[index % (1 << ioat->ring_size_order)]);
+ return (&ioat->ring[index % (1 << ioat->ring_size_order)]);
}
-static int
-ring_grow(struct ioat_softc *ioat, uint32_t oldorder,
- struct ioat_descriptor **newring)
+static union ioat_hw_descriptor *
+ioat_get_descriptor(struct ioat_softc *ioat, uint32_t index)
{
- struct ioat_descriptor *tmp, *next;
- struct ioat_dma_hw_descriptor *hw;
- uint32_t oldsize, newsize, head, tail, i, end;
- int error;
- CTR0(KTR_IOAT, __func__);
-
- mtx_assert(&ioat->submit_lock, MA_OWNED);
-
- if (oldorder != ioat->ring_size_order || oldorder >= IOAT_MAX_ORDER) {
- error = EINVAL;
- goto out;
- }
-
- oldsize = (1 << oldorder);
- newsize = (1 << (oldorder + 1));
-
- mtx_lock(&ioat->cleanup_lock);
-
- head = ioat->head & (oldsize - 1);
- tail = ioat->tail & (oldsize - 1);
-
- /* Copy old descriptors to new ring */
- for (i = 0; i < oldsize; i++)
- newring[i] = ioat->ring[i];
-
- /*
- * If head has wrapped but tail hasn't, we must swap some descriptors
- * around so that tail can increment directly to head.
- */
- if (head < tail) {
- for (i = 0; i <= head; i++) {
- tmp = newring[oldsize + i];
-
- newring[oldsize + i] = newring[i];
- newring[oldsize + i]->id = oldsize + i;
-
- newring[i] = tmp;
- newring[i]->id = i;
- }
- head += oldsize;
- }
-
- KASSERT(head >= tail, ("invariants"));
-
- /* Head didn't wrap; we only need to link in oldsize..newsize */
- if (head < oldsize) {
- i = oldsize - 1;
- end = newsize;
- } else {
- /* Head did wrap; link newhead..newsize and 0..oldhead */
- i = head;
- end = newsize + (head - oldsize) + 1;
- }
-
- /*
- * Fix up hardware ring, being careful not to trample the active
- * section (tail -> head).
- */
- for (; i < end; i++) {
- KASSERT((i & (newsize - 1)) < tail ||
- (i & (newsize - 1)) >= head, ("trampling snake"));
-
- next = newring[(i + 1) & (newsize - 1)];
- hw = newring[i & (newsize - 1)]->u.dma;
- hw->next = next->hw_desc_bus_addr;
- }
-
- free(ioat->ring, M_IOAT);
- ioat->ring = newring;
- ioat->ring_size_order = oldorder + 1;
- ioat->tail = tail;
- ioat->head = head;
- error = 0;
-
- mtx_unlock(&ioat->cleanup_lock);
-out:
- if (error)
- ioat_free_ring(ioat, (1 << (oldorder + 1)), newring);
- return (error);
+ return (&ioat->hw_desc_ring[index % (1 << ioat->ring_size_order)]);
}
-static int
-ring_shrink(struct ioat_softc *ioat, uint32_t oldorder,
- struct ioat_descriptor **newring)
-{
- struct ioat_dma_hw_descriptor *hw;
- struct ioat_descriptor *ent, *next;
- uint32_t oldsize, newsize, current_idx, new_idx, i;
- int error;
-
- CTR0(KTR_IOAT, __func__);
-
- mtx_assert(&ioat->submit_lock, MA_OWNED);
-
- if (oldorder != ioat->ring_size_order || oldorder <= IOAT_MIN_ORDER) {
- error = EINVAL;
- goto out_unlocked;
- }
-
- oldsize = (1 << oldorder);
- newsize = (1 << (oldorder - 1));
-
- mtx_lock(&ioat->cleanup_lock);
-
- /* Can't shrink below current active set! */
- if (ioat_get_active(ioat) >= newsize) {
- error = ENOMEM;
- goto out;
- }
-
- /*
- * Copy current descriptors to the new ring, dropping the removed
- * descriptors.
- */
- for (i = 0; i < newsize; i++) {
- current_idx = (ioat->tail + i) & (oldsize - 1);
- new_idx = (ioat->tail + i) & (newsize - 1);
-
- newring[new_idx] = ioat->ring[current_idx];
- newring[new_idx]->id = new_idx;
- }
-
- /* Free deleted descriptors */
- for (i = newsize; i < oldsize; i++) {
- ent = ioat_get_ring_entry(ioat, ioat->tail + i);
- ioat_free_ring_entry(ioat, ent);
- }
-
- /* Fix up hardware ring. */
- hw = newring[(ioat->tail + newsize - 1) & (newsize - 1)]->u.dma;
- next = newring[(ioat->tail + newsize) & (newsize - 1)];
- hw->next = next->hw_desc_bus_addr;
-
- free(ioat->ring, M_IOAT);
- ioat->ring = newring;
- ioat->ring_size_order = oldorder - 1;
- error = 0;
-
-out:
- mtx_unlock(&ioat->cleanup_lock);
-out_unlocked:
- if (error)
- ioat_free_ring(ioat, (1 << (oldorder - 1)), newring);
- return (error);
-}
-
static void
ioat_halted_debug(struct ioat_softc *ioat, uint32_t chanerr)
{
- struct ioat_descriptor *desc;
+ union ioat_hw_descriptor *desc;
ioat_log_message(0, "Channel halted (%b)\n", (int)chanerr,
IOAT_CHANERR_STR);
@@ -1644,11 +1463,11 @@ ioat_halted_debug(struct ioat_softc *ioat, uint32_t ch
mtx_assert(&ioat->cleanup_lock, MA_OWNED);
- desc = ioat_get_ring_entry(ioat, ioat->tail + 0);
- dump_descriptor(desc->u.raw);
+ desc = ioat_get_descriptor(ioat, ioat->tail + 0);
+ dump_descriptor(desc);
- desc = ioat_get_ring_entry(ioat, ioat->tail + 1);
- dump_descriptor(desc->u.raw);
+ desc = ioat_get_descriptor(ioat, ioat->tail + 1);
+ dump_descriptor(desc);
}
static void
@@ -1662,52 +1481,6 @@ ioat_poll_timer_callback(void *arg)
ioat_process_events(ioat);
}
-static void
-ioat_shrink_timer_callback(void *arg)
-{
- struct ioat_descriptor **newring;
- struct ioat_softc *ioat;
- uint32_t order;
-
- ioat = arg;
- ioat_log_message(1, "%s\n", __func__);
-
- /* Slowly scale the ring down if idle. */
- mtx_lock(&ioat->submit_lock);
-
- /* Don't run while the hardware is being reset. */
- if (ioat->resetting) {
- mtx_unlock(&ioat->submit_lock);
- return;
- }
-
- order = ioat->ring_size_order;
- if (ioat->is_resize_pending || order == IOAT_MIN_ORDER) {
- mtx_unlock(&ioat->submit_lock);
- goto out;
- }
- ioat->is_resize_pending = TRUE;
- mtx_unlock(&ioat->submit_lock);
-
- newring = ioat_prealloc_ring(ioat, 1 << (order - 1), FALSE,
- M_NOWAIT);
-
- mtx_lock(&ioat->submit_lock);
- KASSERT(ioat->ring_size_order == order,
- ("resize_pending protects order"));
-
- if (newring != NULL)
- ring_shrink(ioat, order, newring);
-
- ioat->is_resize_pending = FALSE;
- mtx_unlock(&ioat->submit_lock);
-
-out:
- if (ioat->ring_size_order > IOAT_MIN_ORDER)
- callout_reset(&ioat->poll_timer, IOAT_SHRINK_PERIOD,
- ioat_shrink_timer_callback, ioat);
-}
-
/*
* Support Functions
*/
@@ -1715,17 +1488,15 @@ static void
ioat_submit_single(struct ioat_softc *ioat)
{
+ mtx_assert(&ioat->submit_lock, MA_OWNED);
+
ioat_get(ioat, IOAT_ACTIVE_DESCR_REF);
atomic_add_rel_int(&ioat->head, 1);
atomic_add_rel_int(&ioat->hw_head, 1);
+ CTR5(KTR_IOAT, "%s channel=%u head=%u hw_head=%u tail=%u", __func__,
+ ioat->chan_idx, ioat->head, ioat->hw_head & UINT16_MAX,
+ ioat->tail);
- if (!ioat->is_completion_pending) {
- ioat->is_completion_pending = TRUE;
- callout_reset(&ioat->poll_timer, 1, ioat_poll_timer_callback,
- ioat);
- callout_stop(&ioat->shrink_timer);
- }
-
ioat->stats.descriptors_submitted++;
}
@@ -1737,6 +1508,8 @@ ioat_reset_hw(struct ioat_softc *ioat)
unsigned timeout;
int error;
+ CTR2(KTR_IOAT, "%s channel=%u", __func__, ioat->chan_idx);
+
mtx_lock(IOAT_REFLK);
while (ioat->resetting && !ioat->destroying)
msleep(&ioat->resetting, IOAT_REFLK, 0, "IRH_drain", 0);
@@ -1758,6 +1531,9 @@ ioat_reset_hw(struct ioat_softc *ioat)
ioat->resetting_cleanup = TRUE;
mtx_unlock(&ioat->cleanup_lock);
+ CTR2(KTR_IOAT, "%s channel=%u quiesced and drained", __func__,
+ ioat->chan_idx);
+
status = ioat_get_chansts(ioat);
if (is_ioat_active(status) || is_ioat_idle(status))
ioat_suspend(ioat);
@@ -1778,6 +1554,9 @@ ioat_reset_hw(struct ioat_softc *ioat)
chanerr = ioat_read_4(ioat, IOAT_CHANERR_OFFSET);
ioat_write_4(ioat, IOAT_CHANERR_OFFSET, chanerr);
+ CTR2(KTR_IOAT, "%s channel=%u hardware suspended", __func__,
+ ioat->chan_idx);
+
/*
* IOAT v3 workaround - CHANERRMSK_INT with 3E07h to masks out errors
* that can cause stability issues for IOAT v3.
@@ -1797,6 +1576,8 @@ ioat_reset_hw(struct ioat_softc *ioat)
}
ioat_reset(ioat);
+ CTR2(KTR_IOAT, "%s channel=%u hardware reset", __func__,
+ ioat->chan_idx);
/* Wait at most 20 ms */
for (timeout = 0; ioat_reset_pending(ioat) && timeout < 20; timeout++)
@@ -1840,26 +1621,30 @@ ioat_reset_hw(struct ioat_softc *ioat)
ioat->tail = ioat->head = ioat->hw_head = 0;
ioat->last_seen = 0;
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-stable-11
mailing list