summaryrefslogtreecommitdiffstats
path: root/sys/dev/cxgbe/t4_main.c
diff options
context:
space:
mode:
authorgrehan <grehan@FreeBSD.org>2011-06-28 06:26:03 +0000
committergrehan <grehan@FreeBSD.org>2011-06-28 06:26:03 +0000
commit2c6741be0f59191f2283eb268e4f7690399d578a (patch)
treeb139c8c6dcca4fa284815daade405b75886ee360 /sys/dev/cxgbe/t4_main.c
parent3c35264f695e0a1f8a04dbcca1c93bb5159b2274 (diff)
parent19ae02bba572390c7299166228d31e54003e094a (diff)
downloadFreeBSD-src-2c6741be0f59191f2283eb268e4f7690399d578a.zip
FreeBSD-src-2c6741be0f59191f2283eb268e4f7690399d578a.tar.gz
IFC @ r222830
Diffstat (limited to 'sys/dev/cxgbe/t4_main.c')
-rw-r--r--sys/dev/cxgbe/t4_main.c380
1 files changed, 309 insertions, 71 deletions
diff --git a/sys/dev/cxgbe/t4_main.c b/sys/dev/cxgbe/t4_main.c
index 469af8d..18b813d 100644
--- a/sys/dev/cxgbe/t4_main.c
+++ b/sys/dev/cxgbe/t4_main.c
@@ -62,6 +62,7 @@ __FBSDID("$FreeBSD$");
#include "common/t4_regs_values.h"
#include "common/t4fw_interface.h"
#include "t4_ioctl.h"
+#include "t4_l2t.h"
/* T4 bus driver interface */
static int t4_probe(device_t);
@@ -213,12 +214,12 @@ SYSCTL_UINT(_hw_cxgbe, OID_AUTO, interrupt_types, CTLFLAG_RDTUN, &intr_types, 0,
"interrupt types allowed (bits 0, 1, 2 = INTx, MSI, MSI-X respectively)");
/*
- * Force the driver to use interrupt forwarding.
+ * Force the driver to use the same set of interrupts for all ports.
*/
-static int intr_fwd = 0;
-TUNABLE_INT("hw.cxgbe.interrupt_forwarding", &intr_fwd);
-SYSCTL_UINT(_hw_cxgbe, OID_AUTO, interrupt_forwarding, CTLFLAG_RDTUN,
- &intr_fwd, 0, "always use forwarded interrupts");
+static int intr_shared = 0;
+TUNABLE_INT("hw.cxgbe.interrupts_shared", &intr_shared);
+SYSCTL_UINT(_hw_cxgbe, OID_AUTO, interrupts_shared, CTLFLAG_RDTUN,
+ &intr_shared, 0, "interrupts shared between all ports");
static unsigned int filter_mode = HW_TPL_FR_MT_PR_IV_P_FC;
TUNABLE_INT("hw.cxgbe.filter_mode", &filter_mode);
@@ -228,7 +229,7 @@ SYSCTL_UINT(_hw_cxgbe, OID_AUTO, filter_mode, CTLFLAG_RDTUN,
struct intrs_and_queues {
int intr_type; /* INTx, MSI, or MSI-X */
int nirq; /* Number of vectors */
- int intr_fwd; /* Interrupts forwarded */
+ int intr_shared; /* Interrupts shared between all ports */
int ntxq10g; /* # of NIC txq's for each 10G port */
int nrxq10g; /* # of NIC rxq's for each 10G port */
int ntxq1g; /* # of NIC txq's for each 1G port */
@@ -240,6 +241,7 @@ struct filter_entry {
uint32_t locked:1; /* filter is administratively locked */
uint32_t pending:1; /* filter action is pending firmware reply */
uint32_t smtidx:8; /* Source MAC Table index for smac */
+ struct l2t_entry *l2t; /* Layer Two Table entry for dmac */
struct t4_filter_specification fs;
};
@@ -269,6 +271,7 @@ static void setup_memwin(struct adapter *);
static int cfg_itype_and_nqueues(struct adapter *, int, int,
struct intrs_and_queues *);
static int prep_firmware(struct adapter *);
+static int get_devlog_params(struct adapter *, struct devlog_params *);
static int get_capabilities(struct adapter *, struct fw_caps_config_cmd *);
static int get_params(struct adapter *, struct fw_caps_config_cmd *);
static void t4_set_desc(struct adapter *);
@@ -295,19 +298,22 @@ static int sysctl_holdoff_pktc_idx(SYSCTL_HANDLER_ARGS);
static int sysctl_qsize_rxq(SYSCTL_HANDLER_ARGS);
static int sysctl_qsize_txq(SYSCTL_HANDLER_ARGS);
static int sysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS);
+static int sysctl_devlog(SYSCTL_HANDLER_ARGS);
static inline void txq_start(struct ifnet *, struct sge_txq *);
static uint32_t fconf_to_mode(uint32_t);
static uint32_t mode_to_fconf(uint32_t);
static uint32_t fspec_to_fconf(struct t4_filter_specification *);
static int get_filter_mode(struct adapter *, uint32_t *);
static int set_filter_mode(struct adapter *, uint32_t);
+static inline uint64_t get_filter_hits(struct adapter *, uint32_t);
static int get_filter(struct adapter *, struct t4_filter *);
static int set_filter(struct adapter *, struct t4_filter *);
static int del_filter(struct adapter *, struct t4_filter *);
-static void clear_filter(struct adapter *, struct filter_entry *);
+static void clear_filter(struct filter_entry *);
static int set_filter_wr(struct adapter *, int);
static int del_filter_wr(struct adapter *, int);
void filter_rpl(struct adapter *, const struct cpl_set_tcb_rpl *);
+static int get_sge_context(struct adapter *, struct t4_sge_context *);
static int t4_mod_event(module_t, int, void *);
struct t4_pciids {
@@ -400,6 +406,9 @@ t4_attach(device_t dev)
if (rc != 0)
goto done; /* error message displayed already */
+ /* Read firmware devlog parameters */
+ (void) get_devlog_params(sc, &sc->params.devlog);
+
/* Get device capabilities and select which ones we'll use */
rc = get_capabilities(sc, &caps);
if (rc != 0) {
@@ -484,6 +493,8 @@ t4_attach(device_t dev)
V_RXTSHIFTMAXR2(15) | V_PERSHIFTBACKOFFMAX(8) | V_PERSHIFTMAX(8) |
V_KEEPALIVEMAXR1(4) | V_KEEPALIVEMAXR2(9));
t4_write_reg(sc, A_ULP_RX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12));
+ t4_set_reg_field(sc, A_TP_PARA_REG3, F_TUNNELCNGDROP0 |
+ F_TUNNELCNGDROP1 | F_TUNNELCNGDROP2 | F_TUNNELCNGDROP3, 0);
setup_memwin(sc);
@@ -514,8 +525,8 @@ t4_attach(device_t dev)
device_printf(dev, "unable to initialize port %d: %d\n",
i, rc);
free(pi, M_CXGBE);
- sc->port[i] = NULL; /* indicates init failed */
- continue;
+ sc->port[i] = NULL;
+ goto done;
}
snprintf(pi->lockname, sizeof(pi->lockname), "%sp%d",
@@ -582,15 +593,15 @@ t4_attach(device_t dev)
s->nrxq = n10g * iaq.nrxq10g + n1g * iaq.nrxq1g;
s->ntxq = n10g * iaq.ntxq10g + n1g * iaq.ntxq1g;
s->neq = s->ntxq + s->nrxq; /* the free list in an rxq is an eq */
- s->neq += NCHAN; /* control queues, 1 per hw channel */
+ s->neq += sc->params.nports; /* control queues, 1 per port */
s->niq = s->nrxq + 1; /* 1 extra for firmware event queue */
- if (iaq.intr_fwd) {
- sc->flags |= INTR_FWD;
- s->niq += NFIQ(sc); /* forwarded interrupt queues */
- s->fiq = malloc(NFIQ(sc) * sizeof(struct sge_iq), M_CXGBE,
- M_ZERO | M_WAITOK);
- }
- s->ctrlq = malloc(NCHAN * sizeof(struct sge_ctrlq), M_CXGBE,
+ if (iaq.intr_shared)
+ sc->flags |= INTR_SHARED;
+ s->niq += NINTRQ(sc); /* interrupt queues */
+
+ s->intrq = malloc(NINTRQ(sc) * sizeof(struct sge_iq), M_CXGBE,
+ M_ZERO | M_WAITOK);
+ s->ctrlq = malloc(sc->params.nports * sizeof(struct sge_ctrlq), M_CXGBE,
M_ZERO | M_WAITOK);
s->rxq = malloc(s->nrxq * sizeof(struct sge_rxq), M_CXGBE,
M_ZERO | M_WAITOK);
@@ -604,6 +615,8 @@ t4_attach(device_t dev)
sc->irq = malloc(sc->intr_count * sizeof(struct irq), M_CXGBE,
M_ZERO | M_WAITOK);
+ sc->l2t = t4_init_l2t(M_WAITOK);
+
t4_sysctls(sc);
/*
@@ -691,11 +704,14 @@ t4_detach(device_t dev)
bus_release_resource(dev, SYS_RES_MEMORY, sc->msix_rid,
sc->msix_res);
+ if (sc->l2t)
+ t4_free_l2t(sc->l2t);
+
free(sc->irq, M_CXGBE);
free(sc->sge.rxq, M_CXGBE);
free(sc->sge.txq, M_CXGBE);
free(sc->sge.ctrlq, M_CXGBE);
- free(sc->sge.fiq, M_CXGBE);
+ free(sc->sge.intrq, M_CXGBE);
free(sc->sge.iqmap, M_CXGBE);
free(sc->sge.eqmap, M_CXGBE);
free(sc->tids.ftid_tab, M_CXGBE);
@@ -1231,33 +1247,32 @@ cfg_itype_and_nqueues(struct adapter *sc, int n10g, int n1g,
nrxq10g = min(nc, max_nrxq_10g);
nrxq1g = min(nc, max_nrxq_1g);
- /* Extra 2 is for a) error interrupt b) firmware event */
- iaq->nirq = n10g * nrxq10g + n1g * nrxq1g + 2;
- if (iaq->nirq <= navail && intr_fwd == 0) {
+ iaq->nirq = n10g * nrxq10g + n1g * nrxq1g + T4_EXTRA_INTR;
+ if (iaq->nirq <= navail && intr_shared == 0) {
if (itype == INTR_MSI && !powerof2(iaq->nirq))
- goto fwd;
+ goto share;
/* One for err, one for fwq, and one for each rxq */
- iaq->intr_fwd = 0;
+ iaq->intr_shared = 0;
iaq->nrxq10g = nrxq10g;
iaq->nrxq1g = nrxq1g;
} else {
-fwd:
- iaq->intr_fwd = 1;
+share:
+ iaq->intr_shared = 1;
- if (navail > nc) {
+ if (navail >= nc + T4_EXTRA_INTR) {
if (itype == INTR_MSIX)
- navail = nc + 1;
+ navail = nc + T4_EXTRA_INTR;
/* navail is and must remain a pow2 for MSI */
if (itype == INTR_MSI) {
KASSERT(powerof2(navail),
("%d not power of 2", navail));
- while (navail / 2 > nc)
+ while (navail / 2 >= nc + T4_EXTRA_INTR)
navail /= 2;
}
}
@@ -1290,7 +1305,7 @@ fwd:
* the kernel is willing to allocate (it's in navail).
*/
pci_release_msi(sc->dev);
- goto fwd;
+ goto share;
}
device_printf(sc->dev,
@@ -1414,6 +1429,34 @@ prep_firmware(struct adapter *sc)
}
static int
+get_devlog_params(struct adapter *sc, struct devlog_params *dlog)
+{
+ struct fw_devlog_cmd devlog_cmd;
+ uint32_t meminfo;
+ int rc;
+
+ bzero(&devlog_cmd, sizeof(devlog_cmd));
+ devlog_cmd.op_to_write = htobe32(V_FW_CMD_OP(FW_DEVLOG_CMD) |
+ F_FW_CMD_REQUEST | F_FW_CMD_READ);
+ devlog_cmd.retval_len16 = htobe32(FW_LEN16(devlog_cmd));
+ rc = -t4_wr_mbox(sc, sc->mbox, &devlog_cmd, sizeof(devlog_cmd),
+ &devlog_cmd);
+ if (rc != 0) {
+ device_printf(sc->dev,
+ "failed to get devlog parameters: %d.\n", rc);
+ bzero(dlog, sizeof (*dlog));
+ return (rc);
+ }
+
+ meminfo = be32toh(devlog_cmd.memtype_devlog_memaddr16_devlog);
+ dlog->memtype = G_FW_DEVLOG_CMD_MEMTYPE_DEVLOG(meminfo);
+ dlog->start = G_FW_DEVLOG_CMD_MEMADDR16_DEVLOG(meminfo) << 4;
+ dlog->size = be32toh(devlog_cmd.memsize_devlog);
+
+ return (0);
+}
+
+static int
get_capabilities(struct adapter *sc, struct fw_caps_config_cmd *caps)
{
int rc;
@@ -1923,16 +1966,18 @@ cxgbe_uninit_synchronized(struct port_info *pi)
return (0);
}
-#define T4_ALLOC_IRQ(sc, irqid, rid, handler, arg, name) do { \
- rc = t4_alloc_irq(sc, &sc->irq[irqid], rid, handler, arg, name); \
+#define T4_ALLOC_IRQ(sc, irq, rid, handler, arg, name) do { \
+ rc = t4_alloc_irq(sc, irq, rid, handler, arg, name); \
if (rc != 0) \
goto done; \
} while (0)
static int
first_port_up(struct adapter *sc)
{
- int rc, i;
- char name[8];
+ int rc, i, rid, p, q;
+ char s[8];
+ struct irq *irq;
+ struct sge_iq *intrq;
ADAPTER_LOCK_ASSERT_NOTOWNED(sc);
@@ -1946,39 +1991,52 @@ first_port_up(struct adapter *sc)
/*
* Setup interrupts.
*/
+ irq = &sc->irq[0];
+ rid = sc->intr_type == INTR_INTX ? 0 : 1;
if (sc->intr_count == 1) {
- KASSERT(sc->flags & INTR_FWD,
- ("%s: single interrupt but not forwarded?", __func__));
- T4_ALLOC_IRQ(sc, 0, 0, t4_intr_all, sc, "all");
+ KASSERT(sc->flags & INTR_SHARED,
+ ("%s: single interrupt but not shared?", __func__));
+
+ T4_ALLOC_IRQ(sc, irq, rid, t4_intr_all, sc, "all");
} else {
/* Multiple interrupts. The first one is always error intr */
- T4_ALLOC_IRQ(sc, 0, 1, t4_intr_err, sc, "err");
-
- if (sc->flags & INTR_FWD) {
- /* The rest are shared by the fwq and all data intr */
- for (i = 1; i < sc->intr_count; i++) {
- snprintf(name, sizeof(name), "mux%d", i - 1);
- T4_ALLOC_IRQ(sc, i, i + 1, t4_intr_fwd,
- &sc->sge.fiq[i - 1], name);
+ T4_ALLOC_IRQ(sc, irq, rid, t4_intr_err, sc, "err");
+ irq++;
+ rid++;
+
+ /* Firmware event queue normally has an interrupt of its own */
+ if (sc->intr_count > T4_EXTRA_INTR) {
+ T4_ALLOC_IRQ(sc, irq, rid, t4_intr_evt, &sc->sge.fwq,
+ "evt");
+ irq++;
+ rid++;
+ }
+
+ intrq = &sc->sge.intrq[0];
+ if (sc->flags & INTR_SHARED) {
+
+ /* All ports share these interrupt queues */
+
+ for (i = 0; i < NINTRQ(sc); i++) {
+ snprintf(s, sizeof(s), "*.%d", i);
+ T4_ALLOC_IRQ(sc, irq, rid, t4_intr, intrq, s);
+ irq++;
+ rid++;
+ intrq++;
}
} else {
- struct port_info *pi;
- int p, q;
- T4_ALLOC_IRQ(sc, 1, 2, t4_intr_evt, &sc->sge.fwq,
- "evt");
+ /* Each port has its own set of interrupt queues */
- p = q = 0;
- pi = sc->port[p];
- for (i = 2; i < sc->intr_count; i++) {
- snprintf(name, sizeof(name), "p%dq%d", p, q);
- if (++q >= pi->nrxq) {
- p++;
- q = 0;
- pi = sc->port[p];
+ for (p = 0; p < sc->params.nports; p++) {
+ for (q = 0; q < sc->port[p]->nrxq; q++) {
+ snprintf(s, sizeof(s), "%d.%d", p, q);
+ T4_ALLOC_IRQ(sc, irq, rid, t4_intr,
+ intrq, s);
+ irq++;
+ rid++;
+ intrq++;
}
- T4_ALLOC_IRQ(sc, i, i + 1, t4_intr_data,
- &sc->sge.rxq[i - 2], name);
}
}
}
@@ -2366,6 +2424,10 @@ t4_sysctls(struct adapter *sc)
CTLTYPE_STRING | CTLFLAG_RD, &intr_pktcount, sizeof(intr_pktcount),
sysctl_int_array, "A", "interrupt holdoff packet counter values");
+ SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "devlog",
+ CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
+ sysctl_devlog, "A", "device log");
+
return (0);
}
@@ -2709,6 +2771,120 @@ sysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS)
return (sysctl_handle_64(oidp, &val, 0, req));
}
+const char *devlog_level_strings[] = {
+ [FW_DEVLOG_LEVEL_EMERG] = "EMERG",
+ [FW_DEVLOG_LEVEL_CRIT] = "CRIT",
+ [FW_DEVLOG_LEVEL_ERR] = "ERR",
+ [FW_DEVLOG_LEVEL_NOTICE] = "NOTICE",
+ [FW_DEVLOG_LEVEL_INFO] = "INFO",
+ [FW_DEVLOG_LEVEL_DEBUG] = "DEBUG"
+};
+
+const char *devlog_facility_strings[] = {
+ [FW_DEVLOG_FACILITY_CORE] = "CORE",
+ [FW_DEVLOG_FACILITY_SCHED] = "SCHED",
+ [FW_DEVLOG_FACILITY_TIMER] = "TIMER",
+ [FW_DEVLOG_FACILITY_RES] = "RES",
+ [FW_DEVLOG_FACILITY_HW] = "HW",
+ [FW_DEVLOG_FACILITY_FLR] = "FLR",
+ [FW_DEVLOG_FACILITY_DMAQ] = "DMAQ",
+ [FW_DEVLOG_FACILITY_PHY] = "PHY",
+ [FW_DEVLOG_FACILITY_MAC] = "MAC",
+ [FW_DEVLOG_FACILITY_PORT] = "PORT",
+ [FW_DEVLOG_FACILITY_VI] = "VI",
+ [FW_DEVLOG_FACILITY_FILTER] = "FILTER",
+ [FW_DEVLOG_FACILITY_ACL] = "ACL",
+ [FW_DEVLOG_FACILITY_TM] = "TM",
+ [FW_DEVLOG_FACILITY_QFC] = "QFC",
+ [FW_DEVLOG_FACILITY_DCB] = "DCB",
+ [FW_DEVLOG_FACILITY_ETH] = "ETH",
+ [FW_DEVLOG_FACILITY_OFLD] = "OFLD",
+ [FW_DEVLOG_FACILITY_RI] = "RI",
+ [FW_DEVLOG_FACILITY_ISCSI] = "ISCSI",
+ [FW_DEVLOG_FACILITY_FCOE] = "FCOE",
+ [FW_DEVLOG_FACILITY_FOISCSI] = "FOISCSI",
+ [FW_DEVLOG_FACILITY_FOFCOE] = "FOFCOE"
+};
+
+static int
+sysctl_devlog(SYSCTL_HANDLER_ARGS)
+{
+ struct adapter *sc = arg1;
+ struct devlog_params *dparams = &sc->params.devlog;
+ struct fw_devlog_e *buf, *e;
+ int i, j, rc, nentries, first = 0;
+ struct sbuf *sb;
+ uint64_t ftstamp = UINT64_MAX;
+
+ if (dparams->start == 0)
+ return (ENXIO);
+
+ nentries = dparams->size / sizeof(struct fw_devlog_e);
+
+ buf = malloc(dparams->size, M_CXGBE, M_NOWAIT);
+ if (buf == NULL)
+ return (ENOMEM);
+
+ rc = -t4_mem_read(sc, dparams->memtype, dparams->start, dparams->size,
+ (void *)buf);
+ if (rc != 0)
+ goto done;
+
+ for (i = 0; i < nentries; i++) {
+ e = &buf[i];
+
+ if (e->timestamp == 0)
+ break; /* end */
+
+ e->timestamp = be64toh(e->timestamp);
+ e->seqno = be32toh(e->seqno);
+ for (j = 0; j < 8; j++)
+ e->params[j] = be32toh(e->params[j]);
+
+ if (e->timestamp < ftstamp) {
+ ftstamp = e->timestamp;
+ first = i;
+ }
+ }
+
+ if (buf[first].timestamp == 0)
+ goto done; /* nothing in the log */
+
+ rc = sysctl_wire_old_buffer(req, 0);
+ if (rc != 0)
+ goto done;
+
+ sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req);
+ sbuf_printf(sb, "\n%10s %15s %8s %8s %s\n",
+ "Seq#", "Tstamp", "Level", "Facility", "Message");
+
+ i = first;
+ do {
+ e = &buf[i];
+ if (e->timestamp == 0)
+ break; /* end */
+
+ sbuf_printf(sb, "%10d %15ju %8s %8s ",
+ e->seqno, e->timestamp,
+ (e->level < ARRAY_SIZE(devlog_level_strings) ?
+ devlog_level_strings[e->level] : "UNKNOWN"),
+ (e->facility < ARRAY_SIZE(devlog_facility_strings) ?
+ devlog_facility_strings[e->facility] : "UNKNOWN"));
+ sbuf_printf(sb, e->fmt, e->params[0], e->params[1],
+ e->params[2], e->params[3], e->params[4],
+ e->params[5], e->params[6], e->params[7]);
+
+ if (++i == nentries)
+ i = 0;
+ } while (i != first);
+
+ rc = sbuf_finish(sb);
+ sbuf_delete(sb);
+done:
+ free(buf, M_CXGBE);
+ return (rc);
+}
+
static inline void
txq_start(struct ifnet *ifp, struct sge_txq *txq)
{
@@ -2892,6 +3068,20 @@ done:
return (rc);
}
+static inline uint64_t
+get_filter_hits(struct adapter *sc, uint32_t fid)
+{
+ uint32_t tcb_base = t4_read_reg(sc, A_TP_CMM_TCB_BASE);
+ uint64_t hits;
+
+ t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 0),
+ tcb_base + (fid + sc->tids.ftid_base) * TCB_SIZE);
+ t4_read_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 0));
+ hits = t4_read_reg64(sc, MEMWIN0_BASE + 16);
+
+ return (be64toh(hits));
+}
+
static int
get_filter(struct adapter *sc, struct t4_filter *t)
{
@@ -2913,8 +3103,13 @@ get_filter(struct adapter *sc, struct t4_filter *t)
for (i = t->idx; i < nfilters; i++, f++) {
if (f->valid) {
t->idx = i;
+ t->l2tidx = f->l2t ? f->l2t->idx : 0;
+ t->smtidx = f->smtidx;
+ if (f->fs.hitcnts)
+ t->hits = get_filter_hits(sc, t->idx);
+ else
+ t->hits = UINT64_MAX;
t->fs = f->fs;
- t->hits = 0; /* XXX implement */
return (0);
}
@@ -3034,11 +3229,12 @@ del_filter(struct adapter *sc, struct t4_filter *t)
return (0);
}
-/* XXX: L2T */
static void
-clear_filter(struct adapter *sc, struct filter_entry *f)
+clear_filter(struct filter_entry *f)
{
- (void) sc;
+ if (f->l2t)
+ t4_l2t_release(f->l2t);
+
bzero(f, sizeof (*f));
}
@@ -3053,8 +3249,18 @@ set_filter_wr(struct adapter *sc, int fidx)
ADAPTER_LOCK_ASSERT_OWNED(sc);
- if (f->fs.newdmac || f->fs.newvlan)
- return (ENOTSUP); /* XXX: fix after L2T code */
+ if (f->fs.newdmac || f->fs.newvlan) {
+ /* This filter needs an L2T entry; allocate one. */
+ f->l2t = t4_l2t_alloc_switching(sc->l2t);
+ if (f->l2t == NULL)
+ return (EAGAIN);
+ if (t4_l2t_set_switching(sc, f->l2t, f->fs.vlan, f->fs.eport,
+ f->fs.dmac)) {
+ t4_l2t_release(f->l2t);
+ f->l2t = NULL;
+ return (ENOMEM);
+ }
+ }
ftid = sc->tids.ftid_base + fidx;
@@ -3089,7 +3295,7 @@ set_filter_wr(struct adapter *sc, int fidx)
V_FW_FILTER_WR_HITCNTS(f->fs.hitcnts) |
V_FW_FILTER_WR_TXCHAN(f->fs.eport) |
V_FW_FILTER_WR_PRIO(f->fs.prio) |
- V_FW_FILTER_WR_L2TIX(0)); /* XXX: L2T */
+ V_FW_FILTER_WR_L2TIX(f->l2t ? f->l2t->idx : 0));
fwr->ethtype = htobe16(f->fs.val.ethtype);
fwr->ethtypem = htobe16(f->fs.mask.ethtype);
fwr->frag_to_ovlan_vldm =
@@ -3101,7 +3307,7 @@ set_filter_wr(struct adapter *sc, int fidx)
V_FW_FILTER_WR_OVLAN_VLDM(f->fs.mask.ovlan_vld));
fwr->smac_sel = 0;
fwr->rx_chan_rx_rpl_iq = htobe16(V_FW_FILTER_WR_RX_CHAN(0) |
- V_FW_FILTER_WR_RX_RPL_IQ(sc->sge.fwq.abs_id));
+ V_FW_FILTER_WR_RX_RPL_IQ(sc->sge.intrq[0].abs_id));
fwr->maci_to_matchtypem =
htobe32(V_FW_FILTER_WR_MACI(f->fs.val.macidx) |
V_FW_FILTER_WR_MACIM(f->fs.mask.macidx) |
@@ -3136,7 +3342,7 @@ set_filter_wr(struct adapter *sc, int fidx)
if (rc != 0) {
sc->tids.ftids_in_use--;
m_freem(m);
- clear_filter(sc, f);
+ clear_filter(f);
}
return (rc);
}
@@ -3161,7 +3367,7 @@ del_filter_wr(struct adapter *sc, int fidx)
m->m_len = m->m_pkthdr.len = sizeof(*fwr);
bzero(fwr, sizeof (*fwr));
- t4_mk_filtdelwr(ftid, fwr, sc->sge.fwq.abs_id);
+ t4_mk_filtdelwr(ftid, fwr, sc->sge.intrq[0].abs_id);
f->pending = 1;
rc = t4_mgmt_tx(sc, m);
@@ -3188,12 +3394,12 @@ filter_rpl(struct adapter *sc, const struct cpl_set_tcb_rpl *rpl)
* Clear the filter when we get confirmation from the
* hardware that the filter has been deleted.
*/
- clear_filter(sc, f);
+ clear_filter(f);
sc->tids.ftids_in_use--;
} else if (rc == FW_FILTER_WR_SMT_TBL_FULL) {
device_printf(sc->dev,
"filter %u setup failed due to full SMT\n", idx);
- clear_filter(sc, f);
+ clear_filter(f);
sc->tids.ftids_in_use--;
} else if (rc == FW_FILTER_WR_FLT_ADDED) {
f->smtidx = (be64toh(rpl->oldval) >> 24) & 0xff;
@@ -3206,12 +3412,41 @@ filter_rpl(struct adapter *sc, const struct cpl_set_tcb_rpl *rpl)
*/
device_printf(sc->dev,
"filter %u setup failed with error %u\n", idx, rc);
- clear_filter(sc, f);
+ clear_filter(f);
sc->tids.ftids_in_use--;
}
}
}
+static int
+get_sge_context(struct adapter *sc, struct t4_sge_context *cntxt)
+{
+ int rc = EINVAL;
+
+ if (cntxt->cid > M_CTXTQID)
+ return (rc);
+
+ if (cntxt->mem_id != CTXT_EGRESS && cntxt->mem_id != CTXT_INGRESS &&
+ cntxt->mem_id != CTXT_FLM && cntxt->mem_id != CTXT_CNM)
+ return (rc);
+
+ if (sc->flags & FW_OK) {
+ ADAPTER_LOCK(sc); /* Avoid parallel t4_wr_mbox */
+ rc = -t4_sge_ctxt_rd(sc, sc->mbox, cntxt->cid, cntxt->mem_id,
+ &cntxt->data[0]);
+ ADAPTER_UNLOCK(sc);
+ }
+
+ if (rc != 0) {
+ /* Read via firmware failed or wasn't even attempted */
+
+ rc = -t4_sge_ctxt_rd_bd(sc, cntxt->cid, cntxt->mem_id,
+ &cntxt->data[0]);
+ }
+
+ return (rc);
+}
+
int
t4_os_find_pci_capability(struct adapter *sc, int cap)
{
@@ -3375,6 +3610,9 @@ t4_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data, int fflag,
rc = del_filter(sc, (struct t4_filter *)data);
ADAPTER_UNLOCK(sc);
break;
+ case CHELSIO_T4_GET_SGE_CONTEXT:
+ rc = get_sge_context(sc, (struct t4_sge_context *)data);
+ break;
default:
rc = EINVAL;
}
OpenPOWER on IntegriCloud