diff options
Diffstat (limited to 'sys/dev/cxgbe/common/t4_hw.c')
-rw-r--r-- | sys/dev/cxgbe/common/t4_hw.c | 6623 |
1 files changed, 4990 insertions, 1633 deletions
diff --git a/sys/dev/cxgbe/common/t4_hw.c b/sys/dev/cxgbe/common/t4_hw.c index 31e8668..a618297 100644 --- a/sys/dev/cxgbe/common/t4_hw.c +++ b/sys/dev/cxgbe/common/t4_hw.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2012 Chelsio Communications, Inc. + * Copyright (c) 2012, 2016 Chelsio Communications, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -57,8 +57,8 @@ __FBSDID("$FreeBSD$"); * at the time it indicated completion is stored there. Returns 0 if the * operation completes and -EAGAIN otherwise. */ -int t4_wait_op_done_val(struct adapter *adapter, int reg, u32 mask, - int polarity, int attempts, int delay, u32 *valp) +static int t4_wait_op_done_val(struct adapter *adapter, int reg, u32 mask, + int polarity, int attempts, int delay, u32 *valp) { while (1) { u32 val = t4_read_reg(adapter, reg); @@ -75,6 +75,13 @@ int t4_wait_op_done_val(struct adapter *adapter, int reg, u32 mask, } } +static inline int t4_wait_op_done(struct adapter *adapter, int reg, u32 mask, + int polarity, int attempts, int delay) +{ + return t4_wait_op_done_val(adapter, reg, mask, polarity, attempts, + delay, NULL); +} + /** * t4_set_reg_field - set a register field to a value * @adapter: the adapter to program @@ -107,8 +114,8 @@ void t4_set_reg_field(struct adapter *adapter, unsigned int addr, u32 mask, * register pair. */ void t4_read_indirect(struct adapter *adap, unsigned int addr_reg, - unsigned int data_reg, u32 *vals, unsigned int nregs, - unsigned int start_idx) + unsigned int data_reg, u32 *vals, + unsigned int nregs, unsigned int start_idx) { while (nregs--) { t4_write_reg(adap, addr_reg, start_idx); @@ -144,26 +151,49 @@ void t4_write_indirect(struct adapter *adap, unsigned int addr_reg, * mechanism. This guarantees that we get the real value even if we're * operating within a Virtual Machine and the Hypervisor is trapping our * Configuration Space accesses. + * + * N.B. This routine should only be used as a last resort: the firmware uses + * the backdoor registers on a regular basis and we can end up + * conflicting with it's uses! */ u32 t4_hw_pci_read_cfg4(adapter_t *adap, int reg) { - t4_write_reg(adap, A_PCIE_CFG_SPACE_REQ, - F_ENABLE | F_LOCALCFG | V_FUNCTION(adap->pf) | - V_REGISTER(reg)); - return t4_read_reg(adap, A_PCIE_CFG_SPACE_DATA); + u32 req = V_FUNCTION(adap->pf) | V_REGISTER(reg); + u32 val; + + if (chip_id(adap) <= CHELSIO_T5) + req |= F_ENABLE; + else + req |= F_T6_ENABLE; + + if (is_t4(adap)) + req |= F_LOCALCFG; + + t4_write_reg(adap, A_PCIE_CFG_SPACE_REQ, req); + val = t4_read_reg(adap, A_PCIE_CFG_SPACE_DATA); + + /* + * Reset F_ENABLE to 0 so reads of PCIE_CFG_SPACE_DATA won't cause a + * Configuration Space read. (None of the other fields matter when + * F_ENABLE is 0 so a simple register write is easier than a + * read-modify-write via t4_set_reg_field().) + */ + t4_write_reg(adap, A_PCIE_CFG_SPACE_REQ, 0); + + return val; } /* - * t4_report_fw_error - report firmware error - * @adap: the adapter + * t4_report_fw_error - report firmware error + * @adap: the adapter * - * The adapter firmware can indicate error conditions to the host. - * This routine prints out the reason for the firmware error (as - * reported by the firmware). + * The adapter firmware can indicate error conditions to the host. + * If the firmware has indicated an error, print out the reason for + * the firmware error. */ static void t4_report_fw_error(struct adapter *adap) { - static const char *reason[] = { + static const char *const reason[] = { "Crash", /* PCIE_FW_EVAL_CRASH */ "During Device Preparation", /* PCIE_FW_EVAL_PREP */ "During Device Configuration", /* PCIE_FW_EVAL_CONF */ @@ -178,7 +208,7 @@ static void t4_report_fw_error(struct adapter *adap) pcie_fw = t4_read_reg(adap, A_PCIE_FW); if (pcie_fw & F_PCIE_FW_ERR) CH_ERR(adap, "Firmware reports adapter error: %s\n", - reason[G_PCIE_FW_EVAL(pcie_fw)]); + reason[G_PCIE_FW_EVAL(pcie_fw)]); } /* @@ -194,25 +224,27 @@ static void get_mbox_rpl(struct adapter *adap, __be64 *rpl, int nflit, /* * Handle a FW assertion reported in a mailbox. */ -static void fw_asrt(struct adapter *adap, u32 mbox_addr) +static void fw_asrt(struct adapter *adap, struct fw_debug_cmd *asrt) { - struct fw_debug_cmd asrt; - - get_mbox_rpl(adap, (__be64 *)&asrt, sizeof(asrt) / 8, mbox_addr); - CH_ALERT(adap, "FW assertion at %.16s:%u, val0 %#x, val1 %#x\n", - asrt.u.assert.filename_0_7, ntohl(asrt.u.assert.line), - ntohl(asrt.u.assert.x), ntohl(asrt.u.assert.y)); + CH_ALERT(adap, + "FW assertion at %.16s:%u, val0 %#x, val1 %#x\n", + asrt->u.assert.filename_0_7, + be32_to_cpu(asrt->u.assert.line), + be32_to_cpu(asrt->u.assert.x), + be32_to_cpu(asrt->u.assert.y)); } #define X_CIM_PF_NOACCESS 0xeeeeeeee /** - * t4_wr_mbox_meat - send a command to FW through the given mailbox + * t4_wr_mbox_meat_timeout - send a command to FW through the given mailbox * @adap: the adapter * @mbox: index of the mailbox to use * @cmd: the command to write * @size: command length in bytes * @rpl: where to optionally store the reply * @sleep_ok: if true we may sleep while awaiting command completion + * @timeout: time to wait for command to finish before timing out + * (negative implies @sleep_ok=false) * * Sends the given command to FW through the selected mailbox and waits * for the FW to execute the command. If @rpl is not %NULL it is used to @@ -221,14 +253,17 @@ static void fw_asrt(struct adapter *adap, u32 mbox_addr) * INITIALIZE can take a considerable amount of time to execute. * @sleep_ok determines whether we may sleep while awaiting the response. * If sleeping is allowed we use progressive backoff otherwise we spin. + * Note that passing in a negative @timeout is an alternate mechanism + * for specifying @sleep_ok=false. This is useful when a higher level + * interface allows for specification of @timeout but not @sleep_ok ... * * The return value is 0 on success or a negative errno on failure. A * failure can happen either because we are not able to execute the * command or FW executes it but signals an error. In the latter case * the return value is the error code indicated by FW (negated). */ -int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size, - void *rpl, bool sleep_ok) +int t4_wr_mbox_meat_timeout(struct adapter *adap, int mbox, const void *cmd, + int size, void *rpl, bool sleep_ok, int timeout) { /* * We delay in small increments at first in an effort to maintain @@ -238,43 +273,97 @@ int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size, static const int delay[] = { 1, 1, 3, 5, 10, 10, 20, 50, 100 }; - u32 v; u64 res; - int i, ms, delay_idx; + int i, ms, delay_idx, ret; const __be64 *p = cmd; u32 data_reg = PF_REG(mbox, A_CIM_PF_MAILBOX_DATA); u32 ctl_reg = PF_REG(mbox, A_CIM_PF_MAILBOX_CTRL); + u32 ctl; + __be64 cmd_rpl[MBOX_LEN/8]; + u32 pcie_fw; if ((size & 15) || size > MBOX_LEN) return -EINVAL; - v = G_MBOWNER(t4_read_reg(adap, ctl_reg)); - for (i = 0; v == X_MBOWNER_NONE && i < 3; i++) - v = G_MBOWNER(t4_read_reg(adap, ctl_reg)); + /* + * If we have a negative timeout, that implies that we can't sleep. + */ + if (timeout < 0) { + sleep_ok = false; + timeout = -timeout; + } + + /* + * Attempt to gain access to the mailbox. + */ + for (i = 0; i < 4; i++) { + ctl = t4_read_reg(adap, ctl_reg); + v = G_MBOWNER(ctl); + if (v != X_MBOWNER_NONE) + break; + } + + /* + * If we were unable to gain access, dequeue ourselves from the + * mailbox atomic access list and report the error to our caller. + */ + if (v != X_MBOWNER_PL) { + t4_report_fw_error(adap); + ret = (v == X_MBOWNER_FW) ? -EBUSY : -ETIMEDOUT; + return ret; + } - if (v != X_MBOWNER_PL) - return v ? -EBUSY : -ETIMEDOUT; + /* + * If we gain ownership of the mailbox and there's a "valid" message + * in it, this is likely an asynchronous error message from the + * firmware. So we'll report that and then proceed on with attempting + * to issue our own command ... which may well fail if the error + * presaged the firmware crashing ... + */ + if (ctl & F_MBMSGVALID) { + CH_ERR(adap, "found VALID command in mbox %u: " + "%llx %llx %llx %llx %llx %llx %llx %llx\n", mbox, + (unsigned long long)t4_read_reg64(adap, data_reg), + (unsigned long long)t4_read_reg64(adap, data_reg + 8), + (unsigned long long)t4_read_reg64(adap, data_reg + 16), + (unsigned long long)t4_read_reg64(adap, data_reg + 24), + (unsigned long long)t4_read_reg64(adap, data_reg + 32), + (unsigned long long)t4_read_reg64(adap, data_reg + 40), + (unsigned long long)t4_read_reg64(adap, data_reg + 48), + (unsigned long long)t4_read_reg64(adap, data_reg + 56)); + } + /* + * Copy in the new mailbox command and send it on its way ... + */ for (i = 0; i < size; i += 8, p++) t4_write_reg64(adap, data_reg + i, be64_to_cpu(*p)); CH_DUMP_MBOX(adap, mbox, data_reg); t4_write_reg(adap, ctl_reg, F_MBMSGVALID | V_MBOWNER(X_MBOWNER_FW)); - t4_read_reg(adap, ctl_reg); /* flush write */ + t4_read_reg(adap, ctl_reg); /* flush write */ delay_idx = 0; ms = delay[0]; - for (i = 0; i < FW_CMD_MAX_TIMEOUT; i += ms) { + /* + * Loop waiting for the reply; bail out if we time out or the firmware + * reports an error. + */ + for (i = 0; + !((pcie_fw = t4_read_reg(adap, A_PCIE_FW)) & F_PCIE_FW_ERR) && + i < timeout; + i += ms) { if (sleep_ok) { ms = delay[delay_idx]; /* last element may repeat */ if (delay_idx < ARRAY_SIZE(delay) - 1) delay_idx++; msleep(ms); - } else + } else { mdelay(ms); + } v = t4_read_reg(adap, ctl_reg); if (v == X_CIM_PF_NOACCESS) @@ -286,15 +375,20 @@ int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size, continue; } + /* + * Retrieve the command reply and release the mailbox. + */ + get_mbox_rpl(adap, cmd_rpl, size/8, data_reg); + t4_write_reg(adap, ctl_reg, V_MBOWNER(X_MBOWNER_NONE)); + CH_DUMP_MBOX(adap, mbox, data_reg); - res = t4_read_reg64(adap, data_reg); + res = be64_to_cpu(cmd_rpl[0]); if (G_FW_CMD_OP(res >> 32) == FW_DEBUG_CMD) { - fw_asrt(adap, data_reg); + fw_asrt(adap, (struct fw_debug_cmd *)cmd_rpl); res = V_FW_CMD_RETVAL(EIO); } else if (rpl) - get_mbox_rpl(adap, rpl, size / 8, data_reg); - t4_write_reg(adap, ctl_reg, V_MBOWNER(X_MBOWNER_NONE)); + memcpy(rpl, cmd_rpl, size); return -G_FW_CMD_RETVAL((int)res); } } @@ -304,11 +398,58 @@ int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size, * the error and also check to see if the firmware reported any * errors ... */ + ret = (pcie_fw & F_PCIE_FW_ERR) ? -ENXIO : -ETIMEDOUT; CH_ERR(adap, "command %#x in mailbox %d timed out\n", *(const u8 *)cmd, mbox); - if (t4_read_reg(adap, A_PCIE_FW) & F_PCIE_FW_ERR) - t4_report_fw_error(adap); - return -ETIMEDOUT; + + t4_report_fw_error(adap); + t4_fatal_err(adap); + return ret; +} + +int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size, + void *rpl, bool sleep_ok) +{ + return t4_wr_mbox_meat_timeout(adap, mbox, cmd, size, rpl, + sleep_ok, FW_CMD_MAX_TIMEOUT); + +} + +static int t4_edc_err_read(struct adapter *adap, int idx) +{ + u32 edc_ecc_err_addr_reg; + u32 edc_bist_status_rdata_reg; + + if (is_t4(adap)) { + CH_WARN(adap, "%s: T4 NOT supported.\n", __func__); + return 0; + } + if (idx != 0 && idx != 1) { + CH_WARN(adap, "%s: idx %d NOT supported.\n", __func__, idx); + return 0; + } + + edc_ecc_err_addr_reg = EDC_T5_REG(A_EDC_H_ECC_ERR_ADDR, idx); + edc_bist_status_rdata_reg = EDC_T5_REG(A_EDC_H_BIST_STATUS_RDATA, idx); + + CH_WARN(adap, + "edc%d err addr 0x%x: 0x%x.\n", + idx, edc_ecc_err_addr_reg, + t4_read_reg(adap, edc_ecc_err_addr_reg)); + CH_WARN(adap, + "bist: 0x%x, status %llx %llx %llx %llx %llx %llx %llx %llx %llx.\n", + edc_bist_status_rdata_reg, + (unsigned long long)t4_read_reg64(adap, edc_bist_status_rdata_reg), + (unsigned long long)t4_read_reg64(adap, edc_bist_status_rdata_reg + 8), + (unsigned long long)t4_read_reg64(adap, edc_bist_status_rdata_reg + 16), + (unsigned long long)t4_read_reg64(adap, edc_bist_status_rdata_reg + 24), + (unsigned long long)t4_read_reg64(adap, edc_bist_status_rdata_reg + 32), + (unsigned long long)t4_read_reg64(adap, edc_bist_status_rdata_reg + 40), + (unsigned long long)t4_read_reg64(adap, edc_bist_status_rdata_reg + 48), + (unsigned long long)t4_read_reg64(adap, edc_bist_status_rdata_reg + 56), + (unsigned long long)t4_read_reg64(adap, edc_bist_status_rdata_reg + 64)); + + return 0; } /** @@ -493,8 +634,1956 @@ int t4_mem_read(struct adapter *adap, int mtype, u32 addr, u32 len, } /* + * Return the specified PCI-E Configuration Space register from our Physical + * Function. We try first via a Firmware LDST Command (if fw_attach != 0) + * since we prefer to let the firmware own all of these registers, but if that + * fails we go for it directly ourselves. + */ +u32 t4_read_pcie_cfg4(struct adapter *adap, int reg, int drv_fw_attach) +{ + + /* + * If fw_attach != 0, construct and send the Firmware LDST Command to + * retrieve the specified PCI-E Configuration Space register. + */ + if (drv_fw_attach != 0) { + struct fw_ldst_cmd ldst_cmd; + int ret; + + memset(&ldst_cmd, 0, sizeof(ldst_cmd)); + ldst_cmd.op_to_addrspace = + cpu_to_be32(V_FW_CMD_OP(FW_LDST_CMD) | + F_FW_CMD_REQUEST | + F_FW_CMD_READ | + V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_FUNC_PCIE)); + ldst_cmd.cycles_to_len16 = cpu_to_be32(FW_LEN16(ldst_cmd)); + ldst_cmd.u.pcie.select_naccess = V_FW_LDST_CMD_NACCESS(1); + ldst_cmd.u.pcie.ctrl_to_fn = + (F_FW_LDST_CMD_LC | V_FW_LDST_CMD_FN(adap->pf)); + ldst_cmd.u.pcie.r = reg; + + /* + * If the LDST Command succeeds, return the result, otherwise + * fall through to reading it directly ourselves ... + */ + ret = t4_wr_mbox(adap, adap->mbox, &ldst_cmd, sizeof(ldst_cmd), + &ldst_cmd); + if (ret == 0) + return be32_to_cpu(ldst_cmd.u.pcie.data[0]); + + CH_WARN(adap, "Firmware failed to return " + "Configuration Space register %d, err = %d\n", + reg, -ret); + } + + /* + * Read the desired Configuration Space register via the PCI-E + * Backdoor mechanism. + */ + return t4_hw_pci_read_cfg4(adap, reg); +} + +/** + * t4_get_regs_len - return the size of the chips register set + * @adapter: the adapter + * + * Returns the size of the chip's BAR0 register space. + */ +unsigned int t4_get_regs_len(struct adapter *adapter) +{ + unsigned int chip_version = chip_id(adapter); + + switch (chip_version) { + case CHELSIO_T4: + return T4_REGMAP_SIZE; + + case CHELSIO_T5: + case CHELSIO_T6: + return T5_REGMAP_SIZE; + } + + CH_ERR(adapter, + "Unsupported chip version %d\n", chip_version); + return 0; +} + +/** + * t4_get_regs - read chip registers into provided buffer + * @adap: the adapter + * @buf: register buffer + * @buf_size: size (in bytes) of register buffer + * + * If the provided register buffer isn't large enough for the chip's + * full register range, the register dump will be truncated to the + * register buffer's size. + */ +void t4_get_regs(struct adapter *adap, u8 *buf, size_t buf_size) +{ + static const unsigned int t4_reg_ranges[] = { + 0x1008, 0x1108, + 0x1180, 0x1184, + 0x1190, 0x1194, + 0x11a0, 0x11a4, + 0x11b0, 0x11b4, + 0x11fc, 0x123c, + 0x1300, 0x173c, + 0x1800, 0x18fc, + 0x3000, 0x30d8, + 0x30e0, 0x30e4, + 0x30ec, 0x5910, + 0x5920, 0x5924, + 0x5960, 0x5960, + 0x5968, 0x5968, + 0x5970, 0x5970, + 0x5978, 0x5978, + 0x5980, 0x5980, + 0x5988, 0x5988, + 0x5990, 0x5990, + 0x5998, 0x5998, + 0x59a0, 0x59d4, + 0x5a00, 0x5ae0, + 0x5ae8, 0x5ae8, + 0x5af0, 0x5af0, + 0x5af8, 0x5af8, + 0x6000, 0x6098, + 0x6100, 0x6150, + 0x6200, 0x6208, + 0x6240, 0x6248, + 0x6280, 0x62b0, + 0x62c0, 0x6338, + 0x6370, 0x638c, + 0x6400, 0x643c, + 0x6500, 0x6524, + 0x6a00, 0x6a04, + 0x6a14, 0x6a38, + 0x6a60, 0x6a70, + 0x6a78, 0x6a78, + 0x6b00, 0x6b0c, + 0x6b1c, 0x6b84, + 0x6bf0, 0x6bf8, + 0x6c00, 0x6c0c, + 0x6c1c, 0x6c84, + 0x6cf0, 0x6cf8, + 0x6d00, 0x6d0c, + 0x6d1c, 0x6d84, + 0x6df0, 0x6df8, + 0x6e00, 0x6e0c, + 0x6e1c, 0x6e84, + 0x6ef0, 0x6ef8, + 0x6f00, 0x6f0c, + 0x6f1c, 0x6f84, + 0x6ff0, 0x6ff8, + 0x7000, 0x700c, + 0x701c, 0x7084, + 0x70f0, 0x70f8, + 0x7100, 0x710c, + 0x711c, 0x7184, + 0x71f0, 0x71f8, + 0x7200, 0x720c, + 0x721c, 0x7284, + 0x72f0, 0x72f8, + 0x7300, 0x730c, + 0x731c, 0x7384, + 0x73f0, 0x73f8, + 0x7400, 0x7450, + 0x7500, 0x7530, + 0x7600, 0x760c, + 0x7614, 0x761c, + 0x7680, 0x76cc, + 0x7700, 0x7798, + 0x77c0, 0x77fc, + 0x7900, 0x79fc, + 0x7b00, 0x7b58, + 0x7b60, 0x7b84, + 0x7b8c, 0x7c38, + 0x7d00, 0x7d38, + 0x7d40, 0x7d80, + 0x7d8c, 0x7ddc, + 0x7de4, 0x7e04, + 0x7e10, 0x7e1c, + 0x7e24, 0x7e38, + 0x7e40, 0x7e44, + 0x7e4c, 0x7e78, + 0x7e80, 0x7ea4, + 0x7eac, 0x7edc, + 0x7ee8, 0x7efc, + 0x8dc0, 0x8e04, + 0x8e10, 0x8e1c, + 0x8e30, 0x8e78, + 0x8ea0, 0x8eb8, + 0x8ec0, 0x8f6c, + 0x8fc0, 0x9008, + 0x9010, 0x9058, + 0x9060, 0x9060, + 0x9068, 0x9074, + 0x90fc, 0x90fc, + 0x9400, 0x9408, + 0x9410, 0x9458, + 0x9600, 0x9600, + 0x9608, 0x9638, + 0x9640, 0x96bc, + 0x9800, 0x9808, + 0x9820, 0x983c, + 0x9850, 0x9864, + 0x9c00, 0x9c6c, + 0x9c80, 0x9cec, + 0x9d00, 0x9d6c, + 0x9d80, 0x9dec, + 0x9e00, 0x9e6c, + 0x9e80, 0x9eec, + 0x9f00, 0x9f6c, + 0x9f80, 0x9fec, + 0xd004, 0xd004, + 0xd010, 0xd03c, + 0xdfc0, 0xdfe0, + 0xe000, 0xea7c, + 0xf000, 0x11190, + 0x19040, 0x1906c, + 0x19078, 0x19080, + 0x1908c, 0x190e4, + 0x190f0, 0x190f8, + 0x19100, 0x19110, + 0x19120, 0x19124, + 0x19150, 0x19194, + 0x1919c, 0x191b0, + 0x191d0, 0x191e8, + 0x19238, 0x1924c, + 0x193f8, 0x1943c, + 0x1944c, 0x19474, + 0x19490, 0x194e0, + 0x194f0, 0x194f8, + 0x19800, 0x19c08, + 0x19c10, 0x19c90, + 0x19ca0, 0x19ce4, + 0x19cf0, 0x19d40, + 0x19d50, 0x19d94, + 0x19da0, 0x19de8, + 0x19df0, 0x19e40, + 0x19e50, 0x19e90, + 0x19ea0, 0x19f4c, + 0x1a000, 0x1a004, + 0x1a010, 0x1a06c, + 0x1a0b0, 0x1a0e4, + 0x1a0ec, 0x1a0f4, + 0x1a100, 0x1a108, + 0x1a114, 0x1a120, + 0x1a128, 0x1a130, + 0x1a138, 0x1a138, + 0x1a190, 0x1a1c4, + 0x1a1fc, 0x1a1fc, + 0x1e040, 0x1e04c, + 0x1e284, 0x1e28c, + 0x1e2c0, 0x1e2c0, + 0x1e2e0, 0x1e2e0, + 0x1e300, 0x1e384, + 0x1e3c0, 0x1e3c8, + 0x1e440, 0x1e44c, + 0x1e684, 0x1e68c, + 0x1e6c0, 0x1e6c0, + 0x1e6e0, 0x1e6e0, + 0x1e700, 0x1e784, + 0x1e7c0, 0x1e7c8, + 0x1e840, 0x1e84c, + 0x1ea84, 0x1ea8c, + 0x1eac0, 0x1eac0, + 0x1eae0, 0x1eae0, + 0x1eb00, 0x1eb84, + 0x1ebc0, 0x1ebc8, + 0x1ec40, 0x1ec4c, + 0x1ee84, 0x1ee8c, + 0x1eec0, 0x1eec0, + 0x1eee0, 0x1eee0, + 0x1ef00, 0x1ef84, + 0x1efc0, 0x1efc8, + 0x1f040, 0x1f04c, + 0x1f284, 0x1f28c, + 0x1f2c0, 0x1f2c0, + 0x1f2e0, 0x1f2e0, + 0x1f300, 0x1f384, + 0x1f3c0, 0x1f3c8, + 0x1f440, 0x1f44c, + 0x1f684, 0x1f68c, + 0x1f6c0, 0x1f6c0, + 0x1f6e0, 0x1f6e0, + 0x1f700, 0x1f784, + 0x1f7c0, 0x1f7c8, + 0x1f840, 0x1f84c, + 0x1fa84, 0x1fa8c, + 0x1fac0, 0x1fac0, + 0x1fae0, 0x1fae0, + 0x1fb00, 0x1fb84, + 0x1fbc0, 0x1fbc8, + 0x1fc40, 0x1fc4c, + 0x1fe84, 0x1fe8c, + 0x1fec0, 0x1fec0, + 0x1fee0, 0x1fee0, + 0x1ff00, 0x1ff84, + 0x1ffc0, 0x1ffc8, + 0x20000, 0x2002c, + 0x20100, 0x2013c, + 0x20190, 0x201a0, + 0x201a8, 0x201b8, + 0x201c4, 0x201c8, + 0x20200, 0x20318, + 0x20400, 0x204b4, + 0x204c0, 0x20528, + 0x20540, 0x20614, + 0x21000, 0x21040, + 0x2104c, 0x21060, + 0x210c0, 0x210ec, + 0x21200, 0x21268, + 0x21270, 0x21284, + 0x212fc, 0x21388, + 0x21400, 0x21404, + 0x21500, 0x21500, + 0x21510, 0x21518, + 0x2152c, 0x21530, + 0x2153c, 0x2153c, + 0x21550, 0x21554, + 0x21600, 0x21600, + 0x21608, 0x2161c, + 0x21624, 0x21628, + 0x21630, 0x21634, + 0x2163c, 0x2163c, + 0x21700, 0x2171c, + 0x21780, 0x2178c, + 0x21800, 0x21818, + 0x21820, 0x21828, + 0x21830, 0x21848, + 0x21850, 0x21854, + 0x21860, 0x21868, + 0x21870, 0x21870, + 0x21878, 0x21898, + 0x218a0, 0x218a8, + 0x218b0, 0x218c8, + 0x218d0, 0x218d4, + 0x218e0, 0x218e8, + 0x218f0, 0x218f0, + 0x218f8, 0x21a18, + 0x21a20, 0x21a28, + 0x21a30, 0x21a48, + 0x21a50, 0x21a54, + 0x21a60, 0x21a68, + 0x21a70, 0x21a70, + 0x21a78, 0x21a98, + 0x21aa0, 0x21aa8, + 0x21ab0, 0x21ac8, + 0x21ad0, 0x21ad4, + 0x21ae0, 0x21ae8, + 0x21af0, 0x21af0, + 0x21af8, 0x21c18, + 0x21c20, 0x21c20, + 0x21c28, 0x21c30, + 0x21c38, 0x21c38, + 0x21c80, 0x21c98, + 0x21ca0, 0x21ca8, + 0x21cb0, 0x21cc8, + 0x21cd0, 0x21cd4, + 0x21ce0, 0x21ce8, + 0x21cf0, 0x21cf0, + 0x21cf8, 0x21d7c, + 0x21e00, 0x21e04, + 0x22000, 0x2202c, + 0x22100, 0x2213c, + 0x22190, 0x221a0, + 0x221a8, 0x221b8, + 0x221c4, 0x221c8, + 0x22200, 0x22318, + 0x22400, 0x224b4, + 0x224c0, 0x22528, + 0x22540, 0x22614, + 0x23000, 0x23040, + 0x2304c, 0x23060, + 0x230c0, 0x230ec, + 0x23200, 0x23268, + 0x23270, 0x23284, + 0x232fc, 0x23388, + 0x23400, 0x23404, + 0x23500, 0x23500, + 0x23510, 0x23518, + 0x2352c, 0x23530, + 0x2353c, 0x2353c, + 0x23550, 0x23554, + 0x23600, 0x23600, + 0x23608, 0x2361c, + 0x23624, 0x23628, + 0x23630, 0x23634, + 0x2363c, 0x2363c, + 0x23700, 0x2371c, + 0x23780, 0x2378c, + 0x23800, 0x23818, + 0x23820, 0x23828, + 0x23830, 0x23848, + 0x23850, 0x23854, + 0x23860, 0x23868, + 0x23870, 0x23870, + 0x23878, 0x23898, + 0x238a0, 0x238a8, + 0x238b0, 0x238c8, + 0x238d0, 0x238d4, + 0x238e0, 0x238e8, + 0x238f0, 0x238f0, + 0x238f8, 0x23a18, + 0x23a20, 0x23a28, + 0x23a30, 0x23a48, + 0x23a50, 0x23a54, + 0x23a60, 0x23a68, + 0x23a70, 0x23a70, + 0x23a78, 0x23a98, + 0x23aa0, 0x23aa8, + 0x23ab0, 0x23ac8, + 0x23ad0, 0x23ad4, + 0x23ae0, 0x23ae8, + 0x23af0, 0x23af0, + 0x23af8, 0x23c18, + 0x23c20, 0x23c20, + 0x23c28, 0x23c30, + 0x23c38, 0x23c38, + 0x23c80, 0x23c98, + 0x23ca0, 0x23ca8, + 0x23cb0, 0x23cc8, + 0x23cd0, 0x23cd4, + 0x23ce0, 0x23ce8, + 0x23cf0, 0x23cf0, + 0x23cf8, 0x23d7c, + 0x23e00, 0x23e04, + 0x24000, 0x2402c, + 0x24100, 0x2413c, + 0x24190, 0x241a0, + 0x241a8, 0x241b8, + 0x241c4, 0x241c8, + 0x24200, 0x24318, + 0x24400, 0x244b4, + 0x244c0, 0x24528, + 0x24540, 0x24614, + 0x25000, 0x25040, + 0x2504c, 0x25060, + 0x250c0, 0x250ec, + 0x25200, 0x25268, + 0x25270, 0x25284, + 0x252fc, 0x25388, + 0x25400, 0x25404, + 0x25500, 0x25500, + 0x25510, 0x25518, + 0x2552c, 0x25530, + 0x2553c, 0x2553c, + 0x25550, 0x25554, + 0x25600, 0x25600, + 0x25608, 0x2561c, + 0x25624, 0x25628, + 0x25630, 0x25634, + 0x2563c, 0x2563c, + 0x25700, 0x2571c, + 0x25780, 0x2578c, + 0x25800, 0x25818, + 0x25820, 0x25828, + 0x25830, 0x25848, + 0x25850, 0x25854, + 0x25860, 0x25868, + 0x25870, 0x25870, + 0x25878, 0x25898, + 0x258a0, 0x258a8, + 0x258b0, 0x258c8, + 0x258d0, 0x258d4, + 0x258e0, 0x258e8, + 0x258f0, 0x258f0, + 0x258f8, 0x25a18, + 0x25a20, 0x25a28, + 0x25a30, 0x25a48, + 0x25a50, 0x25a54, + 0x25a60, 0x25a68, + 0x25a70, 0x25a70, + 0x25a78, 0x25a98, + 0x25aa0, 0x25aa8, + 0x25ab0, 0x25ac8, + 0x25ad0, 0x25ad4, + 0x25ae0, 0x25ae8, + 0x25af0, 0x25af0, + 0x25af8, 0x25c18, + 0x25c20, 0x25c20, + 0x25c28, 0x25c30, + 0x25c38, 0x25c38, + 0x25c80, 0x25c98, + 0x25ca0, 0x25ca8, + 0x25cb0, 0x25cc8, + 0x25cd0, 0x25cd4, + 0x25ce0, 0x25ce8, + 0x25cf0, 0x25cf0, + 0x25cf8, 0x25d7c, + 0x25e00, 0x25e04, + 0x26000, 0x2602c, + 0x26100, 0x2613c, + 0x26190, 0x261a0, + 0x261a8, 0x261b8, + 0x261c4, 0x261c8, + 0x26200, 0x26318, + 0x26400, 0x264b4, + 0x264c0, 0x26528, + 0x26540, 0x26614, + 0x27000, 0x27040, + 0x2704c, 0x27060, + 0x270c0, 0x270ec, + 0x27200, 0x27268, + 0x27270, 0x27284, + 0x272fc, 0x27388, + 0x27400, 0x27404, + 0x27500, 0x27500, + 0x27510, 0x27518, + 0x2752c, 0x27530, + 0x2753c, 0x2753c, + 0x27550, 0x27554, + 0x27600, 0x27600, + 0x27608, 0x2761c, + 0x27624, 0x27628, + 0x27630, 0x27634, + 0x2763c, 0x2763c, + 0x27700, 0x2771c, + 0x27780, 0x2778c, + 0x27800, 0x27818, + 0x27820, 0x27828, + 0x27830, 0x27848, + 0x27850, 0x27854, + 0x27860, 0x27868, + 0x27870, 0x27870, + 0x27878, 0x27898, + 0x278a0, 0x278a8, + 0x278b0, 0x278c8, + 0x278d0, 0x278d4, + 0x278e0, 0x278e8, + 0x278f0, 0x278f0, + 0x278f8, 0x27a18, + 0x27a20, 0x27a28, + 0x27a30, 0x27a48, + 0x27a50, 0x27a54, + 0x27a60, 0x27a68, + 0x27a70, 0x27a70, + 0x27a78, 0x27a98, + 0x27aa0, 0x27aa8, + 0x27ab0, 0x27ac8, + 0x27ad0, 0x27ad4, + 0x27ae0, 0x27ae8, + 0x27af0, 0x27af0, + 0x27af8, 0x27c18, + 0x27c20, 0x27c20, + 0x27c28, 0x27c30, + 0x27c38, 0x27c38, + 0x27c80, 0x27c98, + 0x27ca0, 0x27ca8, + 0x27cb0, 0x27cc8, + 0x27cd0, 0x27cd4, + 0x27ce0, 0x27ce8, + 0x27cf0, 0x27cf0, + 0x27cf8, 0x27d7c, + 0x27e00, 0x27e04, + }; + + static const unsigned int t5_reg_ranges[] = { + 0x1008, 0x10c0, + 0x10cc, 0x10f8, + 0x1100, 0x1100, + 0x110c, 0x1148, + 0x1180, 0x1184, + 0x1190, 0x1194, + 0x11a0, 0x11a4, + 0x11b0, 0x11b4, + 0x11fc, 0x123c, + 0x1280, 0x173c, + 0x1800, 0x18fc, + 0x3000, 0x3028, + 0x3060, 0x30b0, + 0x30b8, 0x30d8, + 0x30e0, 0x30fc, + 0x3140, 0x357c, + 0x35a8, 0x35cc, + 0x35ec, 0x35ec, + 0x3600, 0x5624, + 0x56cc, 0x56ec, + 0x56f4, 0x5720, + 0x5728, 0x575c, + 0x580c, 0x5814, + 0x5890, 0x589c, + 0x58a4, 0x58ac, + 0x58b8, 0x58bc, + 0x5940, 0x59c8, + 0x59d0, 0x59dc, + 0x59fc, 0x5a18, + 0x5a60, 0x5a70, + 0x5a80, 0x5a9c, + 0x5b94, 0x5bfc, + 0x6000, 0x6020, + 0x6028, 0x6040, + 0x6058, 0x609c, + 0x60a8, 0x614c, + 0x7700, 0x7798, + 0x77c0, 0x78fc, + 0x7b00, 0x7b58, + 0x7b60, 0x7b84, + 0x7b8c, 0x7c54, + 0x7d00, 0x7d38, + 0x7d40, 0x7d80, + 0x7d8c, 0x7ddc, + 0x7de4, 0x7e04, + 0x7e10, 0x7e1c, + 0x7e24, 0x7e38, + 0x7e40, 0x7e44, + 0x7e4c, 0x7e78, + 0x7e80, 0x7edc, + 0x7ee8, 0x7efc, + 0x8dc0, 0x8de0, + 0x8df8, 0x8e04, + 0x8e10, 0x8e84, + 0x8ea0, 0x8f84, + 0x8fc0, 0x9058, + 0x9060, 0x9060, + 0x9068, 0x90f8, + 0x9400, 0x9408, + 0x9410, 0x9470, + 0x9600, 0x9600, + 0x9608, 0x9638, + 0x9640, 0x96f4, + 0x9800, 0x9808, + 0x9820, 0x983c, + 0x9850, 0x9864, + 0x9c00, 0x9c6c, + 0x9c80, 0x9cec, + 0x9d00, 0x9d6c, + 0x9d80, 0x9dec, + 0x9e00, 0x9e6c, + 0x9e80, 0x9eec, + 0x9f00, 0x9f6c, + 0x9f80, 0xa020, + 0xd004, 0xd004, + 0xd010, 0xd03c, + 0xdfc0, 0xdfe0, + 0xe000, 0x1106c, + 0x11074, 0x11088, + 0x1109c, 0x1117c, + 0x11190, 0x11204, + 0x19040, 0x1906c, + 0x19078, 0x19080, + 0x1908c, 0x190e8, + 0x190f0, 0x190f8, + 0x19100, 0x19110, + 0x19120, 0x19124, + 0x19150, 0x19194, + 0x1919c, 0x191b0, + 0x191d0, 0x191e8, + 0x19238, 0x19290, + 0x193f8, 0x19428, + 0x19430, 0x19444, + 0x1944c, 0x1946c, + 0x19474, 0x19474, + 0x19490, 0x194cc, + 0x194f0, 0x194f8, + 0x19c00, 0x19c08, + 0x19c10, 0x19c60, + 0x19c94, 0x19ce4, + 0x19cf0, 0x19d40, + 0x19d50, 0x19d94, + 0x19da0, 0x19de8, + 0x19df0, 0x19e10, + 0x19e50, 0x19e90, + 0x19ea0, 0x19f24, + 0x19f34, 0x19f34, + 0x19f40, 0x19f50, + 0x19f90, 0x19fb4, + 0x19fc4, 0x19fe4, + 0x1a000, 0x1a004, + 0x1a010, 0x1a06c, + 0x1a0b0, 0x1a0e4, + 0x1a0ec, 0x1a0f8, + 0x1a100, 0x1a108, + 0x1a114, 0x1a120, + 0x1a128, 0x1a130, + 0x1a138, 0x1a138, + 0x1a190, 0x1a1c4, + 0x1a1fc, 0x1a1fc, + 0x1e008, 0x1e00c, + 0x1e040, 0x1e044, + 0x1e04c, 0x1e04c, + 0x1e284, 0x1e290, + 0x1e2c0, 0x1e2c0, + 0x1e2e0, 0x1e2e0, + 0x1e300, 0x1e384, + 0x1e3c0, 0x1e3c8, + 0x1e408, 0x1e40c, + 0x1e440, 0x1e444, + 0x1e44c, 0x1e44c, + 0x1e684, 0x1e690, + 0x1e6c0, 0x1e6c0, + 0x1e6e0, 0x1e6e0, + 0x1e700, 0x1e784, + 0x1e7c0, 0x1e7c8, + 0x1e808, 0x1e80c, + 0x1e840, 0x1e844, + 0x1e84c, 0x1e84c, + 0x1ea84, 0x1ea90, + 0x1eac0, 0x1eac0, + 0x1eae0, 0x1eae0, + 0x1eb00, 0x1eb84, + 0x1ebc0, 0x1ebc8, + 0x1ec08, 0x1ec0c, + 0x1ec40, 0x1ec44, + 0x1ec4c, 0x1ec4c, + 0x1ee84, 0x1ee90, + 0x1eec0, 0x1eec0, + 0x1eee0, 0x1eee0, + 0x1ef00, 0x1ef84, + 0x1efc0, 0x1efc8, + 0x1f008, 0x1f00c, + 0x1f040, 0x1f044, + 0x1f04c, 0x1f04c, + 0x1f284, 0x1f290, + 0x1f2c0, 0x1f2c0, + 0x1f2e0, 0x1f2e0, + 0x1f300, 0x1f384, + 0x1f3c0, 0x1f3c8, + 0x1f408, 0x1f40c, + 0x1f440, 0x1f444, + 0x1f44c, 0x1f44c, + 0x1f684, 0x1f690, + 0x1f6c0, 0x1f6c0, + 0x1f6e0, 0x1f6e0, + 0x1f700, 0x1f784, + 0x1f7c0, 0x1f7c8, + 0x1f808, 0x1f80c, + 0x1f840, 0x1f844, + 0x1f84c, 0x1f84c, + 0x1fa84, 0x1fa90, + 0x1fac0, 0x1fac0, + 0x1fae0, 0x1fae0, + 0x1fb00, 0x1fb84, + 0x1fbc0, 0x1fbc8, + 0x1fc08, 0x1fc0c, + 0x1fc40, 0x1fc44, + 0x1fc4c, 0x1fc4c, + 0x1fe84, 0x1fe90, + 0x1fec0, 0x1fec0, + 0x1fee0, 0x1fee0, + 0x1ff00, 0x1ff84, + 0x1ffc0, 0x1ffc8, + 0x30000, 0x30030, + 0x30038, 0x30038, + 0x30040, 0x30040, + 0x30100, 0x30144, + 0x30190, 0x301a0, + 0x301a8, 0x301b8, + 0x301c4, 0x301c8, + 0x301d0, 0x301d0, + 0x30200, 0x30318, + 0x30400, 0x304b4, + 0x304c0, 0x3052c, + 0x30540, 0x3061c, + 0x30800, 0x30828, + 0x30834, 0x30834, + 0x308c0, 0x30908, + 0x30910, 0x309ac, + 0x30a00, 0x30a14, + 0x30a1c, 0x30a2c, + 0x30a44, 0x30a50, + 0x30a74, 0x30a74, + 0x30a7c, 0x30afc, + 0x30b08, 0x30c24, + 0x30d00, 0x30d00, + 0x30d08, 0x30d14, + 0x30d1c, 0x30d20, + 0x30d3c, 0x30d3c, + 0x30d48, 0x30d50, + 0x31200, 0x3120c, + 0x31220, 0x31220, + 0x31240, 0x31240, + 0x31600, 0x3160c, + 0x31a00, 0x31a1c, + 0x31e00, 0x31e20, + 0x31e38, 0x31e3c, + 0x31e80, 0x31e80, + 0x31e88, 0x31ea8, + 0x31eb0, 0x31eb4, + 0x31ec8, 0x31ed4, + 0x31fb8, 0x32004, + 0x32200, 0x32200, + 0x32208, 0x32240, + 0x32248, 0x32280, + 0x32288, 0x322c0, + 0x322c8, 0x322fc, + 0x32600, 0x32630, + 0x32a00, 0x32abc, + 0x32b00, 0x32b10, + 0x32b20, 0x32b30, + 0x32b40, 0x32b50, + 0x32b60, 0x32b70, + 0x33000, 0x33028, + 0x33030, 0x33048, + 0x33060, 0x33068, + 0x33070, 0x3309c, + 0x330f0, 0x33128, + 0x33130, 0x33148, + 0x33160, 0x33168, + 0x33170, 0x3319c, + 0x331f0, 0x33238, + 0x33240, 0x33240, + 0x33248, 0x33250, + 0x3325c, 0x33264, + 0x33270, 0x332b8, + 0x332c0, 0x332e4, + 0x332f8, 0x33338, + 0x33340, 0x33340, + 0x33348, 0x33350, + 0x3335c, 0x33364, + 0x33370, 0x333b8, + 0x333c0, 0x333e4, + 0x333f8, 0x33428, + 0x33430, 0x33448, + 0x33460, 0x33468, + 0x33470, 0x3349c, + 0x334f0, 0x33528, + 0x33530, 0x33548, + 0x33560, 0x33568, + 0x33570, 0x3359c, + 0x335f0, 0x33638, + 0x33640, 0x33640, + 0x33648, 0x33650, + 0x3365c, 0x33664, + 0x33670, 0x336b8, + 0x336c0, 0x336e4, + 0x336f8, 0x33738, + 0x33740, 0x33740, + 0x33748, 0x33750, + 0x3375c, 0x33764, + 0x33770, 0x337b8, + 0x337c0, 0x337e4, + 0x337f8, 0x337fc, + 0x33814, 0x33814, + 0x3382c, 0x3382c, + 0x33880, 0x3388c, + 0x338e8, 0x338ec, + 0x33900, 0x33928, + 0x33930, 0x33948, + 0x33960, 0x33968, + 0x33970, 0x3399c, + 0x339f0, 0x33a38, + 0x33a40, 0x33a40, + 0x33a48, 0x33a50, + 0x33a5c, 0x33a64, + 0x33a70, 0x33ab8, + 0x33ac0, 0x33ae4, + 0x33af8, 0x33b10, + 0x33b28, 0x33b28, + 0x33b3c, 0x33b50, + 0x33bf0, 0x33c10, + 0x33c28, 0x33c28, + 0x33c3c, 0x33c50, + 0x33cf0, 0x33cfc, + 0x34000, 0x34030, + 0x34038, 0x34038, + 0x34040, 0x34040, + 0x34100, 0x34144, + 0x34190, 0x341a0, + 0x341a8, 0x341b8, + 0x341c4, 0x341c8, + 0x341d0, 0x341d0, + 0x34200, 0x34318, + 0x34400, 0x344b4, + 0x344c0, 0x3452c, + 0x34540, 0x3461c, + 0x34800, 0x34828, + 0x34834, 0x34834, + 0x348c0, 0x34908, + 0x34910, 0x349ac, + 0x34a00, 0x34a14, + 0x34a1c, 0x34a2c, + 0x34a44, 0x34a50, + 0x34a74, 0x34a74, + 0x34a7c, 0x34afc, + 0x34b08, 0x34c24, + 0x34d00, 0x34d00, + 0x34d08, 0x34d14, + 0x34d1c, 0x34d20, + 0x34d3c, 0x34d3c, + 0x34d48, 0x34d50, + 0x35200, 0x3520c, + 0x35220, 0x35220, + 0x35240, 0x35240, + 0x35600, 0x3560c, + 0x35a00, 0x35a1c, + 0x35e00, 0x35e20, + 0x35e38, 0x35e3c, + 0x35e80, 0x35e80, + 0x35e88, 0x35ea8, + 0x35eb0, 0x35eb4, + 0x35ec8, 0x35ed4, + 0x35fb8, 0x36004, + 0x36200, 0x36200, + 0x36208, 0x36240, + 0x36248, 0x36280, + 0x36288, 0x362c0, + 0x362c8, 0x362fc, + 0x36600, 0x36630, + 0x36a00, 0x36abc, + 0x36b00, 0x36b10, + 0x36b20, 0x36b30, + 0x36b40, 0x36b50, + 0x36b60, 0x36b70, + 0x37000, 0x37028, + 0x37030, 0x37048, + 0x37060, 0x37068, + 0x37070, 0x3709c, + 0x370f0, 0x37128, + 0x37130, 0x37148, + 0x37160, 0x37168, + 0x37170, 0x3719c, + 0x371f0, 0x37238, + 0x37240, 0x37240, + 0x37248, 0x37250, + 0x3725c, 0x37264, + 0x37270, 0x372b8, + 0x372c0, 0x372e4, + 0x372f8, 0x37338, + 0x37340, 0x37340, + 0x37348, 0x37350, + 0x3735c, 0x37364, + 0x37370, 0x373b8, + 0x373c0, 0x373e4, + 0x373f8, 0x37428, + 0x37430, 0x37448, + 0x37460, 0x37468, + 0x37470, 0x3749c, + 0x374f0, 0x37528, + 0x37530, 0x37548, + 0x37560, 0x37568, + 0x37570, 0x3759c, + 0x375f0, 0x37638, + 0x37640, 0x37640, + 0x37648, 0x37650, + 0x3765c, 0x37664, + 0x37670, 0x376b8, + 0x376c0, 0x376e4, + 0x376f8, 0x37738, + 0x37740, 0x37740, + 0x37748, 0x37750, + 0x3775c, 0x37764, + 0x37770, 0x377b8, + 0x377c0, 0x377e4, + 0x377f8, 0x377fc, + 0x37814, 0x37814, + 0x3782c, 0x3782c, + 0x37880, 0x3788c, + 0x378e8, 0x378ec, + 0x37900, 0x37928, + 0x37930, 0x37948, + 0x37960, 0x37968, + 0x37970, 0x3799c, + 0x379f0, 0x37a38, + 0x37a40, 0x37a40, + 0x37a48, 0x37a50, + 0x37a5c, 0x37a64, + 0x37a70, 0x37ab8, + 0x37ac0, 0x37ae4, + 0x37af8, 0x37b10, + 0x37b28, 0x37b28, + 0x37b3c, 0x37b50, + 0x37bf0, 0x37c10, + 0x37c28, 0x37c28, + 0x37c3c, 0x37c50, + 0x37cf0, 0x37cfc, + 0x38000, 0x38030, + 0x38038, 0x38038, + 0x38040, 0x38040, + 0x38100, 0x38144, + 0x38190, 0x381a0, + 0x381a8, 0x381b8, + 0x381c4, 0x381c8, + 0x381d0, 0x381d0, + 0x38200, 0x38318, + 0x38400, 0x384b4, + 0x384c0, 0x3852c, + 0x38540, 0x3861c, + 0x38800, 0x38828, + 0x38834, 0x38834, + 0x388c0, 0x38908, + 0x38910, 0x389ac, + 0x38a00, 0x38a14, + 0x38a1c, 0x38a2c, + 0x38a44, 0x38a50, + 0x38a74, 0x38a74, + 0x38a7c, 0x38afc, + 0x38b08, 0x38c24, + 0x38d00, 0x38d00, + 0x38d08, 0x38d14, + 0x38d1c, 0x38d20, + 0x38d3c, 0x38d3c, + 0x38d48, 0x38d50, + 0x39200, 0x3920c, + 0x39220, 0x39220, + 0x39240, 0x39240, + 0x39600, 0x3960c, + 0x39a00, 0x39a1c, + 0x39e00, 0x39e20, + 0x39e38, 0x39e3c, + 0x39e80, 0x39e80, + 0x39e88, 0x39ea8, + 0x39eb0, 0x39eb4, + 0x39ec8, 0x39ed4, + 0x39fb8, 0x3a004, + 0x3a200, 0x3a200, + 0x3a208, 0x3a240, + 0x3a248, 0x3a280, + 0x3a288, 0x3a2c0, + 0x3a2c8, 0x3a2fc, + 0x3a600, 0x3a630, + 0x3aa00, 0x3aabc, + 0x3ab00, 0x3ab10, + 0x3ab20, 0x3ab30, + 0x3ab40, 0x3ab50, + 0x3ab60, 0x3ab70, + 0x3b000, 0x3b028, + 0x3b030, 0x3b048, + 0x3b060, 0x3b068, + 0x3b070, 0x3b09c, + 0x3b0f0, 0x3b128, + 0x3b130, 0x3b148, + 0x3b160, 0x3b168, + 0x3b170, 0x3b19c, + 0x3b1f0, 0x3b238, + 0x3b240, 0x3b240, + 0x3b248, 0x3b250, + 0x3b25c, 0x3b264, + 0x3b270, 0x3b2b8, + 0x3b2c0, 0x3b2e4, + 0x3b2f8, 0x3b338, + 0x3b340, 0x3b340, + 0x3b348, 0x3b350, + 0x3b35c, 0x3b364, + 0x3b370, 0x3b3b8, + 0x3b3c0, 0x3b3e4, + 0x3b3f8, 0x3b428, + 0x3b430, 0x3b448, + 0x3b460, 0x3b468, + 0x3b470, 0x3b49c, + 0x3b4f0, 0x3b528, + 0x3b530, 0x3b548, + 0x3b560, 0x3b568, + 0x3b570, 0x3b59c, + 0x3b5f0, 0x3b638, + 0x3b640, 0x3b640, + 0x3b648, 0x3b650, + 0x3b65c, 0x3b664, + 0x3b670, 0x3b6b8, + 0x3b6c0, 0x3b6e4, + 0x3b6f8, 0x3b738, + 0x3b740, 0x3b740, + 0x3b748, 0x3b750, + 0x3b75c, 0x3b764, + 0x3b770, 0x3b7b8, + 0x3b7c0, 0x3b7e4, + 0x3b7f8, 0x3b7fc, + 0x3b814, 0x3b814, + 0x3b82c, 0x3b82c, + 0x3b880, 0x3b88c, + 0x3b8e8, 0x3b8ec, + 0x3b900, 0x3b928, + 0x3b930, 0x3b948, + 0x3b960, 0x3b968, + 0x3b970, 0x3b99c, + 0x3b9f0, 0x3ba38, + 0x3ba40, 0x3ba40, + 0x3ba48, 0x3ba50, + 0x3ba5c, 0x3ba64, + 0x3ba70, 0x3bab8, + 0x3bac0, 0x3bae4, + 0x3baf8, 0x3bb10, + 0x3bb28, 0x3bb28, + 0x3bb3c, 0x3bb50, + 0x3bbf0, 0x3bc10, + 0x3bc28, 0x3bc28, + 0x3bc3c, 0x3bc50, + 0x3bcf0, 0x3bcfc, + 0x3c000, 0x3c030, + 0x3c038, 0x3c038, + 0x3c040, 0x3c040, + 0x3c100, 0x3c144, + 0x3c190, 0x3c1a0, + 0x3c1a8, 0x3c1b8, + 0x3c1c4, 0x3c1c8, + 0x3c1d0, 0x3c1d0, + 0x3c200, 0x3c318, + 0x3c400, 0x3c4b4, + 0x3c4c0, 0x3c52c, + 0x3c540, 0x3c61c, + 0x3c800, 0x3c828, + 0x3c834, 0x3c834, + 0x3c8c0, 0x3c908, + 0x3c910, 0x3c9ac, + 0x3ca00, 0x3ca14, + 0x3ca1c, 0x3ca2c, + 0x3ca44, 0x3ca50, + 0x3ca74, 0x3ca74, + 0x3ca7c, 0x3cafc, + 0x3cb08, 0x3cc24, + 0x3cd00, 0x3cd00, + 0x3cd08, 0x3cd14, + 0x3cd1c, 0x3cd20, + 0x3cd3c, 0x3cd3c, + 0x3cd48, 0x3cd50, + 0x3d200, 0x3d20c, + 0x3d220, 0x3d220, + 0x3d240, 0x3d240, + 0x3d600, 0x3d60c, + 0x3da00, 0x3da1c, + 0x3de00, 0x3de20, + 0x3de38, 0x3de3c, + 0x3de80, 0x3de80, + 0x3de88, 0x3dea8, + 0x3deb0, 0x3deb4, + 0x3dec8, 0x3ded4, + 0x3dfb8, 0x3e004, + 0x3e200, 0x3e200, + 0x3e208, 0x3e240, + 0x3e248, 0x3e280, + 0x3e288, 0x3e2c0, + 0x3e2c8, 0x3e2fc, + 0x3e600, 0x3e630, + 0x3ea00, 0x3eabc, + 0x3eb00, 0x3eb10, + 0x3eb20, 0x3eb30, + 0x3eb40, 0x3eb50, + 0x3eb60, 0x3eb70, + 0x3f000, 0x3f028, + 0x3f030, 0x3f048, + 0x3f060, 0x3f068, + 0x3f070, 0x3f09c, + 0x3f0f0, 0x3f128, + 0x3f130, 0x3f148, + 0x3f160, 0x3f168, + 0x3f170, 0x3f19c, + 0x3f1f0, 0x3f238, + 0x3f240, 0x3f240, + 0x3f248, 0x3f250, + 0x3f25c, 0x3f264, + 0x3f270, 0x3f2b8, + 0x3f2c0, 0x3f2e4, + 0x3f2f8, 0x3f338, + 0x3f340, 0x3f340, + 0x3f348, 0x3f350, + 0x3f35c, 0x3f364, + 0x3f370, 0x3f3b8, + 0x3f3c0, 0x3f3e4, + 0x3f3f8, 0x3f428, + 0x3f430, 0x3f448, + 0x3f460, 0x3f468, + 0x3f470, 0x3f49c, + 0x3f4f0, 0x3f528, + 0x3f530, 0x3f548, + 0x3f560, 0x3f568, + 0x3f570, 0x3f59c, + 0x3f5f0, 0x3f638, + 0x3f640, 0x3f640, + 0x3f648, 0x3f650, + 0x3f65c, 0x3f664, + 0x3f670, 0x3f6b8, + 0x3f6c0, 0x3f6e4, + 0x3f6f8, 0x3f738, + 0x3f740, 0x3f740, + 0x3f748, 0x3f750, + 0x3f75c, 0x3f764, + 0x3f770, 0x3f7b8, + 0x3f7c0, 0x3f7e4, + 0x3f7f8, 0x3f7fc, + 0x3f814, 0x3f814, + 0x3f82c, 0x3f82c, + 0x3f880, 0x3f88c, + 0x3f8e8, 0x3f8ec, + 0x3f900, 0x3f928, + 0x3f930, 0x3f948, + 0x3f960, 0x3f968, + 0x3f970, 0x3f99c, + 0x3f9f0, 0x3fa38, + 0x3fa40, 0x3fa40, + 0x3fa48, 0x3fa50, + 0x3fa5c, 0x3fa64, + 0x3fa70, 0x3fab8, + 0x3fac0, 0x3fae4, + 0x3faf8, 0x3fb10, + 0x3fb28, 0x3fb28, + 0x3fb3c, 0x3fb50, + 0x3fbf0, 0x3fc10, + 0x3fc28, 0x3fc28, + 0x3fc3c, 0x3fc50, + 0x3fcf0, 0x3fcfc, + 0x40000, 0x4000c, + 0x40040, 0x40050, + 0x40060, 0x40068, + 0x4007c, 0x4008c, + 0x40094, 0x400b0, + 0x400c0, 0x40144, + 0x40180, 0x4018c, + 0x40200, 0x40254, + 0x40260, 0x40264, + 0x40270, 0x40288, + 0x40290, 0x40298, + 0x402ac, 0x402c8, + 0x402d0, 0x402e0, + 0x402f0, 0x402f0, + 0x40300, 0x4033c, + 0x403f8, 0x403fc, + 0x41304, 0x413c4, + 0x41400, 0x4140c, + 0x41414, 0x4141c, + 0x41480, 0x414d0, + 0x44000, 0x44054, + 0x4405c, 0x44078, + 0x440c0, 0x44174, + 0x44180, 0x441ac, + 0x441b4, 0x441b8, + 0x441c0, 0x44254, + 0x4425c, 0x44278, + 0x442c0, 0x44374, + 0x44380, 0x443ac, + 0x443b4, 0x443b8, + 0x443c0, 0x44454, + 0x4445c, 0x44478, + 0x444c0, 0x44574, + 0x44580, 0x445ac, + 0x445b4, 0x445b8, + 0x445c0, 0x44654, + 0x4465c, 0x44678, + 0x446c0, 0x44774, + 0x44780, 0x447ac, + 0x447b4, 0x447b8, + 0x447c0, 0x44854, + 0x4485c, 0x44878, + 0x448c0, 0x44974, + 0x44980, 0x449ac, + 0x449b4, 0x449b8, + 0x449c0, 0x449fc, + 0x45000, 0x45004, + 0x45010, 0x45030, + 0x45040, 0x45060, + 0x45068, 0x45068, + 0x45080, 0x45084, + 0x450a0, 0x450b0, + 0x45200, 0x45204, + 0x45210, 0x45230, + 0x45240, 0x45260, + 0x45268, 0x45268, + 0x45280, 0x45284, + 0x452a0, 0x452b0, + 0x460c0, 0x460e4, + 0x47000, 0x4703c, + 0x47044, 0x4708c, + 0x47200, 0x47250, + 0x47400, 0x47408, + 0x47414, 0x47420, + 0x47600, 0x47618, + 0x47800, 0x47814, + 0x48000, 0x4800c, + 0x48040, 0x48050, + 0x48060, 0x48068, + 0x4807c, 0x4808c, + 0x48094, 0x480b0, + 0x480c0, 0x48144, + 0x48180, 0x4818c, + 0x48200, 0x48254, + 0x48260, 0x48264, + 0x48270, 0x48288, + 0x48290, 0x48298, + 0x482ac, 0x482c8, + 0x482d0, 0x482e0, + 0x482f0, 0x482f0, + 0x48300, 0x4833c, + 0x483f8, 0x483fc, + 0x49304, 0x493c4, + 0x49400, 0x4940c, + 0x49414, 0x4941c, + 0x49480, 0x494d0, + 0x4c000, 0x4c054, + 0x4c05c, 0x4c078, + 0x4c0c0, 0x4c174, + 0x4c180, 0x4c1ac, + 0x4c1b4, 0x4c1b8, + 0x4c1c0, 0x4c254, + 0x4c25c, 0x4c278, + 0x4c2c0, 0x4c374, + 0x4c380, 0x4c3ac, + 0x4c3b4, 0x4c3b8, + 0x4c3c0, 0x4c454, + 0x4c45c, 0x4c478, + 0x4c4c0, 0x4c574, + 0x4c580, 0x4c5ac, + 0x4c5b4, 0x4c5b8, + 0x4c5c0, 0x4c654, + 0x4c65c, 0x4c678, + 0x4c6c0, 0x4c774, + 0x4c780, 0x4c7ac, + 0x4c7b4, 0x4c7b8, + 0x4c7c0, 0x4c854, + 0x4c85c, 0x4c878, + 0x4c8c0, 0x4c974, + 0x4c980, 0x4c9ac, + 0x4c9b4, 0x4c9b8, + 0x4c9c0, 0x4c9fc, + 0x4d000, 0x4d004, + 0x4d010, 0x4d030, + 0x4d040, 0x4d060, + 0x4d068, 0x4d068, + 0x4d080, 0x4d084, + 0x4d0a0, 0x4d0b0, + 0x4d200, 0x4d204, + 0x4d210, 0x4d230, + 0x4d240, 0x4d260, + 0x4d268, 0x4d268, + 0x4d280, 0x4d284, + 0x4d2a0, 0x4d2b0, + 0x4e0c0, 0x4e0e4, + 0x4f000, 0x4f03c, + 0x4f044, 0x4f08c, + 0x4f200, 0x4f250, + 0x4f400, 0x4f408, + 0x4f414, 0x4f420, + 0x4f600, 0x4f618, + 0x4f800, 0x4f814, + 0x50000, 0x50084, + 0x50090, 0x500cc, + 0x50400, 0x50400, + 0x50800, 0x50884, + 0x50890, 0x508cc, + 0x50c00, 0x50c00, + 0x51000, 0x5101c, + 0x51300, 0x51308, + }; + + static const unsigned int t6_reg_ranges[] = { + 0x1008, 0x101c, + 0x1024, 0x10a8, + 0x10b4, 0x10f8, + 0x1100, 0x1114, + 0x111c, 0x112c, + 0x1138, 0x113c, + 0x1144, 0x114c, + 0x1180, 0x1184, + 0x1190, 0x1194, + 0x11a0, 0x11a4, + 0x11b0, 0x11b4, + 0x11fc, 0x1274, + 0x1280, 0x133c, + 0x1800, 0x18fc, + 0x3000, 0x302c, + 0x3060, 0x30b0, + 0x30b8, 0x30d8, + 0x30e0, 0x30fc, + 0x3140, 0x357c, + 0x35a8, 0x35cc, + 0x35ec, 0x35ec, + 0x3600, 0x5624, + 0x56cc, 0x56ec, + 0x56f4, 0x5720, + 0x5728, 0x575c, + 0x580c, 0x5814, + 0x5890, 0x589c, + 0x58a4, 0x58ac, + 0x58b8, 0x58bc, + 0x5940, 0x595c, + 0x5980, 0x598c, + 0x59b0, 0x59c8, + 0x59d0, 0x59dc, + 0x59fc, 0x5a18, + 0x5a60, 0x5a6c, + 0x5a80, 0x5a8c, + 0x5a94, 0x5a9c, + 0x5b94, 0x5bfc, + 0x5c10, 0x5e48, + 0x5e50, 0x5e94, + 0x5ea0, 0x5eb0, + 0x5ec0, 0x5ec0, + 0x5ec8, 0x5ed0, + 0x5ee0, 0x5ee0, + 0x5ef0, 0x5ef0, + 0x5f00, 0x5f00, + 0x6000, 0x6020, + 0x6028, 0x6040, + 0x6058, 0x609c, + 0x60a8, 0x619c, + 0x7700, 0x7798, + 0x77c0, 0x7880, + 0x78cc, 0x78fc, + 0x7b00, 0x7b58, + 0x7b60, 0x7b84, + 0x7b8c, 0x7c54, + 0x7d00, 0x7d38, + 0x7d40, 0x7d84, + 0x7d8c, 0x7ddc, + 0x7de4, 0x7e04, + 0x7e10, 0x7e1c, + 0x7e24, 0x7e38, + 0x7e40, 0x7e44, + 0x7e4c, 0x7e78, + 0x7e80, 0x7edc, + 0x7ee8, 0x7efc, + 0x8dc0, 0x8de4, + 0x8df8, 0x8e04, + 0x8e10, 0x8e84, + 0x8ea0, 0x8f88, + 0x8fb8, 0x9058, + 0x9060, 0x9060, + 0x9068, 0x90f8, + 0x9100, 0x9124, + 0x9400, 0x9470, + 0x9600, 0x9600, + 0x9608, 0x9638, + 0x9640, 0x9704, + 0x9710, 0x971c, + 0x9800, 0x9808, + 0x9820, 0x983c, + 0x9850, 0x9864, + 0x9c00, 0x9c6c, + 0x9c80, 0x9cec, + 0x9d00, 0x9d6c, + 0x9d80, 0x9dec, + 0x9e00, 0x9e6c, + 0x9e80, 0x9eec, + 0x9f00, 0x9f6c, + 0x9f80, 0xa020, + 0xd004, 0xd03c, + 0xd100, 0xd118, + 0xd200, 0xd214, + 0xd220, 0xd234, + 0xd240, 0xd254, + 0xd260, 0xd274, + 0xd280, 0xd294, + 0xd2a0, 0xd2b4, + 0xd2c0, 0xd2d4, + 0xd2e0, 0xd2f4, + 0xd300, 0xd31c, + 0xdfc0, 0xdfe0, + 0xe000, 0xf008, + 0xf010, 0xf018, + 0xf020, 0xf028, + 0x11000, 0x11014, + 0x11048, 0x1106c, + 0x11074, 0x11088, + 0x11098, 0x11120, + 0x1112c, 0x1117c, + 0x11190, 0x112e0, + 0x11300, 0x1130c, + 0x12000, 0x1206c, + 0x19040, 0x1906c, + 0x19078, 0x19080, + 0x1908c, 0x190e8, + 0x190f0, 0x190f8, + 0x19100, 0x19110, + 0x19120, 0x19124, + 0x19150, 0x19194, + 0x1919c, 0x191b0, + 0x191d0, 0x191e8, + 0x19238, 0x19290, + 0x192a4, 0x192b0, + 0x192bc, 0x192bc, + 0x19348, 0x1934c, + 0x193f8, 0x19418, + 0x19420, 0x19428, + 0x19430, 0x19444, + 0x1944c, 0x1946c, + 0x19474, 0x19474, + 0x19490, 0x194cc, + 0x194f0, 0x194f8, + 0x19c00, 0x19c48, + 0x19c50, 0x19c80, + 0x19c94, 0x19c98, + 0x19ca0, 0x19cbc, + 0x19ce4, 0x19ce4, + 0x19cf0, 0x19cf8, + 0x19d00, 0x19d28, + 0x19d50, 0x19d78, + 0x19d94, 0x19d98, + 0x19da0, 0x19dc8, + 0x19df0, 0x19e10, + 0x19e50, 0x19e6c, + 0x19ea0, 0x19ebc, + 0x19ec4, 0x19ef4, + 0x19f04, 0x19f2c, + 0x19f34, 0x19f34, + 0x19f40, 0x19f50, + 0x19f90, 0x19fac, + 0x19fc4, 0x19fc8, + 0x19fd0, 0x19fe4, + 0x1a000, 0x1a004, + 0x1a010, 0x1a06c, + 0x1a0b0, 0x1a0e4, + 0x1a0ec, 0x1a0f8, + 0x1a100, 0x1a108, + 0x1a114, 0x1a120, + 0x1a128, 0x1a130, + 0x1a138, 0x1a138, + 0x1a190, 0x1a1c4, + 0x1a1fc, 0x1a1fc, + 0x1e008, 0x1e00c, + 0x1e040, 0x1e044, + 0x1e04c, 0x1e04c, + 0x1e284, 0x1e290, + 0x1e2c0, 0x1e2c0, + 0x1e2e0, 0x1e2e0, + 0x1e300, 0x1e384, + 0x1e3c0, 0x1e3c8, + 0x1e408, 0x1e40c, + 0x1e440, 0x1e444, + 0x1e44c, 0x1e44c, + 0x1e684, 0x1e690, + 0x1e6c0, 0x1e6c0, + 0x1e6e0, 0x1e6e0, + 0x1e700, 0x1e784, + 0x1e7c0, 0x1e7c8, + 0x1e808, 0x1e80c, + 0x1e840, 0x1e844, + 0x1e84c, 0x1e84c, + 0x1ea84, 0x1ea90, + 0x1eac0, 0x1eac0, + 0x1eae0, 0x1eae0, + 0x1eb00, 0x1eb84, + 0x1ebc0, 0x1ebc8, + 0x1ec08, 0x1ec0c, + 0x1ec40, 0x1ec44, + 0x1ec4c, 0x1ec4c, + 0x1ee84, 0x1ee90, + 0x1eec0, 0x1eec0, + 0x1eee0, 0x1eee0, + 0x1ef00, 0x1ef84, + 0x1efc0, 0x1efc8, + 0x1f008, 0x1f00c, + 0x1f040, 0x1f044, + 0x1f04c, 0x1f04c, + 0x1f284, 0x1f290, + 0x1f2c0, 0x1f2c0, + 0x1f2e0, 0x1f2e0, + 0x1f300, 0x1f384, + 0x1f3c0, 0x1f3c8, + 0x1f408, 0x1f40c, + 0x1f440, 0x1f444, + 0x1f44c, 0x1f44c, + 0x1f684, 0x1f690, + 0x1f6c0, 0x1f6c0, + 0x1f6e0, 0x1f6e0, + 0x1f700, 0x1f784, + 0x1f7c0, 0x1f7c8, + 0x1f808, 0x1f80c, + 0x1f840, 0x1f844, + 0x1f84c, 0x1f84c, + 0x1fa84, 0x1fa90, + 0x1fac0, 0x1fac0, + 0x1fae0, 0x1fae0, + 0x1fb00, 0x1fb84, + 0x1fbc0, 0x1fbc8, + 0x1fc08, 0x1fc0c, + 0x1fc40, 0x1fc44, + 0x1fc4c, 0x1fc4c, + 0x1fe84, 0x1fe90, + 0x1fec0, 0x1fec0, + 0x1fee0, 0x1fee0, + 0x1ff00, 0x1ff84, + 0x1ffc0, 0x1ffc8, + 0x30000, 0x30030, + 0x30038, 0x30038, + 0x30040, 0x30040, + 0x30048, 0x30048, + 0x30050, 0x30050, + 0x3005c, 0x30060, + 0x30068, 0x30068, + 0x30070, 0x30070, + 0x30100, 0x30168, + 0x30190, 0x301a0, + 0x301a8, 0x301b8, + 0x301c4, 0x301c8, + 0x301d0, 0x301d0, + 0x30200, 0x30320, + 0x30400, 0x304b4, + 0x304c0, 0x3052c, + 0x30540, 0x3061c, + 0x30800, 0x308a0, + 0x308c0, 0x30908, + 0x30910, 0x309b8, + 0x30a00, 0x30a04, + 0x30a0c, 0x30a14, + 0x30a1c, 0x30a2c, + 0x30a44, 0x30a50, + 0x30a74, 0x30a74, + 0x30a7c, 0x30afc, + 0x30b08, 0x30c24, + 0x30d00, 0x30d14, + 0x30d1c, 0x30d3c, + 0x30d44, 0x30d4c, + 0x30d54, 0x30d74, + 0x30d7c, 0x30d7c, + 0x30de0, 0x30de0, + 0x30e00, 0x30ed4, + 0x30f00, 0x30fa4, + 0x30fc0, 0x30fc4, + 0x31000, 0x31004, + 0x31080, 0x310fc, + 0x31208, 0x31220, + 0x3123c, 0x31254, + 0x31300, 0x31300, + 0x31308, 0x3131c, + 0x31338, 0x3133c, + 0x31380, 0x31380, + 0x31388, 0x313a8, + 0x313b4, 0x313b4, + 0x31400, 0x31420, + 0x31438, 0x3143c, + 0x31480, 0x31480, + 0x314a8, 0x314a8, + 0x314b0, 0x314b4, + 0x314c8, 0x314d4, + 0x31a40, 0x31a4c, + 0x31af0, 0x31b20, + 0x31b38, 0x31b3c, + 0x31b80, 0x31b80, + 0x31ba8, 0x31ba8, + 0x31bb0, 0x31bb4, + 0x31bc8, 0x31bd4, + 0x32140, 0x3218c, + 0x321f0, 0x321f4, + 0x32200, 0x32200, + 0x32218, 0x32218, + 0x32400, 0x32400, + 0x32408, 0x3241c, + 0x32618, 0x32620, + 0x32664, 0x32664, + 0x326a8, 0x326a8, + 0x326ec, 0x326ec, + 0x32a00, 0x32abc, + 0x32b00, 0x32b38, + 0x32b40, 0x32b58, + 0x32b60, 0x32b78, + 0x32c00, 0x32c00, + 0x32c08, 0x32c3c, + 0x32e00, 0x32e2c, + 0x32f00, 0x32f2c, + 0x33000, 0x3302c, + 0x33034, 0x33050, + 0x33058, 0x33058, + 0x33060, 0x3308c, + 0x3309c, 0x330ac, + 0x330c0, 0x330c0, + 0x330c8, 0x330d0, + 0x330d8, 0x330e0, + 0x330ec, 0x3312c, + 0x33134, 0x33150, + 0x33158, 0x33158, + 0x33160, 0x3318c, + 0x3319c, 0x331ac, + 0x331c0, 0x331c0, + 0x331c8, 0x331d0, + 0x331d8, 0x331e0, + 0x331ec, 0x33290, + 0x33298, 0x332c4, + 0x332e4, 0x33390, + 0x33398, 0x333c4, + 0x333e4, 0x3342c, + 0x33434, 0x33450, + 0x33458, 0x33458, + 0x33460, 0x3348c, + 0x3349c, 0x334ac, + 0x334c0, 0x334c0, + 0x334c8, 0x334d0, + 0x334d8, 0x334e0, + 0x334ec, 0x3352c, + 0x33534, 0x33550, + 0x33558, 0x33558, + 0x33560, 0x3358c, + 0x3359c, 0x335ac, + 0x335c0, 0x335c0, + 0x335c8, 0x335d0, + 0x335d8, 0x335e0, + 0x335ec, 0x33690, + 0x33698, 0x336c4, + 0x336e4, 0x33790, + 0x33798, 0x337c4, + 0x337e4, 0x337fc, + 0x33814, 0x33814, + 0x33854, 0x33868, + 0x33880, 0x3388c, + 0x338c0, 0x338d0, + 0x338e8, 0x338ec, + 0x33900, 0x3392c, + 0x33934, 0x33950, + 0x33958, 0x33958, + 0x33960, 0x3398c, + 0x3399c, 0x339ac, + 0x339c0, 0x339c0, + 0x339c8, 0x339d0, + 0x339d8, 0x339e0, + 0x339ec, 0x33a90, + 0x33a98, 0x33ac4, + 0x33ae4, 0x33b10, + 0x33b24, 0x33b28, + 0x33b38, 0x33b50, + 0x33bf0, 0x33c10, + 0x33c24, 0x33c28, + 0x33c38, 0x33c50, + 0x33cf0, 0x33cfc, + 0x34000, 0x34030, + 0x34038, 0x34038, + 0x34040, 0x34040, + 0x34048, 0x34048, + 0x34050, 0x34050, + 0x3405c, 0x34060, + 0x34068, 0x34068, + 0x34070, 0x34070, + 0x34100, 0x34168, + 0x34190, 0x341a0, + 0x341a8, 0x341b8, + 0x341c4, 0x341c8, + 0x341d0, 0x341d0, + 0x34200, 0x34320, + 0x34400, 0x344b4, + 0x344c0, 0x3452c, + 0x34540, 0x3461c, + 0x34800, 0x348a0, + 0x348c0, 0x34908, + 0x34910, 0x349b8, + 0x34a00, 0x34a04, + 0x34a0c, 0x34a14, + 0x34a1c, 0x34a2c, + 0x34a44, 0x34a50, + 0x34a74, 0x34a74, + 0x34a7c, 0x34afc, + 0x34b08, 0x34c24, + 0x34d00, 0x34d14, + 0x34d1c, 0x34d3c, + 0x34d44, 0x34d4c, + 0x34d54, 0x34d74, + 0x34d7c, 0x34d7c, + 0x34de0, 0x34de0, + 0x34e00, 0x34ed4, + 0x34f00, 0x34fa4, + 0x34fc0, 0x34fc4, + 0x35000, 0x35004, + 0x35080, 0x350fc, + 0x35208, 0x35220, + 0x3523c, 0x35254, + 0x35300, 0x35300, + 0x35308, 0x3531c, + 0x35338, 0x3533c, + 0x35380, 0x35380, + 0x35388, 0x353a8, + 0x353b4, 0x353b4, + 0x35400, 0x35420, + 0x35438, 0x3543c, + 0x35480, 0x35480, + 0x354a8, 0x354a8, + 0x354b0, 0x354b4, + 0x354c8, 0x354d4, + 0x35a40, 0x35a4c, + 0x35af0, 0x35b20, + 0x35b38, 0x35b3c, + 0x35b80, 0x35b80, + 0x35ba8, 0x35ba8, + 0x35bb0, 0x35bb4, + 0x35bc8, 0x35bd4, + 0x36140, 0x3618c, + 0x361f0, 0x361f4, + 0x36200, 0x36200, + 0x36218, 0x36218, + 0x36400, 0x36400, + 0x36408, 0x3641c, + 0x36618, 0x36620, + 0x36664, 0x36664, + 0x366a8, 0x366a8, + 0x366ec, 0x366ec, + 0x36a00, 0x36abc, + 0x36b00, 0x36b38, + 0x36b40, 0x36b58, + 0x36b60, 0x36b78, + 0x36c00, 0x36c00, + 0x36c08, 0x36c3c, + 0x36e00, 0x36e2c, + 0x36f00, 0x36f2c, + 0x37000, 0x3702c, + 0x37034, 0x37050, + 0x37058, 0x37058, + 0x37060, 0x3708c, + 0x3709c, 0x370ac, + 0x370c0, 0x370c0, + 0x370c8, 0x370d0, + 0x370d8, 0x370e0, + 0x370ec, 0x3712c, + 0x37134, 0x37150, + 0x37158, 0x37158, + 0x37160, 0x3718c, + 0x3719c, 0x371ac, + 0x371c0, 0x371c0, + 0x371c8, 0x371d0, + 0x371d8, 0x371e0, + 0x371ec, 0x37290, + 0x37298, 0x372c4, + 0x372e4, 0x37390, + 0x37398, 0x373c4, + 0x373e4, 0x3742c, + 0x37434, 0x37450, + 0x37458, 0x37458, + 0x37460, 0x3748c, + 0x3749c, 0x374ac, + 0x374c0, 0x374c0, + 0x374c8, 0x374d0, + 0x374d8, 0x374e0, + 0x374ec, 0x3752c, + 0x37534, 0x37550, + 0x37558, 0x37558, + 0x37560, 0x3758c, + 0x3759c, 0x375ac, + 0x375c0, 0x375c0, + 0x375c8, 0x375d0, + 0x375d8, 0x375e0, + 0x375ec, 0x37690, + 0x37698, 0x376c4, + 0x376e4, 0x37790, + 0x37798, 0x377c4, + 0x377e4, 0x377fc, + 0x37814, 0x37814, + 0x37854, 0x37868, + 0x37880, 0x3788c, + 0x378c0, 0x378d0, + 0x378e8, 0x378ec, + 0x37900, 0x3792c, + 0x37934, 0x37950, + 0x37958, 0x37958, + 0x37960, 0x3798c, + 0x3799c, 0x379ac, + 0x379c0, 0x379c0, + 0x379c8, 0x379d0, + 0x379d8, 0x379e0, + 0x379ec, 0x37a90, + 0x37a98, 0x37ac4, + 0x37ae4, 0x37b10, + 0x37b24, 0x37b28, + 0x37b38, 0x37b50, + 0x37bf0, 0x37c10, + 0x37c24, 0x37c28, + 0x37c38, 0x37c50, + 0x37cf0, 0x37cfc, + 0x40040, 0x40040, + 0x40080, 0x40084, + 0x40100, 0x40100, + 0x40140, 0x401bc, + 0x40200, 0x40214, + 0x40228, 0x40228, + 0x40240, 0x40258, + 0x40280, 0x40280, + 0x40304, 0x40304, + 0x40330, 0x4033c, + 0x41304, 0x413c8, + 0x413d0, 0x413dc, + 0x413f0, 0x413f0, + 0x41400, 0x4140c, + 0x41414, 0x4141c, + 0x41480, 0x414d0, + 0x44000, 0x4407c, + 0x440c0, 0x441ac, + 0x441b4, 0x4427c, + 0x442c0, 0x443ac, + 0x443b4, 0x4447c, + 0x444c0, 0x445ac, + 0x445b4, 0x4467c, + 0x446c0, 0x447ac, + 0x447b4, 0x4487c, + 0x448c0, 0x449ac, + 0x449b4, 0x44a7c, + 0x44ac0, 0x44bac, + 0x44bb4, 0x44c7c, + 0x44cc0, 0x44dac, + 0x44db4, 0x44e7c, + 0x44ec0, 0x44fac, + 0x44fb4, 0x4507c, + 0x450c0, 0x451ac, + 0x451b4, 0x451fc, + 0x45800, 0x45804, + 0x45810, 0x45830, + 0x45840, 0x45860, + 0x45868, 0x45868, + 0x45880, 0x45884, + 0x458a0, 0x458b0, + 0x45a00, 0x45a04, + 0x45a10, 0x45a30, + 0x45a40, 0x45a60, + 0x45a68, 0x45a68, + 0x45a80, 0x45a84, + 0x45aa0, 0x45ab0, + 0x460c0, 0x460e4, + 0x47000, 0x4703c, + 0x47044, 0x4708c, + 0x47200, 0x47250, + 0x47400, 0x47408, + 0x47414, 0x47420, + 0x47600, 0x47618, + 0x47800, 0x47814, + 0x47820, 0x4782c, + 0x50000, 0x50084, + 0x50090, 0x500cc, + 0x50300, 0x50384, + 0x50400, 0x50400, + 0x50800, 0x50884, + 0x50890, 0x508cc, + 0x50b00, 0x50b84, + 0x50c00, 0x50c00, + 0x51000, 0x51020, + 0x51028, 0x510b0, + 0x51300, 0x51324, + }; + + u32 *buf_end = (u32 *)(buf + buf_size); + const unsigned int *reg_ranges; + int reg_ranges_size, range; + unsigned int chip_version = chip_id(adap); + + /* + * Select the right set of register ranges to dump depending on the + * adapter chip type. + */ + switch (chip_version) { + case CHELSIO_T4: + reg_ranges = t4_reg_ranges; + reg_ranges_size = ARRAY_SIZE(t4_reg_ranges); + break; + + case CHELSIO_T5: + reg_ranges = t5_reg_ranges; + reg_ranges_size = ARRAY_SIZE(t5_reg_ranges); + break; + + case CHELSIO_T6: + reg_ranges = t6_reg_ranges; + reg_ranges_size = ARRAY_SIZE(t6_reg_ranges); + break; + + default: + CH_ERR(adap, + "Unsupported chip version %d\n", chip_version); + return; + } + + /* + * Clear the register buffer and insert the appropriate register + * values selected by the above register ranges. + */ + memset(buf, 0, buf_size); + for (range = 0; range < reg_ranges_size; range += 2) { + unsigned int reg = reg_ranges[range]; + unsigned int last_reg = reg_ranges[range + 1]; + u32 *bufp = (u32 *)(buf + reg); + + /* + * Iterate across the register range filling in the register + * buffer but don't write past the end of the register buffer. + */ + while (reg <= last_reg && bufp < buf_end) { + *bufp++ = t4_read_reg(adap, reg); + reg += sizeof(u32); + } + } +} + +/* * Partial EEPROM Vital Product Data structure. Includes only the ID and - * VPD-R header. + * VPD-R sections. */ struct t4_vpd_hdr { u8 id_tag; @@ -507,14 +2596,65 @@ struct t4_vpd_hdr { /* * EEPROM reads take a few tens of us while writes can take a bit over 5 ms. */ -#define EEPROM_MAX_RD_POLL 40 -#define EEPROM_MAX_WR_POLL 6 -#define EEPROM_STAT_ADDR 0x7bfc -#define VPD_BASE 0x400 -#define VPD_BASE_OLD 0 -#define VPD_LEN 1024 +#define EEPROM_DELAY 10 /* 10us per poll spin */ +#define EEPROM_MAX_POLL 5000 /* x 5000 == 50ms */ + +#define EEPROM_STAT_ADDR 0x7bfc +#define VPD_BASE 0x400 +#define VPD_BASE_OLD 0 +#define VPD_LEN 1024 #define VPD_INFO_FLD_HDR_SIZE 3 -#define CHELSIO_VPD_UNIQUE_ID 0x82 +#define CHELSIO_VPD_UNIQUE_ID 0x82 + +/* + * Small utility function to wait till any outstanding VPD Access is complete. + * We have a per-adapter state variable "VPD Busy" to indicate when we have a + * VPD Access in flight. This allows us to handle the problem of having a + * previous VPD Access time out and prevent an attempt to inject a new VPD + * Request before any in-flight VPD reguest has completed. + */ +static int t4_seeprom_wait(struct adapter *adapter) +{ + unsigned int base = adapter->params.pci.vpd_cap_addr; + int max_poll; + + /* + * If no VPD Access is in flight, we can just return success right + * away. + */ + if (!adapter->vpd_busy) + return 0; + + /* + * Poll the VPD Capability Address/Flag register waiting for it + * to indicate that the operation is complete. + */ + max_poll = EEPROM_MAX_POLL; + do { + u16 val; + + udelay(EEPROM_DELAY); + t4_os_pci_read_cfg2(adapter, base + PCI_VPD_ADDR, &val); + + /* + * If the operation is complete, mark the VPD as no longer + * busy and return success. + */ + if ((val & PCI_VPD_ADDR_F) == adapter->vpd_flag) { + adapter->vpd_busy = 0; + return 0; + } + } while (--max_poll); + + /* + * Failure! Note that we leave the VPD Busy status set in order to + * avoid pushing a new VPD Access request into the VPD Capability till + * the current operation eventually succeeds. It's a bug to issue a + * new request when an existing request is in flight and will result + * in corrupt hardware state. + */ + return -ETIMEDOUT; +} /** * t4_seeprom_read - read a serial EEPROM location @@ -528,23 +2668,44 @@ struct t4_vpd_hdr { */ int t4_seeprom_read(struct adapter *adapter, u32 addr, u32 *data) { - u16 val; - int attempts = EEPROM_MAX_RD_POLL; unsigned int base = adapter->params.pci.vpd_cap_addr; + int ret; + /* + * VPD Accesses must alway be 4-byte aligned! + */ if (addr >= EEPROMVSIZE || (addr & 3)) return -EINVAL; - t4_os_pci_write_cfg2(adapter, base + PCI_VPD_ADDR, (u16)addr); - do { - udelay(10); - t4_os_pci_read_cfg2(adapter, base + PCI_VPD_ADDR, &val); - } while (!(val & PCI_VPD_ADDR_F) && --attempts); + /* + * Wait for any previous operation which may still be in flight to + * complete. + */ + ret = t4_seeprom_wait(adapter); + if (ret) { + CH_ERR(adapter, "VPD still busy from previous operation\n"); + return ret; + } - if (!(val & PCI_VPD_ADDR_F)) { - CH_ERR(adapter, "reading EEPROM address 0x%x failed\n", addr); - return -EIO; + /* + * Issue our new VPD Read request, mark the VPD as being busy and wait + * for our request to complete. If it doesn't complete, note the + * error and return it to our caller. Note that we do not reset the + * VPD Busy status! + */ + t4_os_pci_write_cfg2(adapter, base + PCI_VPD_ADDR, (u16)addr); + adapter->vpd_busy = 1; + adapter->vpd_flag = PCI_VPD_ADDR_F; + ret = t4_seeprom_wait(adapter); + if (ret) { + CH_ERR(adapter, "VPD read of address %#x failed\n", addr); + return ret; } + + /* + * Grab the returned data, swizzle it into our endianess and + * return success. + */ t4_os_pci_read_cfg4(adapter, base + PCI_VPD_DATA, data); *data = le32_to_cpu(*data); return 0; @@ -562,26 +2723,59 @@ int t4_seeprom_read(struct adapter *adapter, u32 addr, u32 *data) */ int t4_seeprom_write(struct adapter *adapter, u32 addr, u32 data) { - u16 val; - int attempts = EEPROM_MAX_WR_POLL; unsigned int base = adapter->params.pci.vpd_cap_addr; + int ret; + u32 stats_reg; + int max_poll; + /* + * VPD Accesses must alway be 4-byte aligned! + */ if (addr >= EEPROMVSIZE || (addr & 3)) return -EINVAL; + /* + * Wait for any previous operation which may still be in flight to + * complete. + */ + ret = t4_seeprom_wait(adapter); + if (ret) { + CH_ERR(adapter, "VPD still busy from previous operation\n"); + return ret; + } + + /* + * Issue our new VPD Read request, mark the VPD as being busy and wait + * for our request to complete. If it doesn't complete, note the + * error and return it to our caller. Note that we do not reset the + * VPD Busy status! + */ t4_os_pci_write_cfg4(adapter, base + PCI_VPD_DATA, cpu_to_le32(data)); t4_os_pci_write_cfg2(adapter, base + PCI_VPD_ADDR, (u16)addr | PCI_VPD_ADDR_F); + adapter->vpd_busy = 1; + adapter->vpd_flag = 0; + ret = t4_seeprom_wait(adapter); + if (ret) { + CH_ERR(adapter, "VPD write of address %#x failed\n", addr); + return ret; + } + + /* + * Reset PCI_VPD_DATA register after a transaction and wait for our + * request to complete. If it doesn't complete, return error. + */ + t4_os_pci_write_cfg4(adapter, base + PCI_VPD_DATA, 0); + max_poll = EEPROM_MAX_POLL; do { - msleep(1); - t4_os_pci_read_cfg2(adapter, base + PCI_VPD_ADDR, &val); - } while ((val & PCI_VPD_ADDR_F) && --attempts); + udelay(EEPROM_DELAY); + t4_seeprom_read(adapter, EEPROM_STAT_ADDR, &stats_reg); + } while ((stats_reg & 0x1) && --max_poll); + if (!max_poll) + return -ETIMEDOUT; - if (val & PCI_VPD_ADDR_F) { - CH_ERR(adapter, "write to EEPROM address 0x%x failed\n", addr); - return -EIO; - } + /* Return success! */ return 0; } @@ -630,33 +2824,33 @@ int t4_seeprom_wp(struct adapter *adapter, int enable) * get_vpd_keyword_val - Locates an information field keyword in the VPD * @v: Pointer to buffered vpd data structure * @kw: The keyword to search for - * + * * Returns the value of the information field keyword or * -ENOENT otherwise. */ static int get_vpd_keyword_val(const struct t4_vpd_hdr *v, const char *kw) { - int i; - unsigned int offset , len; - const u8 *buf = &v->id_tag; - const u8 *vpdr_len = &v->vpdr_tag; - offset = sizeof(struct t4_vpd_hdr); - len = (u16)vpdr_len[1] + ((u16)vpdr_len[2] << 8); - - if (len + sizeof(struct t4_vpd_hdr) > VPD_LEN) { - return -ENOENT; - } + int i; + unsigned int offset , len; + const u8 *buf = (const u8 *)v; + const u8 *vpdr_len = &v->vpdr_len[0]; + offset = sizeof(struct t4_vpd_hdr); + len = (u16)vpdr_len[0] + ((u16)vpdr_len[1] << 8); + + if (len + sizeof(struct t4_vpd_hdr) > VPD_LEN) { + return -ENOENT; + } - for (i = offset; i + VPD_INFO_FLD_HDR_SIZE <= offset + len;) { - if(memcmp(buf + i , kw , 2) == 0){ - i += VPD_INFO_FLD_HDR_SIZE; - return i; - } + for (i = offset; i + VPD_INFO_FLD_HDR_SIZE <= offset + len;) { + if(memcmp(buf + i , kw , 2) == 0){ + i += VPD_INFO_FLD_HDR_SIZE; + return i; + } - i += VPD_INFO_FLD_HDR_SIZE + buf[i+2]; - } + i += VPD_INFO_FLD_HDR_SIZE + buf[i+2]; + } - return -ENOENT; + return -ENOENT; } @@ -664,14 +2858,16 @@ static int get_vpd_keyword_val(const struct t4_vpd_hdr *v, const char *kw) * get_vpd_params - read VPD parameters from VPD EEPROM * @adapter: adapter to read * @p: where to store the parameters + * @vpd: caller provided temporary space to read the VPD into * * Reads card parameters stored in VPD EEPROM. */ -static int get_vpd_params(struct adapter *adapter, struct vpd_params *p) +static int get_vpd_params(struct adapter *adapter, struct vpd_params *p, + u8 *vpd) { int i, ret, addr; int ec, sn, pn, na; - u8 vpd[VPD_LEN], csum; + u8 csum; const struct t4_vpd_hdr *v; /* @@ -679,31 +2875,43 @@ static int get_vpd_params(struct adapter *adapter, struct vpd_params *p) * it at 0. */ ret = t4_seeprom_read(adapter, VPD_BASE, (u32 *)(vpd)); + if (ret) + return (ret); + + /* + * The VPD shall have a unique identifier specified by the PCI SIG. + * For chelsio adapters, the identifier is 0x82. The first byte of a VPD + * shall be CHELSIO_VPD_UNIQUE_ID (0x82). The VPD programming software + * is expected to automatically put this entry at the + * beginning of the VPD. + */ addr = *vpd == CHELSIO_VPD_UNIQUE_ID ? VPD_BASE : VPD_BASE_OLD; - for (i = 0; i < sizeof(vpd); i += 4) { + for (i = 0; i < VPD_LEN; i += 4) { ret = t4_seeprom_read(adapter, addr + i, (u32 *)(vpd + i)); if (ret) return ret; } v = (const struct t4_vpd_hdr *)vpd; - + #define FIND_VPD_KW(var,name) do { \ var = get_vpd_keyword_val(v , name); \ if (var < 0) { \ CH_ERR(adapter, "missing VPD keyword " name "\n"); \ return -EINVAL; \ } \ -} while (0) +} while (0) FIND_VPD_KW(i, "RV"); for (csum = 0; i >= 0; i--) csum += vpd[i]; if (csum) { - CH_ERR(adapter, "corrupted VPD EEPROM, actual csum %u\n", csum); + CH_ERR(adapter, + "corrupted VPD EEPROM, actual csum %u\n", csum); return -EINVAL; } + FIND_VPD_KW(ec, "EC"); FIND_VPD_KW(sn, "SN"); FIND_VPD_KW(pn, "PN"); @@ -729,16 +2937,16 @@ static int get_vpd_params(struct adapter *adapter, struct vpd_params *p) /* serial flash and firmware constants and flash config file constants */ enum { - SF_ATTEMPTS = 10, /* max retries for SF operations */ + SF_ATTEMPTS = 10, /* max retries for SF operations */ /* flash command opcodes */ - SF_PROG_PAGE = 2, /* program page */ - SF_WR_DISABLE = 4, /* disable writes */ - SF_RD_STATUS = 5, /* read status register */ - SF_WR_ENABLE = 6, /* enable writes */ - SF_RD_DATA_FAST = 0xb, /* read flash */ - SF_RD_ID = 0x9f, /* read ID */ - SF_ERASE_SECTOR = 0xd8, /* erase sector */ + SF_PROG_PAGE = 2, /* program page */ + SF_WR_DISABLE = 4, /* disable writes */ + SF_RD_STATUS = 5, /* read status register */ + SF_WR_ENABLE = 6, /* enable writes */ + SF_RD_DATA_FAST = 0xb, /* read flash */ + SF_RD_ID = 0x9f, /* read ID */ + SF_ERASE_SECTOR = 0xd8, /* erase sector */ }; /** @@ -832,7 +3040,7 @@ static int flash_wait_op(struct adapter *adapter, int attempts, int delay) * Read the specified number of 32-bit words from the serial flash. * If @byte_oriented is set the read data is stored as a byte array * (i.e., big-endian), otherwise as 32-bit words in the platform's - * natural endianess. + * natural endianness. */ int t4_read_flash(struct adapter *adapter, unsigned int addr, unsigned int nwords, u32 *data, int byte_oriented) @@ -855,7 +3063,7 @@ int t4_read_flash(struct adapter *adapter, unsigned int addr, if (ret) return ret; if (byte_oriented) - *data = htonl(*data); + *data = (__force __u32)(cpu_to_be32(*data)); } return 0; } @@ -870,10 +3078,10 @@ int t4_read_flash(struct adapter *adapter, unsigned int addr, * * Writes up to a page of data (256 bytes) to the serial flash starting * at the given address. All the data must be written to the same page. - * If @byte_oriented is set the write data is stored as byte stream + * If @byte_oriented is set the write data is stored as byte stream * (i.e. matches what on disk), otherwise in big-endian. */ -static int t4_write_flash(struct adapter *adapter, unsigned int addr, +int t4_write_flash(struct adapter *adapter, unsigned int addr, unsigned int n, const u8 *data, int byte_oriented) { int ret; @@ -895,7 +3103,7 @@ static int t4_write_flash(struct adapter *adapter, unsigned int addr, val = (val << 8) + *data++; if (!byte_oriented) - val = htonl(val); + val = cpu_to_be32(val); ret = sf1_write(adapter, c, c != left, 1, val); if (ret) @@ -914,8 +3122,9 @@ static int t4_write_flash(struct adapter *adapter, unsigned int addr, return ret; if (memcmp(data - n, (u8 *)buf + offset, n)) { - CH_ERR(adapter, "failed to correctly write the flash page " - "at %#x\n", addr); + CH_ERR(adapter, + "failed to correctly write the flash page at %#x\n", + addr); return -EIO; } return 0; @@ -934,8 +3143,8 @@ unlock: */ int t4_get_fw_version(struct adapter *adapter, u32 *vers) { - return t4_read_flash(adapter, - FLASH_FW_START + offsetof(struct fw_hdr, fw_ver), 1, + return t4_read_flash(adapter, FLASH_FW_START + + offsetof(struct fw_hdr, fw_ver), 1, vers, 0); } @@ -948,63 +3157,46 @@ int t4_get_fw_version(struct adapter *adapter, u32 *vers) */ int t4_get_tp_version(struct adapter *adapter, u32 *vers) { - return t4_read_flash(adapter, FLASH_FW_START + offsetof(struct fw_hdr, - tp_microcode_ver), + return t4_read_flash(adapter, FLASH_FW_START + + offsetof(struct fw_hdr, tp_microcode_ver), 1, vers, 0); } /** - * t4_check_fw_version - check if the FW is compatible with this driver + * t4_get_exprom_version - return the Expansion ROM version (if any) * @adapter: the adapter + * @vers: where to place the version * - * Checks if an adapter's FW is compatible with the driver. Returns 0 - * if there's exact match, a negative error if the version could not be - * read or there's a major version mismatch, and a positive value if the - * expected major version is found but there's a minor version mismatch. + * Reads the Expansion ROM header from FLASH and returns the version + * number (if present) through the @vers return value pointer. We return + * this in the Firmware Version Format since it's convenient. Return + * 0 on success, -ENOENT if no Expansion ROM is present. */ -int t4_check_fw_version(struct adapter *adapter) +int t4_get_exprom_version(struct adapter *adap, u32 *vers) { - int ret, major, minor, micro; - int exp_major, exp_minor, exp_micro; + struct exprom_header { + unsigned char hdr_arr[16]; /* must start with 0x55aa */ + unsigned char hdr_ver[4]; /* Expansion ROM version */ + } *hdr; + u32 exprom_header_buf[DIV_ROUND_UP(sizeof(struct exprom_header), + sizeof(u32))]; + int ret; - ret = t4_get_fw_version(adapter, &adapter->params.fw_vers); - if (!ret) - ret = t4_get_tp_version(adapter, &adapter->params.tp_vers); + ret = t4_read_flash(adap, FLASH_EXP_ROM_START, + ARRAY_SIZE(exprom_header_buf), exprom_header_buf, + 0); if (ret) return ret; - major = G_FW_HDR_FW_VER_MAJOR(adapter->params.fw_vers); - minor = G_FW_HDR_FW_VER_MINOR(adapter->params.fw_vers); - micro = G_FW_HDR_FW_VER_MICRO(adapter->params.fw_vers); - - switch (chip_id(adapter)) { - case CHELSIO_T4: - exp_major = T4FW_VERSION_MAJOR; - exp_minor = T4FW_VERSION_MINOR; - exp_micro = T4FW_VERSION_MICRO; - break; - case CHELSIO_T5: - exp_major = T5FW_VERSION_MAJOR; - exp_minor = T5FW_VERSION_MINOR; - exp_micro = T5FW_VERSION_MICRO; - break; - default: - CH_ERR(adapter, "Unsupported chip type, %x\n", - chip_id(adapter)); - return -EINVAL; - } - - if (major != exp_major) { /* major mismatch - fail */ - CH_ERR(adapter, "card FW has major version %u, driver wants " - "%u\n", major, exp_major); - return -EINVAL; - } - - if (minor == exp_minor && micro == exp_micro) - return 0; /* perfect match */ + hdr = (struct exprom_header *)exprom_header_buf; + if (hdr->hdr_arr[0] != 0x55 || hdr->hdr_arr[1] != 0xaa) + return -ENOENT; - /* Minor/micro version mismatch. Report it but often it's OK. */ - return 1; + *vers = (V_FW_HDR_FW_VER_MAJOR(hdr->hdr_ver[0]) | + V_FW_HDR_FW_VER_MINOR(hdr->hdr_ver[1]) | + V_FW_HDR_FW_VER_MICRO(hdr->hdr_ver[2]) | + V_FW_HDR_FW_VER_BUILD(hdr->hdr_ver[3])); + return 0; } /** @@ -1015,17 +3207,21 @@ int t4_check_fw_version(struct adapter *adapter) * * Erases the sectors in the given inclusive range. */ -static int t4_flash_erase_sectors(struct adapter *adapter, int start, int end) +int t4_flash_erase_sectors(struct adapter *adapter, int start, int end) { int ret = 0; + if (end >= adapter->params.sf_nsec) + return -EINVAL; + while (start <= end) { if ((ret = sf1_write(adapter, 1, 0, 1, SF_WR_ENABLE)) != 0 || (ret = sf1_write(adapter, 4, 0, 1, SF_ERASE_SECTOR | (start << 8))) != 0 || (ret = flash_wait_op(adapter, 14, 500)) != 0) { - CH_ERR(adapter, "erase of flash sector %d failed, " - "error %d\n", start, ret); + CH_ERR(adapter, + "erase of flash sector %d failed, error %d\n", + start, ret); break; } start++; @@ -1054,67 +3250,30 @@ int t4_flash_cfg_addr(struct adapter *adapter) return FLASH_CFG_START; } -/** - * t4_load_cfg - download config file - * @adap: the adapter - * @cfg_data: the cfg text file to write - * @size: text file size - * - * Write the supplied config text file to the card's serial flash. +/* + * Return TRUE if the specified firmware matches the adapter. I.e. T4 + * firmware for T4 adapters, T5 firmware for T5 adapters, etc. We go ahead + * and emit an error message for mismatched firmware to save our caller the + * effort ... */ -int t4_load_cfg(struct adapter *adap, const u8 *cfg_data, unsigned int size) +static int t4_fw_matches_chip(struct adapter *adap, + const struct fw_hdr *hdr) { - int ret, i, n, cfg_addr; - unsigned int addr; - unsigned int flash_cfg_start_sec; - unsigned int sf_sec_size = adap->params.sf_size / adap->params.sf_nsec; - - cfg_addr = t4_flash_cfg_addr(adap); - if (cfg_addr < 0) - return cfg_addr; - - addr = cfg_addr; - flash_cfg_start_sec = addr / SF_SEC_SIZE; - - if (size > FLASH_CFG_MAX_SIZE) { - CH_ERR(adap, "cfg file too large, max is %u bytes\n", - FLASH_CFG_MAX_SIZE); - return -EFBIG; - } - - i = DIV_ROUND_UP(FLASH_CFG_MAX_SIZE, /* # of sectors spanned */ - sf_sec_size); - ret = t4_flash_erase_sectors(adap, flash_cfg_start_sec, - flash_cfg_start_sec + i - 1); /* - * If size == 0 then we're simply erasing the FLASH sectors associated - * with the on-adapter Firmware Configuration File. + * The expression below will return FALSE for any unsupported adapter + * which will keep us "honest" in the future ... */ - if (ret || size == 0) - goto out; - - /* this will write to the flash up to SF_PAGE_SIZE at a time */ - for (i = 0; i< size; i+= SF_PAGE_SIZE) { - if ( (size - i) < SF_PAGE_SIZE) - n = size - i; - else - n = SF_PAGE_SIZE; - ret = t4_write_flash(adap, addr, n, cfg_data, 1); - if (ret) - goto out; - - addr += SF_PAGE_SIZE; - cfg_data += SF_PAGE_SIZE; - } - -out: - if (ret) - CH_ERR(adap, "config file %s failed %d\n", - (size == 0 ? "clear" : "download"), ret); - return ret; + if ((is_t4(adap) && hdr->chip == FW_HDR_CHIP_T4) || + (is_t5(adap) && hdr->chip == FW_HDR_CHIP_T5) || + (is_t6(adap) && hdr->chip == FW_HDR_CHIP_T6)) + return 1; + + CH_ERR(adap, + "FW image (%d) is not suitable for this adapter (%d)\n", + hdr->chip, chip_id(adap)); + return 0; } - /** * t4_load_fw - download firmware * @adap: the adapter @@ -1145,40 +3304,39 @@ int t4_load_fw(struct adapter *adap, const u8 *fw_data, unsigned int size) fw_start = FLASH_FW_START; fw_size = FLASH_FW_MAX_SIZE; } + if (!size) { CH_ERR(adap, "FW image has no data\n"); return -EINVAL; } if (size & 511) { - CH_ERR(adap, "FW image size not multiple of 512 bytes\n"); + CH_ERR(adap, + "FW image size not multiple of 512 bytes\n"); return -EINVAL; } - if (ntohs(hdr->len512) * 512 != size) { - CH_ERR(adap, "FW image size differs from size in FW header\n"); + if ((unsigned int) be16_to_cpu(hdr->len512) * 512 != size) { + CH_ERR(adap, + "FW image size differs from size in FW header\n"); return -EINVAL; } if (size > fw_size) { - CH_ERR(adap, "FW image too large, max is %u bytes\n", fw_size); + CH_ERR(adap, "FW image too large, max is %u bytes\n", + fw_size); return -EFBIG; } - if ((is_t4(adap) && hdr->chip != FW_HDR_CHIP_T4) || - (is_t5(adap) && hdr->chip != FW_HDR_CHIP_T5)) { - CH_ERR(adap, - "FW image (%d) is not suitable for this adapter (%d)\n", - hdr->chip, chip_id(adap)); + if (!t4_fw_matches_chip(adap, hdr)) return -EINVAL; - } for (csum = 0, i = 0; i < size / sizeof(csum); i++) - csum += ntohl(p[i]); + csum += be32_to_cpu(p[i]); if (csum != 0xffffffff) { - CH_ERR(adap, "corrupted firmware image, checksum %#x\n", - csum); + CH_ERR(adap, + "corrupted firmware image, checksum %#x\n", csum); return -EINVAL; } - i = DIV_ROUND_UP(size, sf_sec_size); /* # of sectors spanned */ + i = DIV_ROUND_UP(size, sf_sec_size); /* # of sectors spanned */ ret = t4_flash_erase_sectors(adap, fw_start_sec, fw_start_sec + i - 1); if (ret) goto out; @@ -1189,7 +3347,7 @@ int t4_load_fw(struct adapter *adap, const u8 *fw_data, unsigned int size) * first page with a bad version. */ memcpy(first_page, fw_data, SF_PAGE_SIZE); - ((struct fw_hdr *)first_page)->fw_ver = htonl(0xffffffff); + ((struct fw_hdr *)first_page)->fw_ver = cpu_to_be32(0xffffffff); ret = t4_write_flash(adap, fw_start, SF_PAGE_SIZE, first_page, 1); if (ret) goto out; @@ -1208,541 +3366,33 @@ int t4_load_fw(struct adapter *adap, const u8 *fw_data, unsigned int size) sizeof(hdr->fw_ver), (const u8 *)&hdr->fw_ver, 1); out: if (ret) - CH_ERR(adap, "firmware download failed, error %d\n", ret); - return ret; -} - -/* BIOS boot headers */ -typedef struct pci_expansion_rom_header { - u8 signature[2]; /* ROM Signature. Should be 0xaa55 */ - u8 reserved[22]; /* Reserved per processor Architecture data */ - u8 pcir_offset[2]; /* Offset to PCI Data Structure */ -} pci_exp_rom_header_t; /* PCI_EXPANSION_ROM_HEADER */ - -/* Legacy PCI Expansion ROM Header */ -typedef struct legacy_pci_expansion_rom_header { - u8 signature[2]; /* ROM Signature. Should be 0xaa55 */ - u8 size512; /* Current Image Size in units of 512 bytes */ - u8 initentry_point[4]; - u8 cksum; /* Checksum computed on the entire Image */ - u8 reserved[16]; /* Reserved */ - u8 pcir_offset[2]; /* Offset to PCI Data Struture */ -} legacy_pci_exp_rom_header_t; /* LEGACY_PCI_EXPANSION_ROM_HEADER */ - -/* EFI PCI Expansion ROM Header */ -typedef struct efi_pci_expansion_rom_header { - u8 signature[2]; // ROM signature. The value 0xaa55 - u8 initialization_size[2]; /* Units 512. Includes this header */ - u8 efi_signature[4]; /* Signature from EFI image header. 0x0EF1 */ - u8 efi_subsystem[2]; /* Subsystem value for EFI image header */ - u8 efi_machine_type[2]; /* Machine type from EFI image header */ - u8 compression_type[2]; /* Compression type. */ - /* - * Compression type definition - * 0x0: uncompressed - * 0x1: Compressed - * 0x2-0xFFFF: Reserved - */ - u8 reserved[8]; /* Reserved */ - u8 efi_image_header_offset[2]; /* Offset to EFI Image */ - u8 pcir_offset[2]; /* Offset to PCI Data Structure */ -} efi_pci_exp_rom_header_t; /* EFI PCI Expansion ROM Header */ - -/* PCI Data Structure Format */ -typedef struct pcir_data_structure { /* PCI Data Structure */ - u8 signature[4]; /* Signature. The string "PCIR" */ - u8 vendor_id[2]; /* Vendor Identification */ - u8 device_id[2]; /* Device Identification */ - u8 vital_product[2]; /* Pointer to Vital Product Data */ - u8 length[2]; /* PCIR Data Structure Length */ - u8 revision; /* PCIR Data Structure Revision */ - u8 class_code[3]; /* Class Code */ - u8 image_length[2]; /* Image Length. Multiple of 512B */ - u8 code_revision[2]; /* Revision Level of Code/Data */ - u8 code_type; /* Code Type. */ - /* - * PCI Expansion ROM Code Types - * 0x00: Intel IA-32, PC-AT compatible. Legacy - * 0x01: Open Firmware standard for PCI. FCODE - * 0x02: Hewlett-Packard PA RISC. HP reserved - * 0x03: EFI Image. EFI - * 0x04-0xFF: Reserved. - */ - u8 indicator; /* Indicator. Identifies the last image in the ROM */ - u8 reserved[2]; /* Reserved */ -} pcir_data_t; /* PCI__DATA_STRUCTURE */ - -/* BOOT constants */ -enum { - BOOT_FLASH_BOOT_ADDR = 0x0,/* start address of boot image in flash */ - BOOT_SIGNATURE = 0xaa55, /* signature of BIOS boot ROM */ - BOOT_SIZE_INC = 512, /* image size measured in 512B chunks */ - BOOT_MIN_SIZE = sizeof(pci_exp_rom_header_t), /* basic header */ - BOOT_MAX_SIZE = 1024*BOOT_SIZE_INC, /* 1 byte * length increment */ - VENDOR_ID = 0x1425, /* Vendor ID */ - PCIR_SIGNATURE = 0x52494350 /* PCIR signature */ -}; - -/* - * modify_device_id - Modifies the device ID of the Boot BIOS image - * @adatper: the device ID to write. - * @boot_data: the boot image to modify. - * - * Write the supplied device ID to the boot BIOS image. - */ -static void modify_device_id(int device_id, u8 *boot_data) -{ - legacy_pci_exp_rom_header_t *header; - pcir_data_t *pcir_header; - u32 cur_header = 0; - - /* - * Loop through all chained images and change the device ID's - */ - while (1) { - header = (legacy_pci_exp_rom_header_t *) &boot_data[cur_header]; - pcir_header = (pcir_data_t *) &boot_data[cur_header + - le16_to_cpu(*(u16*)header->pcir_offset)]; - - /* - * Only modify the Device ID if code type is Legacy or HP. - * 0x00: Okay to modify - * 0x01: FCODE. Do not be modify - * 0x03: Okay to modify - * 0x04-0xFF: Do not modify - */ - if (pcir_header->code_type == 0x00) { - u8 csum = 0; - int i; - - /* - * Modify Device ID to match current adatper - */ - *(u16*) pcir_header->device_id = device_id; - - /* - * Set checksum temporarily to 0. - * We will recalculate it later. - */ - header->cksum = 0x0; - - /* - * Calculate and update checksum - */ - for (i = 0; i < (header->size512 * 512); i++) - csum += (u8)boot_data[cur_header + i]; - - /* - * Invert summed value to create the checksum - * Writing new checksum value directly to the boot data - */ - boot_data[cur_header + 7] = -csum; - - } else if (pcir_header->code_type == 0x03) { - - /* - * Modify Device ID to match current adatper - */ - *(u16*) pcir_header->device_id = device_id; - - } - - - /* - * Check indicator element to identify if this is the last - * image in the ROM. - */ - if (pcir_header->indicator & 0x80) - break; - - /* - * Move header pointer up to the next image in the ROM. - */ - cur_header += header->size512 * 512; - } -} - -/* - * t4_load_boot - download boot flash - * @adapter: the adapter - * @boot_data: the boot image to write - * @boot_addr: offset in flash to write boot_data - * @size: image size - * - * Write the supplied boot image to the card's serial flash. - * The boot image has the following sections: a 28-byte header and the - * boot image. - */ -int t4_load_boot(struct adapter *adap, u8 *boot_data, - unsigned int boot_addr, unsigned int size) -{ - pci_exp_rom_header_t *header; - int pcir_offset ; - pcir_data_t *pcir_header; - int ret, addr; - uint16_t device_id; - unsigned int i; - unsigned int boot_sector = boot_addr * 1024; - unsigned int sf_sec_size = adap->params.sf_size / adap->params.sf_nsec; - - /* - * Make sure the boot image does not encroach on the firmware region - */ - if ((boot_sector + size) >> 16 > FLASH_FW_START_SEC) { - CH_ERR(adap, "boot image encroaching on firmware region\n"); - return -EFBIG; - } - - /* - * Number of sectors spanned - */ - i = DIV_ROUND_UP(size ? size : FLASH_BOOTCFG_MAX_SIZE, - sf_sec_size); - ret = t4_flash_erase_sectors(adap, boot_sector >> 16, - (boot_sector >> 16) + i - 1); - - /* - * If size == 0 then we're simply erasing the FLASH sectors associated - * with the on-adapter option ROM file - */ - if (ret || (size == 0)) - goto out; - - /* Get boot header */ - header = (pci_exp_rom_header_t *)boot_data; - pcir_offset = le16_to_cpu(*(u16 *)header->pcir_offset); - /* PCIR Data Structure */ - pcir_header = (pcir_data_t *) &boot_data[pcir_offset]; - - /* - * Perform some primitive sanity testing to avoid accidentally - * writing garbage over the boot sectors. We ought to check for - * more but it's not worth it for now ... - */ - if (size < BOOT_MIN_SIZE || size > BOOT_MAX_SIZE) { - CH_ERR(adap, "boot image too small/large\n"); - return -EFBIG; - } - - /* - * Check BOOT ROM header signature - */ - if (le16_to_cpu(*(u16*)header->signature) != BOOT_SIGNATURE ) { - CH_ERR(adap, "Boot image missing signature\n"); - return -EINVAL; - } - - /* - * Check PCI header signature - */ - if (le32_to_cpu(*(u32*)pcir_header->signature) != PCIR_SIGNATURE) { - CH_ERR(adap, "PCI header missing signature\n"); - return -EINVAL; - } - - /* - * Check Vendor ID matches Chelsio ID - */ - if (le16_to_cpu(*(u16*)pcir_header->vendor_id) != VENDOR_ID) { - CH_ERR(adap, "Vendor ID missing signature\n"); - return -EINVAL; - } - - /* - * Retrieve adapter's device ID - */ - t4_os_pci_read_cfg2(adap, PCI_DEVICE_ID, &device_id); - /* Want to deal with PF 0 so I strip off PF 4 indicator */ - device_id = (device_id & 0xff) | 0x4000; - - /* - * Check PCIE Device ID - */ - if (le16_to_cpu(*(u16*)pcir_header->device_id) != device_id) { - /* - * Change the device ID in the Boot BIOS image to match - * the Device ID of the current adapter. - */ - modify_device_id(device_id, boot_data); - } - - /* - * Skip over the first SF_PAGE_SIZE worth of data and write it after - * we finish copying the rest of the boot image. This will ensure - * that the BIOS boot header will only be written if the boot image - * was written in full. - */ - addr = boot_sector; - for (size -= SF_PAGE_SIZE; size; size -= SF_PAGE_SIZE) { - addr += SF_PAGE_SIZE; - boot_data += SF_PAGE_SIZE; - ret = t4_write_flash(adap, addr, SF_PAGE_SIZE, boot_data, 0); - if (ret) - goto out; - } - - ret = t4_write_flash(adap, boot_sector, SF_PAGE_SIZE, boot_data, 0); - -out: - if (ret) - CH_ERR(adap, "boot image download failed, error %d\n", ret); + CH_ERR(adap, "firmware download failed, error %d\n", + ret); return ret; } /** - * t4_read_cimq_cfg - read CIM queue configuration + * t4_fwcache - firmware cache operation * @adap: the adapter - * @base: holds the queue base addresses in bytes - * @size: holds the queue sizes in bytes - * @thres: holds the queue full thresholds in bytes - * - * Returns the current configuration of the CIM queues, starting with - * the IBQs, then the OBQs. + * @op : the operation (flush or flush and invalidate) */ -void t4_read_cimq_cfg(struct adapter *adap, u16 *base, u16 *size, u16 *thres) +int t4_fwcache(struct adapter *adap, enum fw_params_param_dev_fwcache op) { - unsigned int i, v; - int cim_num_obq = is_t4(adap) ? CIM_NUM_OBQ : CIM_NUM_OBQ_T5; - - for (i = 0; i < CIM_NUM_IBQ; i++) { - t4_write_reg(adap, A_CIM_QUEUE_CONFIG_REF, F_IBQSELECT | - V_QUENUMSELECT(i)); - v = t4_read_reg(adap, A_CIM_QUEUE_CONFIG_CTRL); - *base++ = G_CIMQBASE(v) * 256; /* value is in 256-byte units */ - *size++ = G_CIMQSIZE(v) * 256; /* value is in 256-byte units */ - *thres++ = G_QUEFULLTHRSH(v) * 8; /* 8-byte unit */ - } - for (i = 0; i < cim_num_obq; i++) { - t4_write_reg(adap, A_CIM_QUEUE_CONFIG_REF, F_OBQSELECT | - V_QUENUMSELECT(i)); - v = t4_read_reg(adap, A_CIM_QUEUE_CONFIG_CTRL); - *base++ = G_CIMQBASE(v) * 256; /* value is in 256-byte units */ - *size++ = G_CIMQSIZE(v) * 256; /* value is in 256-byte units */ - } -} - -/** - * t4_read_cim_ibq - read the contents of a CIM inbound queue - * @adap: the adapter - * @qid: the queue index - * @data: where to store the queue contents - * @n: capacity of @data in 32-bit words - * - * Reads the contents of the selected CIM queue starting at address 0 up - * to the capacity of @data. @n must be a multiple of 4. Returns < 0 on - * error and the number of 32-bit words actually read on success. - */ -int t4_read_cim_ibq(struct adapter *adap, unsigned int qid, u32 *data, size_t n) -{ - int i, err; - unsigned int addr; - const unsigned int nwords = CIM_IBQ_SIZE * 4; - - if (qid > 5 || (n & 3)) - return -EINVAL; - - addr = qid * nwords; - if (n > nwords) - n = nwords; - - for (i = 0; i < n; i++, addr++) { - t4_write_reg(adap, A_CIM_IBQ_DBG_CFG, V_IBQDBGADDR(addr) | - F_IBQDBGEN); - /* - * It might take 3-10ms before the IBQ debug read access is - * allowed. Wait for 1 Sec with a delay of 1 usec. - */ - err = t4_wait_op_done(adap, A_CIM_IBQ_DBG_CFG, F_IBQDBGBUSY, 0, - 1000000, 1); - if (err) - return err; - *data++ = t4_read_reg(adap, A_CIM_IBQ_DBG_DATA); - } - t4_write_reg(adap, A_CIM_IBQ_DBG_CFG, 0); - return i; -} - -/** - * t4_read_cim_obq - read the contents of a CIM outbound queue - * @adap: the adapter - * @qid: the queue index - * @data: where to store the queue contents - * @n: capacity of @data in 32-bit words - * - * Reads the contents of the selected CIM queue starting at address 0 up - * to the capacity of @data. @n must be a multiple of 4. Returns < 0 on - * error and the number of 32-bit words actually read on success. - */ -int t4_read_cim_obq(struct adapter *adap, unsigned int qid, u32 *data, size_t n) -{ - int i, err; - unsigned int addr, v, nwords; - int cim_num_obq = is_t4(adap) ? CIM_NUM_OBQ : CIM_NUM_OBQ_T5; - - if (qid >= cim_num_obq || (n & 3)) - return -EINVAL; - - t4_write_reg(adap, A_CIM_QUEUE_CONFIG_REF, F_OBQSELECT | - V_QUENUMSELECT(qid)); - v = t4_read_reg(adap, A_CIM_QUEUE_CONFIG_CTRL); - - addr = G_CIMQBASE(v) * 64; /* muliple of 256 -> muliple of 4 */ - nwords = G_CIMQSIZE(v) * 64; /* same */ - if (n > nwords) - n = nwords; - - for (i = 0; i < n; i++, addr++) { - t4_write_reg(adap, A_CIM_OBQ_DBG_CFG, V_OBQDBGADDR(addr) | - F_OBQDBGEN); - err = t4_wait_op_done(adap, A_CIM_OBQ_DBG_CFG, F_OBQDBGBUSY, 0, - 2, 1); - if (err) - return err; - *data++ = t4_read_reg(adap, A_CIM_OBQ_DBG_DATA); - } - t4_write_reg(adap, A_CIM_OBQ_DBG_CFG, 0); - return i; -} - -enum { - CIM_QCTL_BASE = 0, - CIM_CTL_BASE = 0x2000, - CIM_PBT_ADDR_BASE = 0x2800, - CIM_PBT_LRF_BASE = 0x3000, - CIM_PBT_DATA_BASE = 0x3800 -}; - -/** - * t4_cim_read - read a block from CIM internal address space - * @adap: the adapter - * @addr: the start address within the CIM address space - * @n: number of words to read - * @valp: where to store the result - * - * Reads a block of 4-byte words from the CIM intenal address space. - */ -int t4_cim_read(struct adapter *adap, unsigned int addr, unsigned int n, - unsigned int *valp) -{ - int ret = 0; - - if (t4_read_reg(adap, A_CIM_HOST_ACC_CTRL) & F_HOSTBUSY) - return -EBUSY; - - for ( ; !ret && n--; addr += 4) { - t4_write_reg(adap, A_CIM_HOST_ACC_CTRL, addr); - ret = t4_wait_op_done(adap, A_CIM_HOST_ACC_CTRL, F_HOSTBUSY, - 0, 5, 2); - if (!ret) - *valp++ = t4_read_reg(adap, A_CIM_HOST_ACC_DATA); - } - return ret; -} - -/** - * t4_cim_write - write a block into CIM internal address space - * @adap: the adapter - * @addr: the start address within the CIM address space - * @n: number of words to write - * @valp: set of values to write - * - * Writes a block of 4-byte words into the CIM intenal address space. - */ -int t4_cim_write(struct adapter *adap, unsigned int addr, unsigned int n, - const unsigned int *valp) -{ - int ret = 0; - - if (t4_read_reg(adap, A_CIM_HOST_ACC_CTRL) & F_HOSTBUSY) - return -EBUSY; - - for ( ; !ret && n--; addr += 4) { - t4_write_reg(adap, A_CIM_HOST_ACC_DATA, *valp++); - t4_write_reg(adap, A_CIM_HOST_ACC_CTRL, addr | F_HOSTWRITE); - ret = t4_wait_op_done(adap, A_CIM_HOST_ACC_CTRL, F_HOSTBUSY, - 0, 5, 2); - } - return ret; -} - -static int t4_cim_write1(struct adapter *adap, unsigned int addr, unsigned int val) -{ - return t4_cim_write(adap, addr, 1, &val); -} - -/** - * t4_cim_ctl_read - read a block from CIM control region - * @adap: the adapter - * @addr: the start address within the CIM control region - * @n: number of words to read - * @valp: where to store the result - * - * Reads a block of 4-byte words from the CIM control region. - */ -int t4_cim_ctl_read(struct adapter *adap, unsigned int addr, unsigned int n, - unsigned int *valp) -{ - return t4_cim_read(adap, addr + CIM_CTL_BASE, n, valp); -} - -/** - * t4_cim_read_la - read CIM LA capture buffer - * @adap: the adapter - * @la_buf: where to store the LA data - * @wrptr: the HW write pointer within the capture buffer - * - * Reads the contents of the CIM LA buffer with the most recent entry at - * the end of the returned data and with the entry at @wrptr first. - * We try to leave the LA in the running state we find it in. - */ -int t4_cim_read_la(struct adapter *adap, u32 *la_buf, unsigned int *wrptr) -{ - int i, ret; - unsigned int cfg, val, idx; - - ret = t4_cim_read(adap, A_UP_UP_DBG_LA_CFG, 1, &cfg); - if (ret) - return ret; - - if (cfg & F_UPDBGLAEN) { /* LA is running, freeze it */ - ret = t4_cim_write1(adap, A_UP_UP_DBG_LA_CFG, 0); - if (ret) - return ret; - } - - ret = t4_cim_read(adap, A_UP_UP_DBG_LA_CFG, 1, &val); - if (ret) - goto restart; + struct fw_params_cmd c; - idx = G_UPDBGLAWRPTR(val); - if (wrptr) - *wrptr = idx; + memset(&c, 0, sizeof(c)); + c.op_to_vfn = + cpu_to_be32(V_FW_CMD_OP(FW_PARAMS_CMD) | + F_FW_CMD_REQUEST | F_FW_CMD_WRITE | + V_FW_PARAMS_CMD_PFN(adap->pf) | + V_FW_PARAMS_CMD_VFN(0)); + c.retval_len16 = cpu_to_be32(FW_LEN16(c)); + c.param[0].mnem = + cpu_to_be32(V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | + V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_FWCACHE)); + c.param[0].val = (__force __be32)op; - for (i = 0; i < adap->params.cim_la_size; i++) { - ret = t4_cim_write1(adap, A_UP_UP_DBG_LA_CFG, - V_UPDBGLARDPTR(idx) | F_UPDBGLARDEN); - if (ret) - break; - ret = t4_cim_read(adap, A_UP_UP_DBG_LA_CFG, 1, &val); - if (ret) - break; - if (val & F_UPDBGLARDEN) { - ret = -ETIMEDOUT; - break; - } - ret = t4_cim_read(adap, A_UP_UP_DBG_LA_DATA, 1, &la_buf[i]); - if (ret) - break; - idx = (idx + 1) & M_UPDBGLARDPTR; - } -restart: - if (cfg & F_UPDBGLAEN) { - int r = t4_cim_write1(adap, A_UP_UP_DBG_LA_CFG, - cfg & ~F_UPDBGLARDEN); - if (!ret) - ret = r; - } - return ret; + return t4_wr_mbox(adap, adap->mbox, &c, sizeof(c), NULL); } void t4_cim_read_pif_la(struct adapter *adap, u32 *pif_req, u32 *pif_rsp, @@ -1800,53 +3450,6 @@ void t4_cim_read_ma_la(struct adapter *adap, u32 *ma_req, u32 *ma_rsp) t4_write_reg(adap, A_CIM_DEBUGCFG, cfg); } -/** - * t4_tp_read_la - read TP LA capture buffer - * @adap: the adapter - * @la_buf: where to store the LA data - * @wrptr: the HW write pointer within the capture buffer - * - * Reads the contents of the TP LA buffer with the most recent entry at - * the end of the returned data and with the entry at @wrptr first. - * We leave the LA in the running state we find it in. - */ -void t4_tp_read_la(struct adapter *adap, u64 *la_buf, unsigned int *wrptr) -{ - bool last_incomplete; - unsigned int i, cfg, val, idx; - - cfg = t4_read_reg(adap, A_TP_DBG_LA_CONFIG) & 0xffff; - if (cfg & F_DBGLAENABLE) /* freeze LA */ - t4_write_reg(adap, A_TP_DBG_LA_CONFIG, - adap->params.tp.la_mask | (cfg ^ F_DBGLAENABLE)); - - val = t4_read_reg(adap, A_TP_DBG_LA_CONFIG); - idx = G_DBGLAWPTR(val); - last_incomplete = G_DBGLAMODE(val) >= 2 && (val & F_DBGLAWHLF) == 0; - if (last_incomplete) - idx = (idx + 1) & M_DBGLARPTR; - if (wrptr) - *wrptr = idx; - - val &= 0xffff; - val &= ~V_DBGLARPTR(M_DBGLARPTR); - val |= adap->params.tp.la_mask; - - for (i = 0; i < TPLA_SIZE; i++) { - t4_write_reg(adap, A_TP_DBG_LA_CONFIG, V_DBGLARPTR(idx) | val); - la_buf[i] = t4_read_reg64(adap, A_TP_DBG_LA_DATAL); - idx = (idx + 1) & M_DBGLARPTR; - } - - /* Wipe out last entry if it isn't valid */ - if (last_incomplete) - la_buf[TPLA_SIZE - 1] = ~0ULL; - - if (cfg & F_DBGLAENABLE) /* restore running state */ - t4_write_reg(adap, A_TP_DBG_LA_CONFIG, - cfg | adap->params.tp.la_mask); -} - void t4_ulprx_read_la(struct adapter *adap, u32 *la_buf) { unsigned int i, j; @@ -1867,7 +3470,7 @@ void t4_ulprx_read_la(struct adapter *adap, u32 *la_buf) FW_PORT_CAP_SPEED_100G | FW_PORT_CAP_ANEG) /** - * t4_link_start - apply link configuration to MAC/PHY + * t4_link_l1cfg - apply link configuration to MAC/PHY * @phy: the PHY to setup * @mac: the MAC to setup * @lc: the requested link configuration @@ -1879,7 +3482,7 @@ void t4_ulprx_read_la(struct adapter *adap, u32 *la_buf) * - If auto-negotiation is off set the MAC to the proper speed/duplex/FC, * otherwise do it later based on the outcome of auto-negotiation. */ -int t4_link_start(struct adapter *adap, unsigned int mbox, unsigned int port, +int t4_link_l1cfg(struct adapter *adap, unsigned int mbox, unsigned int port, struct link_config *lc) { struct fw_port_cmd c; @@ -1892,19 +3495,22 @@ int t4_link_start(struct adapter *adap, unsigned int mbox, unsigned int port, fc |= FW_PORT_CAP_FC_TX; memset(&c, 0, sizeof(c)); - c.op_to_portid = htonl(V_FW_CMD_OP(FW_PORT_CMD) | F_FW_CMD_REQUEST | - F_FW_CMD_EXEC | V_FW_PORT_CMD_PORTID(port)); - c.action_to_len16 = htonl(V_FW_PORT_CMD_ACTION(FW_PORT_ACTION_L1_CFG) | - FW_LEN16(c)); + c.op_to_portid = cpu_to_be32(V_FW_CMD_OP(FW_PORT_CMD) | + F_FW_CMD_REQUEST | F_FW_CMD_EXEC | + V_FW_PORT_CMD_PORTID(port)); + c.action_to_len16 = + cpu_to_be32(V_FW_PORT_CMD_ACTION(FW_PORT_ACTION_L1_CFG) | + FW_LEN16(c)); if (!(lc->supported & FW_PORT_CAP_ANEG)) { - c.u.l1cfg.rcap = htonl((lc->supported & ADVERT_MASK) | fc); + c.u.l1cfg.rcap = cpu_to_be32((lc->supported & ADVERT_MASK) | + fc); lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX); } else if (lc->autoneg == AUTONEG_DISABLE) { - c.u.l1cfg.rcap = htonl(lc->requested_speed | fc | mdi); + c.u.l1cfg.rcap = cpu_to_be32(lc->requested_speed | fc | mdi); lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX); } else - c.u.l1cfg.rcap = htonl(lc->advertising | fc | mdi); + c.u.l1cfg.rcap = cpu_to_be32(lc->advertising | fc | mdi); return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); } @@ -1922,19 +3528,24 @@ int t4_restart_aneg(struct adapter *adap, unsigned int mbox, unsigned int port) struct fw_port_cmd c; memset(&c, 0, sizeof(c)); - c.op_to_portid = htonl(V_FW_CMD_OP(FW_PORT_CMD) | F_FW_CMD_REQUEST | - F_FW_CMD_EXEC | V_FW_PORT_CMD_PORTID(port)); - c.action_to_len16 = htonl(V_FW_PORT_CMD_ACTION(FW_PORT_ACTION_L1_CFG) | - FW_LEN16(c)); - c.u.l1cfg.rcap = htonl(FW_PORT_CAP_ANEG); + c.op_to_portid = cpu_to_be32(V_FW_CMD_OP(FW_PORT_CMD) | + F_FW_CMD_REQUEST | F_FW_CMD_EXEC | + V_FW_PORT_CMD_PORTID(port)); + c.action_to_len16 = + cpu_to_be32(V_FW_PORT_CMD_ACTION(FW_PORT_ACTION_L1_CFG) | + FW_LEN16(c)); + c.u.l1cfg.rcap = cpu_to_be32(FW_PORT_CAP_ANEG); return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); } +typedef void (*int_handler_t)(struct adapter *adap); + struct intr_info { - unsigned int mask; /* bits to check in interrupt status */ - const char *msg; /* message to print or NULL */ - short stat_idx; /* stat counter to increment or -1 */ - unsigned short fatal; /* whether the condition reported is fatal */ + unsigned int mask; /* bits to check in interrupt status */ + const char *msg; /* message to print or NULL */ + short stat_idx; /* stat counter to increment or -1 */ + unsigned short fatal; /* whether the condition reported is fatal */ + int_handler_t int_handler; /* platform-specific int handler */ }; /** @@ -1945,7 +3556,7 @@ struct intr_info { * * A table driven interrupt handler that applies a set of masks to an * interrupt status word and performs the corresponding actions if the - * interrupts described by the mask have occured. The actions include + * interrupts described by the mask have occurred. The actions include * optionally emitting a warning or alert message. The table is terminated * by an entry specifying mask 0. Returns the number of fatal interrupt * conditions. @@ -1962,15 +3573,17 @@ static int t4_handle_intr_status(struct adapter *adapter, unsigned int reg, continue; if (acts->fatal) { fatal++; - CH_ALERT(adapter, "%s (0x%x)\n", - acts->msg, status & acts->mask); + CH_ALERT(adapter, "%s (0x%x)\n", acts->msg, + status & acts->mask); } else if (acts->msg) - CH_WARN_RATELIMIT(adapter, "%s (0x%x)\n", - acts->msg, status & acts->mask); + CH_WARN_RATELIMIT(adapter, "%s (0x%x)\n", acts->msg, + status & acts->mask); + if (acts->int_handler) + acts->int_handler(adapter); mask |= acts->mask; } status &= mask; - if (status) /* clear processed interrupts */ + if (status) /* clear processed interrupts */ t4_write_reg(adapter, reg, status); return fatal; } @@ -1980,7 +3593,7 @@ static int t4_handle_intr_status(struct adapter *adapter, unsigned int reg, */ static void pcie_intr_handler(struct adapter *adapter) { - static struct intr_info sysbus_intr_info[] = { + static const struct intr_info sysbus_intr_info[] = { { F_RNPP, "RXNP array parity error", -1, 1 }, { F_RPCP, "RXPC array parity error", -1, 1 }, { F_RCIP, "RXCIF array parity error", -1, 1 }, @@ -1988,7 +3601,7 @@ static void pcie_intr_handler(struct adapter *adapter) { F_RFTP, "RXFT array parity error", -1, 1 }, { 0 } }; - static struct intr_info pcie_port_intr_info[] = { + static const struct intr_info pcie_port_intr_info[] = { { F_TPCP, "TXPC array parity error", -1, 1 }, { F_TNPP, "TXNP array parity error", -1, 1 }, { F_TFTP, "TXFT array parity error", -1, 1 }, @@ -2000,7 +3613,7 @@ static void pcie_intr_handler(struct adapter *adapter) { F_TDUE, "Tx uncorrectable data error", -1, 1 }, { 0 } }; - static struct intr_info pcie_intr_info[] = { + static const struct intr_info pcie_intr_info[] = { { F_MSIADDRLPERR, "MSI AddrL parity error", -1, 1 }, { F_MSIADDRHPERR, "MSI AddrH parity error", -1, 1 }, { F_MSIDATAPERR, "MSI data parity error", -1, 1 }, @@ -2035,7 +3648,7 @@ static void pcie_intr_handler(struct adapter *adapter) { 0 } }; - static struct intr_info t5_pcie_intr_info[] = { + static const struct intr_info t5_pcie_intr_info[] = { { F_MSTGRPPERR, "Master Response Read Queue parity error", -1, 1 }, { F_MSTTIMEOUTPERR, "Master Timeout FIFO parity error", -1, 1 }, @@ -2080,13 +3693,13 @@ static void pcie_intr_handler(struct adapter *adapter) if (is_t4(adapter)) fat = t4_handle_intr_status(adapter, - A_PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS, - sysbus_intr_info) + - t4_handle_intr_status(adapter, - A_PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS, - pcie_port_intr_info) + - t4_handle_intr_status(adapter, A_PCIE_INT_CAUSE, - pcie_intr_info); + A_PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS, + sysbus_intr_info) + + t4_handle_intr_status(adapter, + A_PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS, + pcie_port_intr_info) + + t4_handle_intr_status(adapter, A_PCIE_INT_CAUSE, + pcie_intr_info); else fat = t4_handle_intr_status(adapter, A_PCIE_INT_CAUSE, t5_pcie_intr_info); @@ -2099,7 +3712,7 @@ static void pcie_intr_handler(struct adapter *adapter) */ static void tp_intr_handler(struct adapter *adapter) { - static struct intr_info tp_intr_info[] = { + static const struct intr_info tp_intr_info[] = { { 0x3fffffff, "TP parity error", -1, 1 }, { F_FLMTXFLSTEMPTY, "TP out of Tx pages", -1, 1 }, { 0 } @@ -2117,13 +3730,13 @@ static void sge_intr_handler(struct adapter *adapter) u64 v; u32 err; - static struct intr_info sge_intr_info[] = { + static const struct intr_info sge_intr_info[] = { { F_ERR_CPL_EXCEED_IQE_SIZE, "SGE received CPL exceeding IQE size", -1, 1 }, { F_ERR_INVALID_CIDX_INC, "SGE GTS CIDX increment too large", -1, 0 }, { F_ERR_CPL_OPCODE_0, "SGE received 0-length CPL", -1, 0 }, - { F_ERR_DROPPED_DB, "SGE doorbell dropped", -1, 0 }, + { F_DBFIFO_LP_INT, NULL, -1, 0, t4_db_full }, { F_ERR_DATA_CPL_ON_HIGH_QID1 | F_ERR_DATA_CPL_ON_HIGH_QID0, "SGE IQID > 1023 received CPL for FL", -1, 0 }, { F_ERR_BAD_DB_PIDX3, "SGE DBP 3 pidx increment too large", -1, @@ -2136,23 +3749,47 @@ static void sge_intr_handler(struct adapter *adapter) 0 }, { F_ERR_ING_CTXT_PRIO, "SGE too many priority ingress contexts", -1, 0 }, - { F_ERR_EGR_CTXT_PRIO, - "SGE too many priority egress contexts", -1, 0 }, { F_INGRESS_SIZE_ERR, "SGE illegal ingress QID", -1, 0 }, { F_EGRESS_SIZE_ERR, "SGE illegal egress QID", -1, 0 }, { 0 } }; + static const struct intr_info t4t5_sge_intr_info[] = { + { F_ERR_DROPPED_DB, NULL, -1, 0, t4_db_dropped }, + { F_DBFIFO_HP_INT, NULL, -1, 0, t4_db_full }, + { F_ERR_EGR_CTXT_PRIO, + "SGE too many priority egress contexts", -1, 0 }, + { 0 } + }; + + /* + * For now, treat below interrupts as fatal so that we disable SGE and + * get better debug */ + static const struct intr_info t6_sge_intr_info[] = { + { F_ERR_PCIE_ERROR0 | F_ERR_PCIE_ERROR1, + "SGE PCIe error for a DBP thread", -1, 1 }, + { F_FATAL_WRE_LEN, + "SGE Actual WRE packet is less than advertized length", + -1, 1 }, + { 0 } + }; + v = (u64)t4_read_reg(adapter, A_SGE_INT_CAUSE1) | - ((u64)t4_read_reg(adapter, A_SGE_INT_CAUSE2) << 32); + ((u64)t4_read_reg(adapter, A_SGE_INT_CAUSE2) << 32); if (v) { CH_ALERT(adapter, "SGE parity error (%#llx)\n", - (unsigned long long)v); + (unsigned long long)v); t4_write_reg(adapter, A_SGE_INT_CAUSE1, v); t4_write_reg(adapter, A_SGE_INT_CAUSE2, v >> 32); } v |= t4_handle_intr_status(adapter, A_SGE_INT_CAUSE3, sge_intr_info); + if (chip_id(adapter) <= CHELSIO_T5) + v |= t4_handle_intr_status(adapter, A_SGE_INT_CAUSE3, + t4t5_sge_intr_info); + else + v |= t4_handle_intr_status(adapter, A_SGE_INT_CAUSE3, + t6_sge_intr_info); err = t4_read_reg(adapter, A_SGE_ERROR_STATS); if (err & F_ERROR_QID_VALID) { @@ -2177,7 +3814,7 @@ static void sge_intr_handler(struct adapter *adapter) */ static void cim_intr_handler(struct adapter *adapter) { - static struct intr_info cim_intr_info[] = { + static const struct intr_info cim_intr_info[] = { { F_PREFDROPINT, "CIM control register prefetch drop", -1, 1 }, { CIM_OBQ_INTR, "CIM OBQ parity error", -1, 1 }, { CIM_IBQ_INTR, "CIM IBQ parity error", -1, 1 }, @@ -2187,7 +3824,7 @@ static void cim_intr_handler(struct adapter *adapter) { F_TIEQOUTPARERRINT, "CIM TIEQ incoming parity error", -1, 1 }, { 0 } }; - static struct intr_info cim_upintr_info[] = { + static const struct intr_info cim_upintr_info[] = { { F_RSVDSPACEINT, "CIM reserved space access", -1, 1 }, { F_ILLTRANSINT, "CIM illegal transaction", -1, 1 }, { F_ILLWRINT, "CIM illegal write", -1, 1 }, @@ -2236,7 +3873,7 @@ static void cim_intr_handler(struct adapter *adapter) */ static void ulprx_intr_handler(struct adapter *adapter) { - static struct intr_info ulprx_intr_info[] = { + static const struct intr_info ulprx_intr_info[] = { { F_CAUSE_CTX_1, "ULPRX channel 1 context error", -1, 1 }, { F_CAUSE_CTX_0, "ULPRX channel 0 context error", -1, 1 }, { 0x7fffff, "ULPRX parity error", -1, 1 }, @@ -2252,7 +3889,7 @@ static void ulprx_intr_handler(struct adapter *adapter) */ static void ulptx_intr_handler(struct adapter *adapter) { - static struct intr_info ulptx_intr_info[] = { + static const struct intr_info ulptx_intr_info[] = { { F_PBL_BOUND_ERR_CH3, "ULPTX channel 3 PBL out of bounds", -1, 0 }, { F_PBL_BOUND_ERR_CH2, "ULPTX channel 2 PBL out of bounds", -1, @@ -2274,7 +3911,7 @@ static void ulptx_intr_handler(struct adapter *adapter) */ static void pmtx_intr_handler(struct adapter *adapter) { - static struct intr_info pmtx_intr_info[] = { + static const struct intr_info pmtx_intr_info[] = { { F_PCMD_LEN_OVFL0, "PMTX channel 0 pcmd too large", -1, 1 }, { F_PCMD_LEN_OVFL1, "PMTX channel 1 pcmd too large", -1, 1 }, { F_PCMD_LEN_OVFL2, "PMTX channel 2 pcmd too large", -1, 1 }, @@ -2297,7 +3934,7 @@ static void pmtx_intr_handler(struct adapter *adapter) */ static void pmrx_intr_handler(struct adapter *adapter) { - static struct intr_info pmrx_intr_info[] = { + static const struct intr_info pmrx_intr_info[] = { { F_ZERO_E_CMD_ERROR, "PMRX 0-length pcmd", -1, 1 }, { 0x3ffff0, "PMRX framing error", -1, 1 }, { F_OCSPI_PAR_ERROR, "PMRX ocspi parity error", -1, 1 }, @@ -2317,7 +3954,7 @@ static void pmrx_intr_handler(struct adapter *adapter) */ static void cplsw_intr_handler(struct adapter *adapter) { - static struct intr_info cplsw_intr_info[] = { + static const struct intr_info cplsw_intr_info[] = { { F_CIM_OP_MAP_PERR, "CPLSW CIM op_map parity error", -1, 1 }, { F_CIM_OVFL_ERROR, "CPLSW CIM overflow", -1, 1 }, { F_TP_FRAMING_ERROR, "CPLSW TP framing error", -1, 1 }, @@ -2336,7 +3973,8 @@ static void cplsw_intr_handler(struct adapter *adapter) */ static void le_intr_handler(struct adapter *adap) { - static struct intr_info le_intr_info[] = { + unsigned int chip_ver = chip_id(adap); + static const struct intr_info le_intr_info[] = { { F_LIPMISS, "LE LIP miss", -1, 0 }, { F_LIP0, "LE 0 LIP error", -1, 0 }, { F_PARITYERR, "LE parity error", -1, 1 }, @@ -2345,7 +3983,18 @@ static void le_intr_handler(struct adapter *adap) { 0 } }; - if (t4_handle_intr_status(adap, A_LE_DB_INT_CAUSE, le_intr_info)) + static const struct intr_info t6_le_intr_info[] = { + { F_T6_LIPMISS, "LE LIP miss", -1, 0 }, + { F_T6_LIP0, "LE 0 LIP error", -1, 0 }, + { F_TCAMINTPERR, "LE parity error", -1, 1 }, + { F_T6_UNKNOWNCMD, "LE unknown command", -1, 1 }, + { F_SSRAMINTPERR, "LE request queue parity error", -1, 1 }, + { 0 } + }; + + if (t4_handle_intr_status(adap, A_LE_DB_INT_CAUSE, + (chip_ver <= CHELSIO_T5) ? + le_intr_info : t6_le_intr_info)) t4_fatal_err(adap); } @@ -2354,11 +4003,11 @@ static void le_intr_handler(struct adapter *adap) */ static void mps_intr_handler(struct adapter *adapter) { - static struct intr_info mps_rx_intr_info[] = { + static const struct intr_info mps_rx_intr_info[] = { { 0xffffff, "MPS Rx parity error", -1, 1 }, { 0 } }; - static struct intr_info mps_tx_intr_info[] = { + static const struct intr_info mps_tx_intr_info[] = { { V_TPFIFO(M_TPFIFO), "MPS Tx TP FIFO parity error", -1, 1 }, { F_NCSIFIFO, "MPS Tx NC-SI FIFO parity error", -1, 1 }, { V_TXDATAFIFO(M_TXDATAFIFO), "MPS Tx data FIFO parity error", @@ -2370,26 +4019,26 @@ static void mps_intr_handler(struct adapter *adapter) { F_FRMERR, "MPS Tx framing error", -1, 1 }, { 0 } }; - static struct intr_info mps_trc_intr_info[] = { + static const struct intr_info mps_trc_intr_info[] = { { V_FILTMEM(M_FILTMEM), "MPS TRC filter parity error", -1, 1 }, { V_PKTFIFO(M_PKTFIFO), "MPS TRC packet FIFO parity error", -1, 1 }, { F_MISCPERR, "MPS TRC misc parity error", -1, 1 }, { 0 } }; - static struct intr_info mps_stat_sram_intr_info[] = { + static const struct intr_info mps_stat_sram_intr_info[] = { { 0x1fffff, "MPS statistics SRAM parity error", -1, 1 }, { 0 } }; - static struct intr_info mps_stat_tx_intr_info[] = { + static const struct intr_info mps_stat_tx_intr_info[] = { { 0xfffff, "MPS statistics Tx FIFO parity error", -1, 1 }, { 0 } }; - static struct intr_info mps_stat_rx_intr_info[] = { + static const struct intr_info mps_stat_rx_intr_info[] = { { 0xffffff, "MPS statistics Rx FIFO parity error", -1, 1 }, { 0 } }; - static struct intr_info mps_cls_intr_info[] = { + static const struct intr_info mps_cls_intr_info[] = { { F_MATCHSRAM, "MPS match SRAM parity error", -1, 1 }, { F_MATCHTCAM, "MPS match TCAM parity error", -1, 1 }, { F_HASHSRAM, "MPS hash SRAM parity error", -1, 1 }, @@ -2414,26 +4063,27 @@ static void mps_intr_handler(struct adapter *adapter) mps_cls_intr_info); t4_write_reg(adapter, A_MPS_INT_CAUSE, 0); - t4_read_reg(adapter, A_MPS_INT_CAUSE); /* flush */ + t4_read_reg(adapter, A_MPS_INT_CAUSE); /* flush */ if (fat) t4_fatal_err(adapter); } -#define MEM_INT_MASK (F_PERR_INT_CAUSE | F_ECC_CE_INT_CAUSE | F_ECC_UE_INT_CAUSE) +#define MEM_INT_MASK (F_PERR_INT_CAUSE | F_ECC_CE_INT_CAUSE | \ + F_ECC_UE_INT_CAUSE) /* * EDC/MC interrupt handler. */ static void mem_intr_handler(struct adapter *adapter, int idx) { - static const char name[3][5] = { "EDC0", "EDC1", "MC" }; + static const char name[4][7] = { "EDC0", "EDC1", "MC/MC0", "MC1" }; unsigned int addr, cnt_addr, v; if (idx <= MEM_EDC1) { addr = EDC_REG(A_EDC_INT_CAUSE, idx); cnt_addr = EDC_REG(A_EDC_ECC_STATUS, idx); - } else { + } else if (idx == MEM_MC) { if (is_t4(adapter)) { addr = A_MC_INT_CAUSE; cnt_addr = A_MC_ECC_STATUS; @@ -2441,22 +4091,28 @@ static void mem_intr_handler(struct adapter *adapter, int idx) addr = A_MC_P_INT_CAUSE; cnt_addr = A_MC_P_ECC_STATUS; } + } else { + addr = MC_REG(A_MC_P_INT_CAUSE, 1); + cnt_addr = MC_REG(A_MC_P_ECC_STATUS, 1); } v = t4_read_reg(adapter, addr) & MEM_INT_MASK; if (v & F_PERR_INT_CAUSE) - CH_ALERT(adapter, "%s FIFO parity error\n", name[idx]); + CH_ALERT(adapter, "%s FIFO parity error\n", + name[idx]); if (v & F_ECC_CE_INT_CAUSE) { u32 cnt = G_ECC_CECNT(t4_read_reg(adapter, cnt_addr)); + t4_edc_err_read(adapter, idx); + t4_write_reg(adapter, cnt_addr, V_ECC_CECNT(M_ECC_CECNT)); CH_WARN_RATELIMIT(adapter, "%u %s correctable ECC data error%s\n", cnt, name[idx], cnt > 1 ? "s" : ""); } if (v & F_ECC_UE_INT_CAUSE) - CH_ALERT(adapter, "%s uncorrectable ECC data error\n", - name[idx]); + CH_ALERT(adapter, + "%s uncorrectable ECC data error\n", name[idx]); t4_write_reg(adapter, addr, v); if (v & (F_PERR_INT_CAUSE | F_ECC_UE_INT_CAUSE)) @@ -2471,19 +4127,21 @@ static void ma_intr_handler(struct adapter *adapter) u32 v, status = t4_read_reg(adapter, A_MA_INT_CAUSE); if (status & F_MEM_PERR_INT_CAUSE) { - CH_ALERT(adapter, "MA parity error, parity status %#x\n", - t4_read_reg(adapter, A_MA_PARITY_ERROR_STATUS1)); + CH_ALERT(adapter, + "MA parity error, parity status %#x\n", + t4_read_reg(adapter, A_MA_PARITY_ERROR_STATUS1)); if (is_t5(adapter)) CH_ALERT(adapter, - "MA parity error, parity status %#x\n", - t4_read_reg(adapter, - A_MA_PARITY_ERROR_STATUS2)); + "MA parity error, parity status %#x\n", + t4_read_reg(adapter, + A_MA_PARITY_ERROR_STATUS2)); } if (status & F_MEM_WRAP_INT_CAUSE) { v = t4_read_reg(adapter, A_MA_INT_WRAP_STATUS); - CH_ALERT(adapter, "MA address wrap-around error by client %u to" - " address %#x\n", G_MEM_WRAP_CLIENT_NUM(v), - G_MEM_WRAP_ADDRESS(v) << 4); + CH_ALERT(adapter, "MA address wrap-around error by " + "client %u to address %#x\n", + G_MEM_WRAP_CLIENT_NUM(v), + G_MEM_WRAP_ADDRESS(v) << 4); } t4_write_reg(adapter, A_MA_INT_CAUSE, status); t4_fatal_err(adapter); @@ -2494,7 +4152,7 @@ static void ma_intr_handler(struct adapter *adapter) */ static void smb_intr_handler(struct adapter *adap) { - static struct intr_info smb_intr_info[] = { + static const struct intr_info smb_intr_info[] = { { F_MSTTXFIFOPARINT, "SMB master Tx FIFO parity error", -1, 1 }, { F_MSTRXFIFOPARINT, "SMB master Rx FIFO parity error", -1, 1 }, { F_SLVFIFOPARINT, "SMB slave FIFO parity error", -1, 1 }, @@ -2510,7 +4168,7 @@ static void smb_intr_handler(struct adapter *adap) */ static void ncsi_intr_handler(struct adapter *adap) { - static struct intr_info ncsi_intr_info[] = { + static const struct intr_info ncsi_intr_info[] = { { F_CIM_DM_PRTY_ERR, "NC-SI CIM parity error", -1, 1 }, { F_MPS_DM_PRTY_ERR, "NC-SI MPS parity error", -1, 1 }, { F_TXFIFO_PRTY_ERR, "NC-SI Tx FIFO parity error", -1, 1 }, @@ -2535,14 +4193,17 @@ static void xgmac_intr_handler(struct adapter *adap, int port) int_cause_reg = T5_PORT_REG(port, A_MAC_PORT_INT_CAUSE); v = t4_read_reg(adap, int_cause_reg); + v &= (F_TXFIFO_PRTY_ERR | F_RXFIFO_PRTY_ERR); if (!v) return; if (v & F_TXFIFO_PRTY_ERR) - CH_ALERT(adap, "XGMAC %d Tx FIFO parity error\n", port); + CH_ALERT(adap, "XGMAC %d Tx FIFO parity error\n", + port); if (v & F_RXFIFO_PRTY_ERR) - CH_ALERT(adap, "XGMAC %d Rx FIFO parity error\n", port); + CH_ALERT(adap, "XGMAC %d Rx FIFO parity error\n", + port); t4_write_reg(adap, int_cause_reg, v); t4_fatal_err(adap); } @@ -2552,27 +4213,24 @@ static void xgmac_intr_handler(struct adapter *adap, int port) */ static void pl_intr_handler(struct adapter *adap) { - static struct intr_info pl_intr_info[] = { + static const struct intr_info pl_intr_info[] = { { F_FATALPERR, "Fatal parity error", -1, 1 }, { F_PERRVFID, "PL VFID_MAP parity error", -1, 1 }, { 0 } }; - static struct intr_info t5_pl_intr_info[] = { - { F_PL_BUSPERR, "PL bus parity error", -1, 1 }, + static const struct intr_info t5_pl_intr_info[] = { { F_FATALPERR, "Fatal parity error", -1, 1 }, { 0 } }; if (t4_handle_intr_status(adap, A_PL_PL_INT_CAUSE, - is_t4(adap) ? pl_intr_info : t5_pl_intr_info)) + is_t4(adap) ? + pl_intr_info : t5_pl_intr_info)) t4_fatal_err(adap); } #define PF_INTR_MASK (F_PFSW | F_PFCIM) -#define GLBL_INTR_MASK (F_CIM | F_MPS | F_PL | F_PCIE | F_MC | F_EDC0 | \ - F_EDC1 | F_LE | F_TP | F_MA | F_PM_TX | F_PM_RX | F_ULP_RX | \ - F_CPL_SWITCH | F_SGE | F_ULP_TX) /** * t4_slow_intr_handler - control path interrupt handler @@ -2598,18 +4256,20 @@ int t4_slow_intr_handler(struct adapter *adapter) pl_intr_handler(adapter); if (cause & F_SMB) smb_intr_handler(adapter); - if (cause & F_XGMAC0) + if (cause & F_MAC0) xgmac_intr_handler(adapter, 0); - if (cause & F_XGMAC1) + if (cause & F_MAC1) xgmac_intr_handler(adapter, 1); - if (cause & F_XGMAC_KR0) + if (cause & F_MAC2) xgmac_intr_handler(adapter, 2); - if (cause & F_XGMAC_KR1) + if (cause & F_MAC3) xgmac_intr_handler(adapter, 3); if (cause & F_PCIE) pcie_intr_handler(adapter); - if (cause & F_MC) + if (cause & F_MC0) mem_intr_handler(adapter, MEM_MC); + if (is_t5(adapter) && (cause & F_MC1)) + mem_intr_handler(adapter, MEM_MC1); if (cause & F_EDC0) mem_intr_handler(adapter, MEM_EDC0); if (cause & F_EDC1) @@ -2635,7 +4295,7 @@ int t4_slow_intr_handler(struct adapter *adapter) /* Clear the interrupts just processed for which we are the master. */ t4_write_reg(adapter, A_PL_INT_CAUSE, cause & GLBL_INTR_MASK); - (void) t4_read_reg(adapter, A_PL_INT_CAUSE); /* flush */ + (void)t4_read_reg(adapter, A_PL_INT_CAUSE); /* flush */ return 1; } @@ -2654,16 +4314,23 @@ int t4_slow_intr_handler(struct adapter *adapter) */ void t4_intr_enable(struct adapter *adapter) { - u32 pf = G_SOURCEPF(t4_read_reg(adapter, A_PL_WHOAMI)); + u32 val = 0; + u32 whoami = t4_read_reg(adapter, A_PL_WHOAMI); + u32 pf = (chip_id(adapter) <= CHELSIO_T5 + ? G_SOURCEPF(whoami) + : G_T6_SOURCEPF(whoami)); + if (chip_id(adapter) <= CHELSIO_T5) + val = F_ERR_DROPPED_DB | F_ERR_EGR_CTXT_PRIO | F_DBFIFO_HP_INT; + else + val = F_ERR_PCIE_ERROR0 | F_ERR_PCIE_ERROR1 | F_FATAL_WRE_LEN; t4_write_reg(adapter, A_SGE_INT_ENABLE3, F_ERR_CPL_EXCEED_IQE_SIZE | F_ERR_INVALID_CIDX_INC | F_ERR_CPL_OPCODE_0 | - F_ERR_DROPPED_DB | F_ERR_DATA_CPL_ON_HIGH_QID1 | + F_ERR_DATA_CPL_ON_HIGH_QID1 | F_INGRESS_SIZE_ERR | F_ERR_DATA_CPL_ON_HIGH_QID0 | F_ERR_BAD_DB_PIDX3 | F_ERR_BAD_DB_PIDX2 | F_ERR_BAD_DB_PIDX1 | F_ERR_BAD_DB_PIDX0 | F_ERR_ING_CTXT_PRIO | - F_ERR_EGR_CTXT_PRIO | F_INGRESS_SIZE_ERR | - F_EGRESS_SIZE_ERR); + F_DBFIFO_LP_INT | F_EGRESS_SIZE_ERR | val); t4_write_reg(adapter, MYPF_REG(A_PL_PF_INT_ENABLE), PF_INTR_MASK); t4_set_reg_field(adapter, A_PL_INT_MAP0, 0, 1 << pf); } @@ -2678,7 +4345,10 @@ void t4_intr_enable(struct adapter *adapter) */ void t4_intr_disable(struct adapter *adapter) { - u32 pf = G_SOURCEPF(t4_read_reg(adapter, A_PL_WHOAMI)); + u32 whoami = t4_read_reg(adapter, A_PL_WHOAMI); + u32 pf = (chip_id(adapter) <= CHELSIO_T5 + ? G_SOURCEPF(whoami) + : G_T6_SOURCEPF(whoami)); t4_write_reg(adapter, MYPF_REG(A_PL_PF_INT_ENABLE), 0); t4_set_reg_field(adapter, A_PL_INT_MAP0, 1 << pf, 0); @@ -2773,11 +4443,10 @@ int t4_config_rss_range(struct adapter *adapter, int mbox, unsigned int viid, struct fw_rss_ind_tbl_cmd cmd; memset(&cmd, 0, sizeof(cmd)); - cmd.op_to_viid = htonl(V_FW_CMD_OP(FW_RSS_IND_TBL_CMD) | - F_FW_CMD_REQUEST | F_FW_CMD_WRITE | - V_FW_RSS_IND_TBL_CMD_VIID(viid)); - cmd.retval_len16 = htonl(FW_LEN16(cmd)); - + cmd.op_to_viid = cpu_to_be32(V_FW_CMD_OP(FW_RSS_IND_TBL_CMD) | + F_FW_CMD_REQUEST | F_FW_CMD_WRITE | + V_FW_RSS_IND_TBL_CMD_VIID(viid)); + cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd)); /* * Each firmware RSS command can accommodate up to 32 RSS Ingress @@ -2794,8 +4463,8 @@ int t4_config_rss_range(struct adapter *adapter, int mbox, unsigned int viid, * Set up the firmware RSS command header to send the next * "nq" Ingress Queue IDs to the firmware. */ - cmd.niqid = htons(nq); - cmd.startidx = htons(start); + cmd.niqid = cpu_to_be16(nq); + cmd.startidx = cpu_to_be16(start); /* * "nq" more done for the start of the next loop. @@ -2841,7 +4510,6 @@ int t4_config_rss_range(struct adapter *adapter, int mbox, unsigned int viid, if (ret) return ret; } - return 0; } @@ -2860,15 +4528,16 @@ int t4_config_glbl_rss(struct adapter *adapter, int mbox, unsigned int mode, struct fw_rss_glb_config_cmd c; memset(&c, 0, sizeof(c)); - c.op_to_write = htonl(V_FW_CMD_OP(FW_RSS_GLB_CONFIG_CMD) | - F_FW_CMD_REQUEST | F_FW_CMD_WRITE); - c.retval_len16 = htonl(FW_LEN16(c)); + c.op_to_write = cpu_to_be32(V_FW_CMD_OP(FW_RSS_GLB_CONFIG_CMD) | + F_FW_CMD_REQUEST | F_FW_CMD_WRITE); + c.retval_len16 = cpu_to_be32(FW_LEN16(c)); if (mode == FW_RSS_GLB_CONFIG_CMD_MODE_MANUAL) { - c.u.manual.mode_pkd = htonl(V_FW_RSS_GLB_CONFIG_CMD_MODE(mode)); + c.u.manual.mode_pkd = + cpu_to_be32(V_FW_RSS_GLB_CONFIG_CMD_MODE(mode)); } else if (mode == FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL) { c.u.basicvirtual.mode_pkd = - htonl(V_FW_RSS_GLB_CONFIG_CMD_MODE(mode)); - c.u.basicvirtual.synmapen_to_hashtoeplitz = htonl(flags); + cpu_to_be32(V_FW_RSS_GLB_CONFIG_CMD_MODE(mode)); + c.u.basicvirtual.synmapen_to_hashtoeplitz = cpu_to_be32(flags); } else return -EINVAL; return t4_wr_mbox(adapter, mbox, &c, sizeof(c), NULL); @@ -2890,11 +4559,11 @@ int t4_config_vi_rss(struct adapter *adapter, int mbox, unsigned int viid, struct fw_rss_vi_config_cmd c; memset(&c, 0, sizeof(c)); - c.op_to_viid = htonl(V_FW_CMD_OP(FW_RSS_VI_CONFIG_CMD) | - F_FW_CMD_REQUEST | F_FW_CMD_WRITE | - V_FW_RSS_VI_CONFIG_CMD_VIID(viid)); - c.retval_len16 = htonl(FW_LEN16(c)); - c.u.basicvirtual.defaultq_to_udpen = htonl(flags | + c.op_to_viid = cpu_to_be32(V_FW_CMD_OP(FW_RSS_VI_CONFIG_CMD) | + F_FW_CMD_REQUEST | F_FW_CMD_WRITE | + V_FW_RSS_VI_CONFIG_CMD_VIID(viid)); + c.retval_len16 = cpu_to_be32(FW_LEN16(c)); + c.u.basicvirtual.defaultq_to_udpen = cpu_to_be32(flags | V_FW_RSS_VI_CONFIG_CMD_DEFAULTQ(defq)); return t4_wr_mbox(adapter, mbox, &c, sizeof(c), NULL); } @@ -2906,7 +4575,7 @@ static int rd_rss_row(struct adapter *adap, int row, u32 *val) return t4_wait_op_done_val(adap, A_TP_RSS_LKP_TABLE, F_LKPTBLROWVLD, 1, 5, 0, val); } - + /** * t4_read_rss - read the contents of the RSS mapping table * @adapter: the adapter @@ -2930,6 +4599,42 @@ int t4_read_rss(struct adapter *adapter, u16 *map) } /** + * t4_fw_tp_pio_rw - Access TP PIO through LDST + * @adap: the adapter + * @vals: where the indirect register values are stored/written + * @nregs: how many indirect registers to read/write + * @start_idx: index of first indirect register to read/write + * @rw: Read (1) or Write (0) + * + * Access TP PIO registers through LDST + */ +void t4_fw_tp_pio_rw(struct adapter *adap, u32 *vals, unsigned int nregs, + unsigned int start_index, unsigned int rw) +{ + int ret, i; + int cmd = FW_LDST_ADDRSPC_TP_PIO; + struct fw_ldst_cmd c; + + for (i = 0 ; i < nregs; i++) { + memset(&c, 0, sizeof(c)); + c.op_to_addrspace = cpu_to_be32(V_FW_CMD_OP(FW_LDST_CMD) | + F_FW_CMD_REQUEST | + (rw ? F_FW_CMD_READ : + F_FW_CMD_WRITE) | + V_FW_LDST_CMD_ADDRSPACE(cmd)); + c.cycles_to_len16 = cpu_to_be32(FW_LEN16(c)); + + c.u.addrval.addr = cpu_to_be32(start_index + i); + c.u.addrval.val = rw ? 0 : cpu_to_be32(vals[i]); + ret = t4_wr_mbox(adap, adap->mbox, &c, sizeof(c), &c); + if (ret == 0) { + if (rw) + vals[i] = be32_to_cpu(c.u.addrval.val); + } + } +} + +/** * t4_read_rss_key - read the global RSS key * @adap: the adapter * @key: 10-entry array holding the 320-bit RSS key @@ -2938,8 +4643,11 @@ int t4_read_rss(struct adapter *adapter, u16 *map) */ void t4_read_rss_key(struct adapter *adap, u32 *key) { - t4_read_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA, key, 10, - A_TP_RSS_SECRET_KEY0); + if (t4_use_ldst(adap)) + t4_fw_tp_pio_rw(adap, key, 10, A_TP_RSS_SECRET_KEY0, 1); + else + t4_read_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA, key, 10, + A_TP_RSS_SECRET_KEY0); } /** @@ -2952,13 +4660,35 @@ void t4_read_rss_key(struct adapter *adap, u32 *key) * 0..15 the corresponding entry in the RSS key table is written, * otherwise the global RSS key is written. */ -void t4_write_rss_key(struct adapter *adap, const u32 *key, int idx) +void t4_write_rss_key(struct adapter *adap, u32 *key, int idx) { - t4_write_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA, key, 10, - A_TP_RSS_SECRET_KEY0); - if (idx >= 0 && idx < 16) - t4_write_reg(adap, A_TP_RSS_CONFIG_VRT, - V_KEYWRADDR(idx) | F_KEYWREN); + u8 rss_key_addr_cnt = 16; + u32 vrt = t4_read_reg(adap, A_TP_RSS_CONFIG_VRT); + + /* + * T6 and later: for KeyMode 3 (per-vf and per-vf scramble), + * allows access to key addresses 16-63 by using KeyWrAddrX + * as index[5:4](upper 2) into key table + */ + if ((chip_id(adap) > CHELSIO_T5) && + (vrt & F_KEYEXTEND) && (G_KEYMODE(vrt) == 3)) + rss_key_addr_cnt = 32; + + if (t4_use_ldst(adap)) + t4_fw_tp_pio_rw(adap, key, 10, A_TP_RSS_SECRET_KEY0, 0); + else + t4_write_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA, key, 10, + A_TP_RSS_SECRET_KEY0); + + if (idx >= 0 && idx < rss_key_addr_cnt) { + if (rss_key_addr_cnt > 16) + t4_write_reg(adap, A_TP_RSS_CONFIG_VRT, + V_KEYWRADDRX(idx >> 4) | + V_T6_VFWRADDR(idx) | F_KEYWREN); + else + t4_write_reg(adap, A_TP_RSS_CONFIG_VRT, + V_KEYWRADDR(idx) | F_KEYWREN); + } } /** @@ -2970,10 +4700,15 @@ void t4_write_rss_key(struct adapter *adap, const u32 *key, int idx) * Reads the PF RSS Configuration Table at the specified index and returns * the value found there. */ -void t4_read_rss_pf_config(struct adapter *adapter, unsigned int index, u32 *valp) +void t4_read_rss_pf_config(struct adapter *adapter, unsigned int index, + u32 *valp) { - t4_read_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA, - valp, 1, A_TP_RSS_PF0_CONFIG + index); + if (t4_use_ldst(adapter)) + t4_fw_tp_pio_rw(adapter, valp, 1, + A_TP_RSS_PF0_CONFIG + index, 1); + else + t4_read_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA, + valp, 1, A_TP_RSS_PF0_CONFIG + index); } /** @@ -2985,10 +4720,15 @@ void t4_read_rss_pf_config(struct adapter *adapter, unsigned int index, u32 *val * Writes the PF RSS Configuration Table at the specified index with the * specified value. */ -void t4_write_rss_pf_config(struct adapter *adapter, unsigned int index, u32 val) +void t4_write_rss_pf_config(struct adapter *adapter, unsigned int index, + u32 val) { - t4_write_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA, - &val, 1, A_TP_RSS_PF0_CONFIG + index); + if (t4_use_ldst(adapter)) + t4_fw_tp_pio_rw(adapter, &val, 1, + A_TP_RSS_PF0_CONFIG + index, 0); + else + t4_write_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA, + &val, 1, A_TP_RSS_PF0_CONFIG + index); } /** @@ -3004,28 +4744,40 @@ void t4_write_rss_pf_config(struct adapter *adapter, unsigned int index, u32 val void t4_read_rss_vf_config(struct adapter *adapter, unsigned int index, u32 *vfl, u32 *vfh) { - u32 vrt; + u32 vrt, mask, data; + if (chip_id(adapter) <= CHELSIO_T5) { + mask = V_VFWRADDR(M_VFWRADDR); + data = V_VFWRADDR(index); + } else { + mask = V_T6_VFWRADDR(M_T6_VFWRADDR); + data = V_T6_VFWRADDR(index); + } /* * Request that the index'th VF Table values be read into VFL/VFH. */ vrt = t4_read_reg(adapter, A_TP_RSS_CONFIG_VRT); - vrt &= ~(F_VFRDRG | V_VFWRADDR(M_VFWRADDR) | F_VFWREN | F_KEYWREN); - vrt |= V_VFWRADDR(index) | F_VFRDEN; + vrt &= ~(F_VFRDRG | F_VFWREN | F_KEYWREN | mask); + vrt |= data | F_VFRDEN; t4_write_reg(adapter, A_TP_RSS_CONFIG_VRT, vrt); /* * Grab the VFL/VFH values ... */ - t4_read_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA, - vfl, 1, A_TP_RSS_VFL_CONFIG); - t4_read_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA, - vfh, 1, A_TP_RSS_VFH_CONFIG); + if (t4_use_ldst(adapter)) { + t4_fw_tp_pio_rw(adapter, vfl, 1, A_TP_RSS_VFL_CONFIG, 1); + t4_fw_tp_pio_rw(adapter, vfh, 1, A_TP_RSS_VFH_CONFIG, 1); + } else { + t4_read_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA, + vfl, 1, A_TP_RSS_VFL_CONFIG); + t4_read_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA, + vfh, 1, A_TP_RSS_VFH_CONFIG); + } } /** * t4_write_rss_vf_config - write VF RSS Configuration Table - * + * * @adapter: the adapter * @index: the entry in the VF RSS table to write * @vfl: the VFL to store @@ -3037,22 +4789,35 @@ void t4_read_rss_vf_config(struct adapter *adapter, unsigned int index, void t4_write_rss_vf_config(struct adapter *adapter, unsigned int index, u32 vfl, u32 vfh) { - u32 vrt; + u32 vrt, mask, data; + + if (chip_id(adapter) <= CHELSIO_T5) { + mask = V_VFWRADDR(M_VFWRADDR); + data = V_VFWRADDR(index); + } else { + mask = V_T6_VFWRADDR(M_T6_VFWRADDR); + data = V_T6_VFWRADDR(index); + } /* * Load up VFL/VFH with the values to be written ... */ - t4_write_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA, - &vfl, 1, A_TP_RSS_VFL_CONFIG); - t4_write_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA, - &vfh, 1, A_TP_RSS_VFH_CONFIG); + if (t4_use_ldst(adapter)) { + t4_fw_tp_pio_rw(adapter, &vfl, 1, A_TP_RSS_VFL_CONFIG, 0); + t4_fw_tp_pio_rw(adapter, &vfh, 1, A_TP_RSS_VFH_CONFIG, 0); + } else { + t4_write_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA, + &vfl, 1, A_TP_RSS_VFL_CONFIG); + t4_write_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA, + &vfh, 1, A_TP_RSS_VFH_CONFIG); + } /* * Write the VFL/VFH into the VF Table at index'th location. */ vrt = t4_read_reg(adapter, A_TP_RSS_CONFIG_VRT); - vrt &= ~(F_VFRDRG | F_VFRDEN | V_VFWRADDR(M_VFWRADDR) | F_KEYWREN); - vrt |= V_VFWRADDR(index) | F_VFWREN; + vrt &= ~(F_VFRDRG | F_VFWREN | F_KEYWREN | mask); + vrt |= data | F_VFRDEN; t4_write_reg(adapter, A_TP_RSS_CONFIG_VRT, vrt); } @@ -3066,8 +4831,11 @@ u32 t4_read_rss_pf_map(struct adapter *adapter) { u32 pfmap; - t4_read_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA, - &pfmap, 1, A_TP_RSS_PF_MAP); + if (t4_use_ldst(adapter)) + t4_fw_tp_pio_rw(adapter, &pfmap, 1, A_TP_RSS_PF_MAP, 1); + else + t4_read_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA, + &pfmap, 1, A_TP_RSS_PF_MAP); return pfmap; } @@ -3080,8 +4848,11 @@ u32 t4_read_rss_pf_map(struct adapter *adapter) */ void t4_write_rss_pf_map(struct adapter *adapter, u32 pfmap) { - t4_write_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA, - &pfmap, 1, A_TP_RSS_PF_MAP); + if (t4_use_ldst(adapter)) + t4_fw_tp_pio_rw(adapter, &pfmap, 1, A_TP_RSS_PF_MAP, 0); + else + t4_write_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA, + &pfmap, 1, A_TP_RSS_PF_MAP); } /** @@ -3094,8 +4865,11 @@ u32 t4_read_rss_pf_mask(struct adapter *adapter) { u32 pfmask; - t4_read_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA, - &pfmask, 1, A_TP_RSS_PF_MSK); + if (t4_use_ldst(adapter)) + t4_fw_tp_pio_rw(adapter, &pfmask, 1, A_TP_RSS_PF_MSK, 1); + else + t4_read_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA, + &pfmask, 1, A_TP_RSS_PF_MSK); return pfmask; } @@ -3108,61 +4882,11 @@ u32 t4_read_rss_pf_mask(struct adapter *adapter) */ void t4_write_rss_pf_mask(struct adapter *adapter, u32 pfmask) { - t4_write_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA, - &pfmask, 1, A_TP_RSS_PF_MSK); -} - -static void refresh_vlan_pri_map(struct adapter *adap) -{ - - t4_read_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA, - &adap->params.tp.vlan_pri_map, 1, - A_TP_VLAN_PRI_MAP); - - /* - * Now that we have TP_VLAN_PRI_MAP cached, we can calculate the field - * shift positions of several elements of the Compressed Filter Tuple - * for this adapter which we need frequently ... - */ - adap->params.tp.vlan_shift = t4_filter_field_shift(adap, F_VLAN); - adap->params.tp.vnic_shift = t4_filter_field_shift(adap, F_VNIC_ID); - adap->params.tp.port_shift = t4_filter_field_shift(adap, F_PORT); - adap->params.tp.protocol_shift = t4_filter_field_shift(adap, F_PROTOCOL); - - /* - * If TP_INGRESS_CONFIG.VNID == 0, then TP_VLAN_PRI_MAP.VNIC_ID - * represents the presense of an Outer VLAN instead of a VNIC ID. - */ - if ((adap->params.tp.ingress_config & F_VNIC) == 0) - adap->params.tp.vnic_shift = -1; -} - -/** - * t4_set_filter_mode - configure the optional components of filter tuples - * @adap: the adapter - * @mode_map: a bitmap selcting which optional filter components to enable - * - * Sets the filter mode by selecting the optional components to enable - * in filter tuples. Returns 0 on success and a negative error if the - * requested mode needs more bits than are available for optional - * components. - */ -int t4_set_filter_mode(struct adapter *adap, unsigned int mode_map) -{ - static u8 width[] = { 1, 3, 17, 17, 8, 8, 16, 9, 3, 1 }; - - int i, nbits = 0; - - for (i = S_FCOE; i <= S_FRAGMENTATION; i++) - if (mode_map & (1 << i)) - nbits += width[i]; - if (nbits > FILTER_OPT_LEN) - return -EINVAL; - t4_write_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA, &mode_map, 1, - A_TP_VLAN_PRI_MAP); - refresh_vlan_pri_map(adap); - - return 0; + if (t4_use_ldst(adapter)) + t4_fw_tp_pio_rw(adapter, &pfmask, 1, A_TP_RSS_PF_MSK, 0); + else + t4_write_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA, + &pfmask, 1, A_TP_RSS_PF_MSK); } /** @@ -3186,18 +4910,18 @@ void t4_tp_get_tcp_stats(struct adapter *adap, struct tp_tcp_stats *v4, if (v4) { t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, val, ARRAY_SIZE(val), A_TP_MIB_TCP_OUT_RST); - v4->tcpOutRsts = STAT(OUT_RST); - v4->tcpInSegs = STAT64(IN_SEG); - v4->tcpOutSegs = STAT64(OUT_SEG); - v4->tcpRetransSegs = STAT64(RXT_SEG); + v4->tcp_out_rsts = STAT(OUT_RST); + v4->tcp_in_segs = STAT64(IN_SEG); + v4->tcp_out_segs = STAT64(OUT_SEG); + v4->tcp_retrans_segs = STAT64(RXT_SEG); } if (v6) { t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, val, ARRAY_SIZE(val), A_TP_MIB_TCP_V6OUT_RST); - v6->tcpOutRsts = STAT(OUT_RST); - v6->tcpInSegs = STAT64(IN_SEG); - v6->tcpOutSegs = STAT64(OUT_SEG); - v6->tcpRetransSegs = STAT64(RXT_SEG); + v6->tcp_out_rsts = STAT(OUT_RST); + v6->tcp_in_segs = STAT64(IN_SEG); + v6->tcp_out_segs = STAT64(OUT_SEG); + v6->tcp_retrans_segs = STAT64(RXT_SEG); } #undef STAT64 #undef STAT @@ -3213,18 +4937,27 @@ void t4_tp_get_tcp_stats(struct adapter *adap, struct tp_tcp_stats *v4, */ void t4_tp_get_err_stats(struct adapter *adap, struct tp_err_stats *st) { - t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, st->macInErrs, - 12, A_TP_MIB_MAC_IN_ERR_0); - t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, st->tnlCongDrops, - 8, A_TP_MIB_TNL_CNG_DROP_0); - t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, st->tnlTxDrops, - 4, A_TP_MIB_TNL_DROP_0); - t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, st->ofldVlanDrops, - 4, A_TP_MIB_OFD_VLN_DROP_0); - t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, st->tcp6InErrs, - 4, A_TP_MIB_TCP_V6IN_ERR_0); - t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, &st->ofldNoNeigh, - 2, A_TP_MIB_OFD_ARP_DROP); + int nchan = adap->chip_params->nchan; + + t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, + st->mac_in_errs, nchan, A_TP_MIB_MAC_IN_ERR_0); + t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, + st->hdr_in_errs, nchan, A_TP_MIB_HDR_IN_ERR_0); + t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, + st->tcp_in_errs, nchan, A_TP_MIB_TCP_IN_ERR_0); + t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, + st->tnl_cong_drops, nchan, A_TP_MIB_TNL_CNG_DROP_0); + t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, + st->ofld_chan_drops, nchan, A_TP_MIB_OFD_CHN_DROP_0); + t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, + st->tnl_tx_drops, nchan, A_TP_MIB_TNL_DROP_0); + t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, + st->ofld_vlan_drops, nchan, A_TP_MIB_OFD_VLN_DROP_0); + t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, + st->tcp6_in_errs, nchan, A_TP_MIB_TCP_V6IN_ERR_0); + + t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, + &st->ofld_no_neigh, 2, A_TP_MIB_OFD_ARP_DROP); } /** @@ -3236,8 +4969,10 @@ void t4_tp_get_err_stats(struct adapter *adap, struct tp_err_stats *st) */ void t4_tp_get_proxy_stats(struct adapter *adap, struct tp_proxy_stats *st) { + int nchan = adap->chip_params->nchan; + t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, st->proxy, - 4, A_TP_MIB_TNL_LPBK_0); + nchan, A_TP_MIB_TNL_LPBK_0); } /** @@ -3249,8 +4984,12 @@ void t4_tp_get_proxy_stats(struct adapter *adap, struct tp_proxy_stats *st) */ void t4_tp_get_cpl_stats(struct adapter *adap, struct tp_cpl_stats *st) { + int nchan = adap->chip_params->nchan; + t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, st->req, - 8, A_TP_MIB_CPL_IN_REQ_0); + nchan, A_TP_MIB_CPL_IN_REQ_0); + t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, st->rsp, + nchan, A_TP_MIB_CPL_OUT_RSP_0); } /** @@ -3262,8 +5001,8 @@ void t4_tp_get_cpl_stats(struct adapter *adap, struct tp_cpl_stats *st) */ void t4_tp_get_rdma_stats(struct adapter *adap, struct tp_rdma_stats *st) { - t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, &st->rqe_dfr_mod, - 2, A_TP_MIB_RQE_DFR_MOD); + t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, &st->rqe_dfr_pkt, + 2, A_TP_MIB_RQE_DFR_PKT); } /** @@ -3279,13 +5018,13 @@ void t4_get_fcoe_stats(struct adapter *adap, unsigned int idx, { u32 val[2]; - t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, &st->framesDDP, + t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, &st->frames_ddp, 1, A_TP_MIB_FCOE_DDP_0 + idx); - t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, &st->framesDrop, + t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, &st->frames_drop, 1, A_TP_MIB_FCOE_DROP_0 + idx); t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, val, 2, A_TP_MIB_FCOE_BYTE_0_HI + 2 * idx); - st->octetsDDP = ((u64)val[0] << 32) | val[1]; + st->octets_ddp = ((u64)val[0] << 32) | val[1]; } /** @@ -3351,24 +5090,6 @@ void t4_read_cong_tbl(struct adapter *adap, u16 incr[NMTUS][NCCTRL_WIN]) } /** - * t4_read_pace_tbl - read the pace table - * @adap: the adapter - * @pace_vals: holds the returned values - * - * Returns the values of TP's pace table in microseconds. - */ -void t4_read_pace_tbl(struct adapter *adap, unsigned int pace_vals[NTX_SCHED]) -{ - unsigned int i, v; - - for (i = 0; i < NTX_SCHED; i++) { - t4_write_reg(adap, A_TP_PACE_TABLE, 0xffff0000 + i); - v = t4_read_reg(adap, A_TP_PACE_TABLE); - pace_vals[i] = dack_ticks_to_usec(adap, v); - } -} - -/** * t4_tp_wr_bits_indirect - set/clear bits in an indirect TP register * @adap: the adapter * @addr: the indirect TP register address @@ -3392,7 +5113,7 @@ void t4_tp_wr_bits_indirect(struct adapter *adap, unsigned int addr, * * Initialize the congestion control parameters. */ -static void __devinit init_cong_ctrl(unsigned short *a, unsigned short *b) +static void init_cong_ctrl(unsigned short *a, unsigned short *b) { a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = a[6] = a[7] = a[8] = 1; a[9] = 2; @@ -3493,7 +5214,7 @@ int t4_set_pace_tbl(struct adapter *adap, const unsigned int *pace_vals, if (n > NTX_SCHED) return -ERANGE; - + /* convert values from us to dack ticks, rounding to closest value */ for (i = 0; i < n; i++, pace_vals++) { vals[i] = (1000 * *pace_vals + tick_ns / 2) / tick_ns; @@ -3580,46 +5301,6 @@ int t4_set_sched_ipg(struct adapter *adap, int sched, unsigned int ipg) return 0; } -/** - * t4_get_tx_sched - get the configuration of a Tx HW traffic scheduler - * @adap: the adapter - * @sched: the scheduler index - * @kbps: the byte rate in Kbps - * @ipg: the interpacket delay in tenths of nanoseconds - * - * Return the current configuration of a HW Tx scheduler. - */ -void t4_get_tx_sched(struct adapter *adap, unsigned int sched, unsigned int *kbps, - unsigned int *ipg) -{ - unsigned int v, addr, bpt, cpt; - - if (kbps) { - addr = A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2; - t4_write_reg(adap, A_TP_TM_PIO_ADDR, addr); - v = t4_read_reg(adap, A_TP_TM_PIO_DATA); - if (sched & 1) - v >>= 16; - bpt = (v >> 8) & 0xff; - cpt = v & 0xff; - if (!cpt) - *kbps = 0; /* scheduler disabled */ - else { - v = (adap->params.vpd.cclk * 1000) / cpt; /* ticks/s */ - *kbps = (v * bpt) / 125; - } - } - if (ipg) { - addr = A_TP_TX_MOD_Q1_Q0_TIMER_SEPARATOR - sched / 2; - t4_write_reg(adap, A_TP_TM_PIO_ADDR, addr); - v = t4_read_reg(adap, A_TP_TM_PIO_DATA); - if (sched & 1) - v >>= 16; - v &= 0xffff; - *ipg = (10000 * v) / core_ticks_per_usec(adap); - } -} - /* * Calculates a rate in bytes/s given the number of 256-byte units per 4K core * clocks. The formula is @@ -3653,14 +5334,18 @@ void t4_get_chan_txrate(struct adapter *adap, u64 *nic_rate, u64 *ofld_rate) v = t4_read_reg(adap, A_TP_TX_TRATE); nic_rate[0] = chan_rate(adap, G_TNLRATE0(v)); nic_rate[1] = chan_rate(adap, G_TNLRATE1(v)); - nic_rate[2] = chan_rate(adap, G_TNLRATE2(v)); - nic_rate[3] = chan_rate(adap, G_TNLRATE3(v)); + if (adap->chip_params->nchan > 2) { + nic_rate[2] = chan_rate(adap, G_TNLRATE2(v)); + nic_rate[3] = chan_rate(adap, G_TNLRATE3(v)); + } v = t4_read_reg(adap, A_TP_TX_ORATE); ofld_rate[0] = chan_rate(adap, G_OFDRATE0(v)); ofld_rate[1] = chan_rate(adap, G_OFDRATE1(v)); - ofld_rate[2] = chan_rate(adap, G_OFDRATE2(v)); - ofld_rate[3] = chan_rate(adap, G_OFDRATE3(v)); + if (adap->chip_params->nchan > 2) { + ofld_rate[2] = chan_rate(adap, G_OFDRATE2(v)); + ofld_rate[3] = chan_rate(adap, G_OFDRATE3(v)); + } } /** @@ -3695,10 +5380,10 @@ int t4_set_trace_filter(struct adapter *adap, const struct trace_params *tp, * TODO - After T4 data book is updated, specify the exact * section below. * - * See T4 data book - MPS section for a complete description - * of the below if..else handling of A_MPS_TRC_CFG register + * See T4 data book - MPS section for a complete description + * of the below if..else handling of A_MPS_TRC_CFG register * value. - */ + */ cfg = t4_read_reg(adap, A_MPS_TRC_CFG); if (cfg & F_TRCMULTIFILTER) { /* @@ -3707,10 +5392,10 @@ int t4_set_trace_filter(struct adapter *adap, const struct trace_params *tp, * minus 2 flits for CPL_TRACE_PKT header. */ if (tp->snap_len > ((10 * 1024 / 4) - (2 * 8))) - return -EINVAL; + return -EINVAL; } else { /* - * If multiple tracers are disabled, to avoid deadlocks + * If multiple tracers are disabled, to avoid deadlocks * maximum packet capture size of 9600 bytes is recommended. * Also in this mode, only trace0 can be enabled and running. */ @@ -3803,7 +5488,7 @@ void t4_pmtx_get_stats(struct adapter *adap, u32 cnt[], u64 cycles[]) int i; u32 data[2]; - for (i = 0; i < PM_NSTATS; i++) { + for (i = 0; i < adap->chip_params->pm_stats_cnt; i++) { t4_write_reg(adap, A_PM_TX_STAT_CONFIG, i + 1); cnt[i] = t4_read_reg(adap, A_PM_TX_STAT_COUNT); if (is_t4(adap)) @@ -3830,12 +5515,12 @@ void t4_pmrx_get_stats(struct adapter *adap, u32 cnt[], u64 cycles[]) int i; u32 data[2]; - for (i = 0; i < PM_NSTATS; i++) { + for (i = 0; i < adap->chip_params->pm_stats_cnt; i++) { t4_write_reg(adap, A_PM_RX_STAT_CONFIG, i + 1); cnt[i] = t4_read_reg(adap, A_PM_RX_STAT_COUNT); - if (is_t4(adap)) + if (is_t4(adap)) { cycles[i] = t4_read_reg64(adap, A_PM_RX_STAT_LSB); - else { + } else { t4_read_indirect(adap, A_PM_RX_DBG_CTRL, A_PM_RX_DBG_DATA, data, 2, A_PM_RX_DBG_STAT_MSB); @@ -3845,7 +5530,7 @@ void t4_pmrx_get_stats(struct adapter *adap, u32 cnt[], u64 cycles[]) } /** - * get_mps_bg_map - return the buffer groups associated with a port + * t4_get_mps_bg_map - return the buffer groups associated with a port * @adap: the adapter * @idx: the port index * @@ -3853,20 +5538,50 @@ void t4_pmrx_get_stats(struct adapter *adap, u32 cnt[], u64 cycles[]) * with the given port. Bit i is set if buffer group i is used by the * port. */ -static unsigned int get_mps_bg_map(struct adapter *adap, int idx) +static unsigned int t4_get_mps_bg_map(struct adapter *adap, int idx) { u32 n = G_NUMPORTS(t4_read_reg(adap, A_MPS_CMN_CTL)); if (n == 0) return idx == 0 ? 0xf : 0; - if (n == 1) + if (n == 1 && chip_id(adap) <= CHELSIO_T5) return idx < 2 ? (3 << (2 * idx)) : 0; return 1 << idx; } /** + * t4_get_port_type_description - return Port Type string description + * @port_type: firmware Port Type enumeration + */ +const char *t4_get_port_type_description(enum fw_port_type port_type) +{ + static const char *const port_type_description[] = { + "Fiber_XFI", + "Fiber_XAUI", + "BT_SGMII", + "BT_XFI", + "BT_XAUI", + "KX4", + "CX4", + "KX", + "KR", + "SFP", + "BP_AP", + "BP4_AP", + "QSFP_10G", + "QSA", + "QSFP", + "BP40_BA", + }; + + if (port_type < ARRAY_SIZE(port_type_description)) + return port_type_description[port_type]; + return "UNKNOWN"; +} + +/** * t4_get_port_stats_offset - collect port stats relative to a previous - * snapshot + * snapshot * @adap: The adapter * @idx: The port * @stats: Current stats to fill @@ -3896,7 +5611,7 @@ void t4_get_port_stats_offset(struct adapter *adap, int idx, */ void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p) { - u32 bgmap = get_mps_bg_map(adap, idx); + u32 bgmap = t4_get_mps_bg_map(adap, idx); #define GET_STAT(name) \ t4_read_reg64(adap, \ @@ -3904,57 +5619,57 @@ void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p) T5_PORT_REG(idx, A_MPS_PORT_STAT_##name##_L))) #define GET_STAT_COM(name) t4_read_reg64(adap, A_MPS_STAT_##name##_L) - p->tx_pause = GET_STAT(TX_PORT_PAUSE); - p->tx_octets = GET_STAT(TX_PORT_BYTES); - p->tx_frames = GET_STAT(TX_PORT_FRAMES); - p->tx_bcast_frames = GET_STAT(TX_PORT_BCAST); - p->tx_mcast_frames = GET_STAT(TX_PORT_MCAST); - p->tx_ucast_frames = GET_STAT(TX_PORT_UCAST); - p->tx_error_frames = GET_STAT(TX_PORT_ERROR); - p->tx_frames_64 = GET_STAT(TX_PORT_64B); - p->tx_frames_65_127 = GET_STAT(TX_PORT_65B_127B); - p->tx_frames_128_255 = GET_STAT(TX_PORT_128B_255B); - p->tx_frames_256_511 = GET_STAT(TX_PORT_256B_511B); - p->tx_frames_512_1023 = GET_STAT(TX_PORT_512B_1023B); - p->tx_frames_1024_1518 = GET_STAT(TX_PORT_1024B_1518B); - p->tx_frames_1519_max = GET_STAT(TX_PORT_1519B_MAX); - p->tx_drop = GET_STAT(TX_PORT_DROP); - p->tx_ppp0 = GET_STAT(TX_PORT_PPP0); - p->tx_ppp1 = GET_STAT(TX_PORT_PPP1); - p->tx_ppp2 = GET_STAT(TX_PORT_PPP2); - p->tx_ppp3 = GET_STAT(TX_PORT_PPP3); - p->tx_ppp4 = GET_STAT(TX_PORT_PPP4); - p->tx_ppp5 = GET_STAT(TX_PORT_PPP5); - p->tx_ppp6 = GET_STAT(TX_PORT_PPP6); - p->tx_ppp7 = GET_STAT(TX_PORT_PPP7); - - p->rx_pause = GET_STAT(RX_PORT_PAUSE); - p->rx_octets = GET_STAT(RX_PORT_BYTES); - p->rx_frames = GET_STAT(RX_PORT_FRAMES); - p->rx_bcast_frames = GET_STAT(RX_PORT_BCAST); - p->rx_mcast_frames = GET_STAT(RX_PORT_MCAST); - p->rx_ucast_frames = GET_STAT(RX_PORT_UCAST); - p->rx_too_long = GET_STAT(RX_PORT_MTU_ERROR); - p->rx_jabber = GET_STAT(RX_PORT_MTU_CRC_ERROR); - p->rx_fcs_err = GET_STAT(RX_PORT_CRC_ERROR); - p->rx_len_err = GET_STAT(RX_PORT_LEN_ERROR); - p->rx_symbol_err = GET_STAT(RX_PORT_SYM_ERROR); - p->rx_runt = GET_STAT(RX_PORT_LESS_64B); - p->rx_frames_64 = GET_STAT(RX_PORT_64B); - p->rx_frames_65_127 = GET_STAT(RX_PORT_65B_127B); - p->rx_frames_128_255 = GET_STAT(RX_PORT_128B_255B); - p->rx_frames_256_511 = GET_STAT(RX_PORT_256B_511B); - p->rx_frames_512_1023 = GET_STAT(RX_PORT_512B_1023B); - p->rx_frames_1024_1518 = GET_STAT(RX_PORT_1024B_1518B); - p->rx_frames_1519_max = GET_STAT(RX_PORT_1519B_MAX); - p->rx_ppp0 = GET_STAT(RX_PORT_PPP0); - p->rx_ppp1 = GET_STAT(RX_PORT_PPP1); - p->rx_ppp2 = GET_STAT(RX_PORT_PPP2); - p->rx_ppp3 = GET_STAT(RX_PORT_PPP3); - p->rx_ppp4 = GET_STAT(RX_PORT_PPP4); - p->rx_ppp5 = GET_STAT(RX_PORT_PPP5); - p->rx_ppp6 = GET_STAT(RX_PORT_PPP6); - p->rx_ppp7 = GET_STAT(RX_PORT_PPP7); + p->tx_pause = GET_STAT(TX_PORT_PAUSE); + p->tx_octets = GET_STAT(TX_PORT_BYTES); + p->tx_frames = GET_STAT(TX_PORT_FRAMES); + p->tx_bcast_frames = GET_STAT(TX_PORT_BCAST); + p->tx_mcast_frames = GET_STAT(TX_PORT_MCAST); + p->tx_ucast_frames = GET_STAT(TX_PORT_UCAST); + p->tx_error_frames = GET_STAT(TX_PORT_ERROR); + p->tx_frames_64 = GET_STAT(TX_PORT_64B); + p->tx_frames_65_127 = GET_STAT(TX_PORT_65B_127B); + p->tx_frames_128_255 = GET_STAT(TX_PORT_128B_255B); + p->tx_frames_256_511 = GET_STAT(TX_PORT_256B_511B); + p->tx_frames_512_1023 = GET_STAT(TX_PORT_512B_1023B); + p->tx_frames_1024_1518 = GET_STAT(TX_PORT_1024B_1518B); + p->tx_frames_1519_max = GET_STAT(TX_PORT_1519B_MAX); + p->tx_drop = GET_STAT(TX_PORT_DROP); + p->tx_ppp0 = GET_STAT(TX_PORT_PPP0); + p->tx_ppp1 = GET_STAT(TX_PORT_PPP1); + p->tx_ppp2 = GET_STAT(TX_PORT_PPP2); + p->tx_ppp3 = GET_STAT(TX_PORT_PPP3); + p->tx_ppp4 = GET_STAT(TX_PORT_PPP4); + p->tx_ppp5 = GET_STAT(TX_PORT_PPP5); + p->tx_ppp6 = GET_STAT(TX_PORT_PPP6); + p->tx_ppp7 = GET_STAT(TX_PORT_PPP7); + + p->rx_pause = GET_STAT(RX_PORT_PAUSE); + p->rx_octets = GET_STAT(RX_PORT_BYTES); + p->rx_frames = GET_STAT(RX_PORT_FRAMES); + p->rx_bcast_frames = GET_STAT(RX_PORT_BCAST); + p->rx_mcast_frames = GET_STAT(RX_PORT_MCAST); + p->rx_ucast_frames = GET_STAT(RX_PORT_UCAST); + p->rx_too_long = GET_STAT(RX_PORT_MTU_ERROR); + p->rx_jabber = GET_STAT(RX_PORT_MTU_CRC_ERROR); + p->rx_fcs_err = GET_STAT(RX_PORT_CRC_ERROR); + p->rx_len_err = GET_STAT(RX_PORT_LEN_ERROR); + p->rx_symbol_err = GET_STAT(RX_PORT_SYM_ERROR); + p->rx_runt = GET_STAT(RX_PORT_LESS_64B); + p->rx_frames_64 = GET_STAT(RX_PORT_64B); + p->rx_frames_65_127 = GET_STAT(RX_PORT_65B_127B); + p->rx_frames_128_255 = GET_STAT(RX_PORT_128B_255B); + p->rx_frames_256_511 = GET_STAT(RX_PORT_256B_511B); + p->rx_frames_512_1023 = GET_STAT(RX_PORT_512B_1023B); + p->rx_frames_1024_1518 = GET_STAT(RX_PORT_1024B_1518B); + p->rx_frames_1519_max = GET_STAT(RX_PORT_1519B_MAX); + p->rx_ppp0 = GET_STAT(RX_PORT_PPP0); + p->rx_ppp1 = GET_STAT(RX_PORT_PPP1); + p->rx_ppp2 = GET_STAT(RX_PORT_PPP2); + p->rx_ppp3 = GET_STAT(RX_PORT_PPP3); + p->rx_ppp4 = GET_STAT(RX_PORT_PPP4); + p->rx_ppp5 = GET_STAT(RX_PORT_PPP5); + p->rx_ppp6 = GET_STAT(RX_PORT_PPP6); + p->rx_ppp7 = GET_STAT(RX_PORT_PPP7); p->rx_ovflow0 = (bgmap & 1) ? GET_STAT_COM(RX_BG_0_MAC_DROP_FRAME) : 0; p->rx_ovflow1 = (bgmap & 2) ? GET_STAT_COM(RX_BG_1_MAC_DROP_FRAME) : 0; @@ -3970,39 +5685,6 @@ void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p) } /** - * t4_clr_port_stats - clear port statistics - * @adap: the adapter - * @idx: the port index - * - * Clear HW statistics for the given port. - */ -void t4_clr_port_stats(struct adapter *adap, int idx) -{ - unsigned int i; - u32 bgmap = get_mps_bg_map(adap, idx); - u32 port_base_addr; - - if (is_t4(adap)) - port_base_addr = PORT_BASE(idx); - else - port_base_addr = T5_PORT_BASE(idx); - - for (i = A_MPS_PORT_STAT_TX_PORT_BYTES_L; - i <= A_MPS_PORT_STAT_TX_PORT_PPP7_H; i += 8) - t4_write_reg(adap, port_base_addr + i, 0); - for (i = A_MPS_PORT_STAT_RX_PORT_BYTES_L; - i <= A_MPS_PORT_STAT_RX_PORT_LESS_64B_H; i += 8) - t4_write_reg(adap, port_base_addr + i, 0); - for (i = 0; i < 4; i++) - if (bgmap & (1 << i)) { - t4_write_reg(adap, - A_MPS_STAT_RX_BG_0_MAC_DROP_FRAME_L + i * 8, 0); - t4_write_reg(adap, - A_MPS_STAT_RX_BG_0_MAC_TRUNC_FRAME_L + i * 8, 0); - } -} - -/** * t4_get_lb_stats - collect loopback port statistics * @adap: the adapter * @idx: the loopback port index @@ -4012,7 +5694,7 @@ void t4_clr_port_stats(struct adapter *adap, int idx) */ void t4_get_lb_stats(struct adapter *adap, int idx, struct lb_port_stats *p) { - u32 bgmap = get_mps_bg_map(adap, idx); + u32 bgmap = t4_get_mps_bg_map(adap, idx); #define GET_STAT(name) \ t4_read_reg64(adap, \ @@ -4021,21 +5703,21 @@ void t4_get_lb_stats(struct adapter *adap, int idx, struct lb_port_stats *p) T5_PORT_REG(idx, A_MPS_PORT_STAT_LB_PORT_##name##_L))) #define GET_STAT_COM(name) t4_read_reg64(adap, A_MPS_STAT_##name##_L) - p->octets = GET_STAT(BYTES); - p->frames = GET_STAT(FRAMES); - p->bcast_frames = GET_STAT(BCAST); - p->mcast_frames = GET_STAT(MCAST); - p->ucast_frames = GET_STAT(UCAST); - p->error_frames = GET_STAT(ERROR); - - p->frames_64 = GET_STAT(64B); - p->frames_65_127 = GET_STAT(65B_127B); - p->frames_128_255 = GET_STAT(128B_255B); - p->frames_256_511 = GET_STAT(256B_511B); - p->frames_512_1023 = GET_STAT(512B_1023B); - p->frames_1024_1518 = GET_STAT(1024B_1518B); - p->frames_1519_max = GET_STAT(1519B_MAX); - p->drop = GET_STAT(DROP_FRAMES); + p->octets = GET_STAT(BYTES); + p->frames = GET_STAT(FRAMES); + p->bcast_frames = GET_STAT(BCAST); + p->mcast_frames = GET_STAT(MCAST); + p->ucast_frames = GET_STAT(UCAST); + p->error_frames = GET_STAT(ERROR); + + p->frames_64 = GET_STAT(64B); + p->frames_65_127 = GET_STAT(65B_127B); + p->frames_128_255 = GET_STAT(128B_255B); + p->frames_256_511 = GET_STAT(256B_511B); + p->frames_512_1023 = GET_STAT(512B_1023B); + p->frames_1024_1518 = GET_STAT(1024B_1518B); + p->frames_1519_max = GET_STAT(1519B_MAX); + p->drop = GET_STAT(DROP_FRAMES); p->ovflow0 = (bgmap & 1) ? GET_STAT_COM(RX_BG_0_LB_DROP_FRAME) : 0; p->ovflow1 = (bgmap & 2) ? GET_STAT_COM(RX_BG_1_LB_DROP_FRAME) : 0; @@ -4149,43 +5831,49 @@ int t4_wol_pat_enable(struct adapter *adap, unsigned int port, unsigned int map, return 0; } -/** - * t4_mk_filtdelwr - create a delete filter WR - * @ftid: the filter ID - * @wr: the filter work request to populate - * @qid: ingress queue to receive the delete notification +/* t4_mk_filtdelwr - create a delete filter WR + * @ftid: the filter ID + * @wr: the filter work request to populate + * @qid: ingress queue to receive the delete notification * - * Creates a filter work request to delete the supplied filter. If @qid is - * negative the delete notification is suppressed. + * Creates a filter work request to delete the supplied filter. If @qid is + * negative the delete notification is suppressed. */ void t4_mk_filtdelwr(unsigned int ftid, struct fw_filter_wr *wr, int qid) { memset(wr, 0, sizeof(*wr)); - wr->op_pkd = htonl(V_FW_WR_OP(FW_FILTER_WR)); - wr->len16_pkd = htonl(V_FW_WR_LEN16(sizeof(*wr) / 16)); - wr->tid_to_iq = htonl(V_FW_FILTER_WR_TID(ftid) | - V_FW_FILTER_WR_NOREPLY(qid < 0)); - wr->del_filter_to_l2tix = htonl(F_FW_FILTER_WR_DEL_FILTER); + wr->op_pkd = cpu_to_be32(V_FW_WR_OP(FW_FILTER_WR)); + wr->len16_pkd = cpu_to_be32(V_FW_WR_LEN16(sizeof(*wr) / 16)); + wr->tid_to_iq = cpu_to_be32(V_FW_FILTER_WR_TID(ftid) | + V_FW_FILTER_WR_NOREPLY(qid < 0)); + wr->del_filter_to_l2tix = cpu_to_be32(F_FW_FILTER_WR_DEL_FILTER); if (qid >= 0) - wr->rx_chan_rx_rpl_iq = htons(V_FW_FILTER_WR_RX_RPL_IQ(qid)); + wr->rx_chan_rx_rpl_iq = + cpu_to_be16(V_FW_FILTER_WR_RX_RPL_IQ(qid)); } #define INIT_CMD(var, cmd, rd_wr) do { \ - (var).op_to_write = htonl(V_FW_CMD_OP(FW_##cmd##_CMD) | \ - F_FW_CMD_REQUEST | F_FW_CMD_##rd_wr); \ - (var).retval_len16 = htonl(FW_LEN16(var)); \ + (var).op_to_write = cpu_to_be32(V_FW_CMD_OP(FW_##cmd##_CMD) | \ + F_FW_CMD_REQUEST | \ + F_FW_CMD_##rd_wr); \ + (var).retval_len16 = cpu_to_be32(FW_LEN16(var)); \ } while (0) -int t4_fwaddrspace_write(struct adapter *adap, unsigned int mbox, u32 addr, u32 val) +int t4_fwaddrspace_write(struct adapter *adap, unsigned int mbox, + u32 addr, u32 val) { + u32 ldst_addrspace; struct fw_ldst_cmd c; memset(&c, 0, sizeof(c)); - c.op_to_addrspace = htonl(V_FW_CMD_OP(FW_LDST_CMD) | F_FW_CMD_REQUEST | - F_FW_CMD_WRITE | V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_FIRMWARE)); - c.cycles_to_len16 = htonl(FW_LEN16(c)); - c.u.addrval.addr = htonl(addr); - c.u.addrval.val = htonl(val); + ldst_addrspace = V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_FIRMWARE); + c.op_to_addrspace = cpu_to_be32(V_FW_CMD_OP(FW_LDST_CMD) | + F_FW_CMD_REQUEST | + F_FW_CMD_WRITE | + ldst_addrspace); + c.cycles_to_len16 = cpu_to_be32(FW_LEN16(c)); + c.u.addrval.addr = cpu_to_be32(addr); + c.u.addrval.val = cpu_to_be32(val); return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); } @@ -4205,19 +5893,22 @@ int t4_mdio_rd(struct adapter *adap, unsigned int mbox, unsigned int phy_addr, unsigned int mmd, unsigned int reg, unsigned int *valp) { int ret; + u32 ldst_addrspace; struct fw_ldst_cmd c; memset(&c, 0, sizeof(c)); - c.op_to_addrspace = htonl(V_FW_CMD_OP(FW_LDST_CMD) | F_FW_CMD_REQUEST | - F_FW_CMD_READ | V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_MDIO)); - c.cycles_to_len16 = htonl(FW_LEN16(c)); - c.u.mdio.paddr_mmd = htons(V_FW_LDST_CMD_PADDR(phy_addr) | - V_FW_LDST_CMD_MMD(mmd)); - c.u.mdio.raddr = htons(reg); + ldst_addrspace = V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_MDIO); + c.op_to_addrspace = cpu_to_be32(V_FW_CMD_OP(FW_LDST_CMD) | + F_FW_CMD_REQUEST | F_FW_CMD_READ | + ldst_addrspace); + c.cycles_to_len16 = cpu_to_be32(FW_LEN16(c)); + c.u.mdio.paddr_mmd = cpu_to_be16(V_FW_LDST_CMD_PADDR(phy_addr) | + V_FW_LDST_CMD_MMD(mmd)); + c.u.mdio.raddr = cpu_to_be16(reg); ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); if (ret == 0) - *valp = ntohs(c.u.mdio.rval); + *valp = be16_to_cpu(c.u.mdio.rval); return ret; } @@ -4235,197 +5926,212 @@ int t4_mdio_rd(struct adapter *adap, unsigned int mbox, unsigned int phy_addr, int t4_mdio_wr(struct adapter *adap, unsigned int mbox, unsigned int phy_addr, unsigned int mmd, unsigned int reg, unsigned int val) { + u32 ldst_addrspace; struct fw_ldst_cmd c; memset(&c, 0, sizeof(c)); - c.op_to_addrspace = htonl(V_FW_CMD_OP(FW_LDST_CMD) | F_FW_CMD_REQUEST | - F_FW_CMD_WRITE | V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_MDIO)); - c.cycles_to_len16 = htonl(FW_LEN16(c)); - c.u.mdio.paddr_mmd = htons(V_FW_LDST_CMD_PADDR(phy_addr) | - V_FW_LDST_CMD_MMD(mmd)); - c.u.mdio.raddr = htons(reg); - c.u.mdio.rval = htons(val); + ldst_addrspace = V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_MDIO); + c.op_to_addrspace = cpu_to_be32(V_FW_CMD_OP(FW_LDST_CMD) | + F_FW_CMD_REQUEST | F_FW_CMD_WRITE | + ldst_addrspace); + c.cycles_to_len16 = cpu_to_be32(FW_LEN16(c)); + c.u.mdio.paddr_mmd = cpu_to_be16(V_FW_LDST_CMD_PADDR(phy_addr) | + V_FW_LDST_CMD_MMD(mmd)); + c.u.mdio.raddr = cpu_to_be16(reg); + c.u.mdio.rval = cpu_to_be16(val); return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); } /** - * t4_i2c_rd - read I2C data from adapter - * @adap: the adapter - * @port: Port number if per-port device; <0 if not - * @devid: per-port device ID or absolute device ID - * @offset: byte offset into device I2C space - * @len: byte length of I2C space data - * @buf: buffer in which to return I2C data * - * Reads the I2C data from the indicated device and location. - */ -int t4_i2c_rd(struct adapter *adap, unsigned int mbox, - int port, unsigned int devid, - unsigned int offset, unsigned int len, - u8 *buf) -{ - struct fw_ldst_cmd ldst; - int ret; - - if (port >= 4 || - devid >= 256 || - offset >= 256 || - len > sizeof ldst.u.i2c.data) - return -EINVAL; - - memset(&ldst, 0, sizeof ldst); - ldst.op_to_addrspace = - cpu_to_be32(V_FW_CMD_OP(FW_LDST_CMD) | - F_FW_CMD_REQUEST | - F_FW_CMD_READ | - V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_I2C)); - ldst.cycles_to_len16 = cpu_to_be32(FW_LEN16(ldst)); - ldst.u.i2c.pid = (port < 0 ? 0xff : port); - ldst.u.i2c.did = devid; - ldst.u.i2c.boffset = offset; - ldst.u.i2c.blen = len; - ret = t4_wr_mbox(adap, mbox, &ldst, sizeof ldst, &ldst); - if (!ret) - memcpy(buf, ldst.u.i2c.data, len); - return ret; -} - -/** - * t4_i2c_wr - write I2C data to adapter + * t4_sge_decode_idma_state - decode the idma state * @adap: the adapter - * @port: Port number if per-port device; <0 if not - * @devid: per-port device ID or absolute device ID - * @offset: byte offset into device I2C space - * @len: byte length of I2C space data - * @buf: buffer containing new I2C data - * - * Write the I2C data to the indicated device and location. - */ -int t4_i2c_wr(struct adapter *adap, unsigned int mbox, - int port, unsigned int devid, - unsigned int offset, unsigned int len, - u8 *buf) -{ - struct fw_ldst_cmd ldst; + * @state: the state idma is stuck in + */ +void t4_sge_decode_idma_state(struct adapter *adapter, int state) +{ + static const char * const t4_decode[] = { + "IDMA_IDLE", + "IDMA_PUSH_MORE_CPL_FIFO", + "IDMA_PUSH_CPL_MSG_HEADER_TO_FIFO", + "Not used", + "IDMA_PHYSADDR_SEND_PCIEHDR", + "IDMA_PHYSADDR_SEND_PAYLOAD_FIRST", + "IDMA_PHYSADDR_SEND_PAYLOAD", + "IDMA_SEND_FIFO_TO_IMSG", + "IDMA_FL_REQ_DATA_FL_PREP", + "IDMA_FL_REQ_DATA_FL", + "IDMA_FL_DROP", + "IDMA_FL_H_REQ_HEADER_FL", + "IDMA_FL_H_SEND_PCIEHDR", + "IDMA_FL_H_PUSH_CPL_FIFO", + "IDMA_FL_H_SEND_CPL", + "IDMA_FL_H_SEND_IP_HDR_FIRST", + "IDMA_FL_H_SEND_IP_HDR", + "IDMA_FL_H_REQ_NEXT_HEADER_FL", + "IDMA_FL_H_SEND_NEXT_PCIEHDR", + "IDMA_FL_H_SEND_IP_HDR_PADDING", + "IDMA_FL_D_SEND_PCIEHDR", + "IDMA_FL_D_SEND_CPL_AND_IP_HDR", + "IDMA_FL_D_REQ_NEXT_DATA_FL", + "IDMA_FL_SEND_PCIEHDR", + "IDMA_FL_PUSH_CPL_FIFO", + "IDMA_FL_SEND_CPL", + "IDMA_FL_SEND_PAYLOAD_FIRST", + "IDMA_FL_SEND_PAYLOAD", + "IDMA_FL_REQ_NEXT_DATA_FL", + "IDMA_FL_SEND_NEXT_PCIEHDR", + "IDMA_FL_SEND_PADDING", + "IDMA_FL_SEND_COMPLETION_TO_IMSG", + "IDMA_FL_SEND_FIFO_TO_IMSG", + "IDMA_FL_REQ_DATAFL_DONE", + "IDMA_FL_REQ_HEADERFL_DONE", + }; + static const char * const t5_decode[] = { + "IDMA_IDLE", + "IDMA_ALMOST_IDLE", + "IDMA_PUSH_MORE_CPL_FIFO", + "IDMA_PUSH_CPL_MSG_HEADER_TO_FIFO", + "IDMA_SGEFLRFLUSH_SEND_PCIEHDR", + "IDMA_PHYSADDR_SEND_PCIEHDR", + "IDMA_PHYSADDR_SEND_PAYLOAD_FIRST", + "IDMA_PHYSADDR_SEND_PAYLOAD", + "IDMA_SEND_FIFO_TO_IMSG", + "IDMA_FL_REQ_DATA_FL", + "IDMA_FL_DROP", + "IDMA_FL_DROP_SEND_INC", + "IDMA_FL_H_REQ_HEADER_FL", + "IDMA_FL_H_SEND_PCIEHDR", + "IDMA_FL_H_PUSH_CPL_FIFO", + "IDMA_FL_H_SEND_CPL", + "IDMA_FL_H_SEND_IP_HDR_FIRST", + "IDMA_FL_H_SEND_IP_HDR", + "IDMA_FL_H_REQ_NEXT_HEADER_FL", + "IDMA_FL_H_SEND_NEXT_PCIEHDR", + "IDMA_FL_H_SEND_IP_HDR_PADDING", + "IDMA_FL_D_SEND_PCIEHDR", + "IDMA_FL_D_SEND_CPL_AND_IP_HDR", + "IDMA_FL_D_REQ_NEXT_DATA_FL", + "IDMA_FL_SEND_PCIEHDR", + "IDMA_FL_PUSH_CPL_FIFO", + "IDMA_FL_SEND_CPL", + "IDMA_FL_SEND_PAYLOAD_FIRST", + "IDMA_FL_SEND_PAYLOAD", + "IDMA_FL_REQ_NEXT_DATA_FL", + "IDMA_FL_SEND_NEXT_PCIEHDR", + "IDMA_FL_SEND_PADDING", + "IDMA_FL_SEND_COMPLETION_TO_IMSG", + }; + static const char * const t6_decode[] = { + "IDMA_IDLE", + "IDMA_PUSH_MORE_CPL_FIFO", + "IDMA_PUSH_CPL_MSG_HEADER_TO_FIFO", + "IDMA_SGEFLRFLUSH_SEND_PCIEHDR", + "IDMA_PHYSADDR_SEND_PCIEHDR", + "IDMA_PHYSADDR_SEND_PAYLOAD_FIRST", + "IDMA_PHYSADDR_SEND_PAYLOAD", + "IDMA_FL_REQ_DATA_FL", + "IDMA_FL_DROP", + "IDMA_FL_DROP_SEND_INC", + "IDMA_FL_H_REQ_HEADER_FL", + "IDMA_FL_H_SEND_PCIEHDR", + "IDMA_FL_H_PUSH_CPL_FIFO", + "IDMA_FL_H_SEND_CPL", + "IDMA_FL_H_SEND_IP_HDR_FIRST", + "IDMA_FL_H_SEND_IP_HDR", + "IDMA_FL_H_REQ_NEXT_HEADER_FL", + "IDMA_FL_H_SEND_NEXT_PCIEHDR", + "IDMA_FL_H_SEND_IP_HDR_PADDING", + "IDMA_FL_D_SEND_PCIEHDR", + "IDMA_FL_D_SEND_CPL_AND_IP_HDR", + "IDMA_FL_D_REQ_NEXT_DATA_FL", + "IDMA_FL_SEND_PCIEHDR", + "IDMA_FL_PUSH_CPL_FIFO", + "IDMA_FL_SEND_CPL", + "IDMA_FL_SEND_PAYLOAD_FIRST", + "IDMA_FL_SEND_PAYLOAD", + "IDMA_FL_REQ_NEXT_DATA_FL", + "IDMA_FL_SEND_NEXT_PCIEHDR", + "IDMA_FL_SEND_PADDING", + "IDMA_FL_SEND_COMPLETION_TO_IMSG", + }; + static const u32 sge_regs[] = { + A_SGE_DEBUG_DATA_LOW_INDEX_2, + A_SGE_DEBUG_DATA_LOW_INDEX_3, + A_SGE_DEBUG_DATA_HIGH_INDEX_10, + }; + const char * const *sge_idma_decode; + int sge_idma_decode_nstates; + int i; + unsigned int chip_version = chip_id(adapter); - if (port >= 4 || - devid >= 256 || - offset >= 256 || - len > sizeof ldst.u.i2c.data) - return -EINVAL; + /* Select the right set of decode strings to dump depending on the + * adapter chip type. + */ + switch (chip_version) { + case CHELSIO_T4: + sge_idma_decode = (const char * const *)t4_decode; + sge_idma_decode_nstates = ARRAY_SIZE(t4_decode); + break; - memset(&ldst, 0, sizeof ldst); - ldst.op_to_addrspace = - cpu_to_be32(V_FW_CMD_OP(FW_LDST_CMD) | - F_FW_CMD_REQUEST | - F_FW_CMD_WRITE | - V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_I2C)); - ldst.cycles_to_len16 = cpu_to_be32(FW_LEN16(ldst)); - ldst.u.i2c.pid = (port < 0 ? 0xff : port); - ldst.u.i2c.did = devid; - ldst.u.i2c.boffset = offset; - ldst.u.i2c.blen = len; - memcpy(ldst.u.i2c.data, buf, len); - return t4_wr_mbox(adap, mbox, &ldst, sizeof ldst, &ldst); -} + case CHELSIO_T5: + sge_idma_decode = (const char * const *)t5_decode; + sge_idma_decode_nstates = ARRAY_SIZE(t5_decode); + break; -/** - * t4_sge_ctxt_flush - flush the SGE context cache - * @adap: the adapter - * @mbox: mailbox to use for the FW command - * - * Issues a FW command through the given mailbox to flush the - * SGE context cache. - */ -int t4_sge_ctxt_flush(struct adapter *adap, unsigned int mbox) -{ - int ret; - struct fw_ldst_cmd c; + case CHELSIO_T6: + sge_idma_decode = (const char * const *)t6_decode; + sge_idma_decode_nstates = ARRAY_SIZE(t6_decode); + break; - memset(&c, 0, sizeof(c)); - c.op_to_addrspace = htonl(V_FW_CMD_OP(FW_LDST_CMD) | F_FW_CMD_REQUEST | - F_FW_CMD_READ | - V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_SGE_EGRC)); - c.cycles_to_len16 = htonl(FW_LEN16(c)); - c.u.idctxt.msg_ctxtflush = htonl(F_FW_LDST_CMD_CTXTFLUSH); + default: + CH_ERR(adapter, "Unsupported chip version %d\n", chip_version); + return; + } - ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); - return ret; + if (state < sge_idma_decode_nstates) + CH_WARN(adapter, "idma state %s\n", sge_idma_decode[state]); + else + CH_WARN(adapter, "idma state %d unknown\n", state); + + for (i = 0; i < ARRAY_SIZE(sge_regs); i++) + CH_WARN(adapter, "SGE register %#x value %#x\n", + sge_regs[i], t4_read_reg(adapter, sge_regs[i])); } /** - * t4_sge_ctxt_rd - read an SGE context through FW - * @adap: the adapter - * @mbox: mailbox to use for the FW command - * @cid: the context id - * @ctype: the context type - * @data: where to store the context data + * t4_sge_ctxt_flush - flush the SGE context cache + * @adap: the adapter + * @mbox: mailbox to use for the FW command * - * Issues a FW command through the given mailbox to read an SGE context. + * Issues a FW command through the given mailbox to flush the + * SGE context cache. */ -int t4_sge_ctxt_rd(struct adapter *adap, unsigned int mbox, unsigned int cid, - enum ctxt_type ctype, u32 *data) +int t4_sge_ctxt_flush(struct adapter *adap, unsigned int mbox) { int ret; + u32 ldst_addrspace; struct fw_ldst_cmd c; - if (ctype == CTXT_EGRESS) - ret = FW_LDST_ADDRSPC_SGE_EGRC; - else if (ctype == CTXT_INGRESS) - ret = FW_LDST_ADDRSPC_SGE_INGC; - else if (ctype == CTXT_FLM) - ret = FW_LDST_ADDRSPC_SGE_FLMC; - else - ret = FW_LDST_ADDRSPC_SGE_CONMC; - memset(&c, 0, sizeof(c)); - c.op_to_addrspace = htonl(V_FW_CMD_OP(FW_LDST_CMD) | F_FW_CMD_REQUEST | - F_FW_CMD_READ | V_FW_LDST_CMD_ADDRSPACE(ret)); - c.cycles_to_len16 = htonl(FW_LEN16(c)); - c.u.idctxt.physid = htonl(cid); + ldst_addrspace = V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_SGE_EGRC); + c.op_to_addrspace = cpu_to_be32(V_FW_CMD_OP(FW_LDST_CMD) | + F_FW_CMD_REQUEST | F_FW_CMD_READ | + ldst_addrspace); + c.cycles_to_len16 = cpu_to_be32(FW_LEN16(c)); + c.u.idctxt.msg_ctxtflush = cpu_to_be32(F_FW_LDST_CMD_CTXTFLUSH); ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); - if (ret == 0) { - data[0] = ntohl(c.u.idctxt.ctxt_data0); - data[1] = ntohl(c.u.idctxt.ctxt_data1); - data[2] = ntohl(c.u.idctxt.ctxt_data2); - data[3] = ntohl(c.u.idctxt.ctxt_data3); - data[4] = ntohl(c.u.idctxt.ctxt_data4); - data[5] = ntohl(c.u.idctxt.ctxt_data5); - } - return ret; -} - -/** - * t4_sge_ctxt_rd_bd - read an SGE context bypassing FW - * @adap: the adapter - * @cid: the context id - * @ctype: the context type - * @data: where to store the context data - * - * Reads an SGE context directly, bypassing FW. This is only for - * debugging when FW is unavailable. - */ -int t4_sge_ctxt_rd_bd(struct adapter *adap, unsigned int cid, enum ctxt_type ctype, - u32 *data) -{ - int i, ret; - - t4_write_reg(adap, A_SGE_CTXT_CMD, V_CTXTQID(cid) | V_CTXTTYPE(ctype)); - ret = t4_wait_op_done(adap, A_SGE_CTXT_CMD, F_BUSY, 0, 3, 1); - if (!ret) - for (i = A_SGE_CTXT_DATA0; i <= A_SGE_CTXT_DATA5; i += 4) - *data++ = t4_read_reg(adap, i); return ret; } /** - * t4_fw_hello - establish communication with FW - * @adap: the adapter - * @mbox: mailbox to use for the FW command - * @evt_mbox: mailbox to receive async FW events - * @master: specifies the caller's willingness to be the device master + * t4_fw_hello - establish communication with FW + * @adap: the adapter + * @mbox: mailbox to use for the FW command + * @evt_mbox: mailbox to receive async FW events + * @master: specifies the caller's willingness to be the device master * @state: returns the current device state (if non-NULL) * * Issues a command to establish communication with FW. Returns either @@ -4443,11 +6149,11 @@ int t4_fw_hello(struct adapter *adap, unsigned int mbox, unsigned int evt_mbox, retry: memset(&c, 0, sizeof(c)); INIT_CMD(c, HELLO, WRITE); - c.err_to_clearinit = htonl( + c.err_to_clearinit = cpu_to_be32( V_FW_HELLO_CMD_MASTERDIS(master == MASTER_CANT) | V_FW_HELLO_CMD_MASTERFORCE(master == MASTER_MUST) | - V_FW_HELLO_CMD_MBMASTER(master == MASTER_MUST ? mbox : - M_FW_HELLO_CMD_MBMASTER) | + V_FW_HELLO_CMD_MBMASTER(master == MASTER_MUST ? + mbox : M_FW_HELLO_CMD_MBMASTER) | V_FW_HELLO_CMD_MBASYNCNOT(evt_mbox) | V_FW_HELLO_CMD_STAGE(FW_HELLO_CMD_STAGE_OS) | F_FW_HELLO_CMD_CLEARINIT); @@ -4468,7 +6174,7 @@ retry: return ret; } - v = ntohl(c.err_to_clearinit); + v = be32_to_cpu(c.err_to_clearinit); master_mbox = G_FW_HELLO_CMD_MBMASTER(v); if (state) { if (v & F_FW_HELLO_CMD_ERR) @@ -4580,7 +6286,7 @@ int t4_fw_reset(struct adapter *adap, unsigned int mbox, int reset) memset(&c, 0, sizeof(c)); INIT_CMD(c, RESET, WRITE); - c.val = htonl(reset); + c.val = cpu_to_be32(reset); return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); } @@ -4613,8 +6319,8 @@ int t4_fw_halt(struct adapter *adap, unsigned int mbox, int force) memset(&c, 0, sizeof(c)); INIT_CMD(c, RESET, WRITE); - c.val = htonl(F_PIORST | F_PIORSTMODE); - c.halt_pkd = htonl(F_FW_RESET_CMD_HALT); + c.val = cpu_to_be32(F_PIORST | F_PIORSTMODE); + c.halt_pkd = cpu_to_be32(F_FW_RESET_CMD_HALT); ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); } @@ -4633,7 +6339,8 @@ int t4_fw_halt(struct adapter *adap, unsigned int mbox, int force) */ if (ret == 0 || force) { t4_set_reg_field(adap, A_CIM_BOOT_CFG, F_UPCRST, F_UPCRST); - t4_set_reg_field(adap, A_PCIE_FW, F_PCIE_FW_HALT, F_PCIE_FW_HALT); + t4_set_reg_field(adap, A_PCIE_FW, F_PCIE_FW_HALT, + F_PCIE_FW_HALT); } /* @@ -4731,9 +6438,13 @@ int t4_fw_upgrade(struct adapter *adap, unsigned int mbox, const u8 *fw_data, unsigned int size, int force) { const struct fw_hdr *fw_hdr = (const struct fw_hdr *)fw_data; - unsigned int bootstrap = ntohl(fw_hdr->magic) == FW_HDR_MAGIC_BOOTSTRAP; + unsigned int bootstrap = + be32_to_cpu(fw_hdr->magic) == FW_HDR_MAGIC_BOOTSTRAP; int reset, ret; + if (!t4_fw_matches_chip(adap, fw_hdr)) + return -EINVAL; + if (!bootstrap) { ret = t4_fw_halt(adap, mbox, force); if (ret < 0 && !force) @@ -4752,7 +6463,7 @@ int t4_fw_upgrade(struct adapter *adap, unsigned int mbox, * the newly loaded firmware will handle this right by checking * its header flags to see if it advertises the capability. */ - reset = ((ntohl(fw_hdr->flags) & FW_HDR_FLAGS_RESET_HALT) == 0); + reset = ((be32_to_cpu(fw_hdr->flags) & FW_HDR_FLAGS_RESET_HALT) == 0); return t4_fw_restart(adap, mbox, reset); } @@ -4774,7 +6485,7 @@ int t4_fw_initialize(struct adapter *adap, unsigned int mbox) } /** - * t4_query_params - query FW or device parameters + * t4_query_params_rw - query FW or device parameters * @adap: the adapter * @mbox: mailbox to use for the FW command * @pf: the PF @@ -4782,13 +6493,14 @@ int t4_fw_initialize(struct adapter *adap, unsigned int mbox) * @nparams: the number of parameters * @params: the parameter names * @val: the parameter values + * @rw: Write and read flag * * Reads the value of FW or device parameters. Up to 7 parameters can be * queried at once. */ -int t4_query_params(struct adapter *adap, unsigned int mbox, unsigned int pf, - unsigned int vf, unsigned int nparams, const u32 *params, - u32 *val) +int t4_query_params_rw(struct adapter *adap, unsigned int mbox, unsigned int pf, + unsigned int vf, unsigned int nparams, const u32 *params, + u32 *val, int rw) { int i, ret; struct fw_params_cmd c; @@ -4798,21 +6510,73 @@ int t4_query_params(struct adapter *adap, unsigned int mbox, unsigned int pf, return -EINVAL; memset(&c, 0, sizeof(c)); - c.op_to_vfn = htonl(V_FW_CMD_OP(FW_PARAMS_CMD) | F_FW_CMD_REQUEST | - F_FW_CMD_READ | V_FW_PARAMS_CMD_PFN(pf) | - V_FW_PARAMS_CMD_VFN(vf)); - c.retval_len16 = htonl(FW_LEN16(c)); - - for (i = 0; i < nparams; i++, p += 2, params++) - *p = htonl(*params); + c.op_to_vfn = cpu_to_be32(V_FW_CMD_OP(FW_PARAMS_CMD) | + F_FW_CMD_REQUEST | F_FW_CMD_READ | + V_FW_PARAMS_CMD_PFN(pf) | + V_FW_PARAMS_CMD_VFN(vf)); + c.retval_len16 = cpu_to_be32(FW_LEN16(c)); + + for (i = 0; i < nparams; i++) { + *p++ = cpu_to_be32(*params++); + if (rw) + *p = cpu_to_be32(*(val + i)); + p++; + } ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); if (ret == 0) for (i = 0, p = &c.param[0].val; i < nparams; i++, p += 2) - *val++ = ntohl(*p); + *val++ = be32_to_cpu(*p); return ret; } +int t4_query_params(struct adapter *adap, unsigned int mbox, unsigned int pf, + unsigned int vf, unsigned int nparams, const u32 *params, + u32 *val) +{ + return t4_query_params_rw(adap, mbox, pf, vf, nparams, params, val, 0); +} + +/** + * t4_set_params_timeout - sets FW or device parameters + * @adap: the adapter + * @mbox: mailbox to use for the FW command + * @pf: the PF + * @vf: the VF + * @nparams: the number of parameters + * @params: the parameter names + * @val: the parameter values + * @timeout: the timeout time + * + * Sets the value of FW or device parameters. Up to 7 parameters can be + * specified at once. + */ +int t4_set_params_timeout(struct adapter *adap, unsigned int mbox, + unsigned int pf, unsigned int vf, + unsigned int nparams, const u32 *params, + const u32 *val, int timeout) +{ + struct fw_params_cmd c; + __be32 *p = &c.param[0].mnem; + + if (nparams > 7) + return -EINVAL; + + memset(&c, 0, sizeof(c)); + c.op_to_vfn = cpu_to_be32(V_FW_CMD_OP(FW_PARAMS_CMD) | + F_FW_CMD_REQUEST | F_FW_CMD_WRITE | + V_FW_PARAMS_CMD_PFN(pf) | + V_FW_PARAMS_CMD_VFN(vf)); + c.retval_len16 = cpu_to_be32(FW_LEN16(c)); + + while (nparams--) { + *p++ = cpu_to_be32(*params++); + *p++ = cpu_to_be32(*val++); + } + + return t4_wr_mbox_timeout(adap, mbox, &c, sizeof(c), NULL, timeout); +} + /** * t4_set_params - sets FW or device parameters * @adap: the adapter @@ -4830,26 +6594,8 @@ int t4_set_params(struct adapter *adap, unsigned int mbox, unsigned int pf, unsigned int vf, unsigned int nparams, const u32 *params, const u32 *val) { - struct fw_params_cmd c; - __be32 *p = &c.param[0].mnem; - - if (nparams > 7) - return -EINVAL; - - memset(&c, 0, sizeof(c)); - c.op_to_vfn = htonl(V_FW_CMD_OP(FW_PARAMS_CMD) | F_FW_CMD_REQUEST | - F_FW_CMD_WRITE | V_FW_PARAMS_CMD_PFN(pf) | - V_FW_PARAMS_CMD_VFN(vf)); - c.retval_len16 = htonl(FW_LEN16(c)); - - while (nparams--) { - *p++ = htonl(*params); - params++; - *p++ = htonl(*val); - val++; - } - - return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); + return t4_set_params_timeout(adap, mbox, pf, vf, nparams, params, val, + FW_CMD_MAX_TIMEOUT); } /** @@ -4882,18 +6628,19 @@ int t4_cfg_pfvf(struct adapter *adap, unsigned int mbox, unsigned int pf, struct fw_pfvf_cmd c; memset(&c, 0, sizeof(c)); - c.op_to_vfn = htonl(V_FW_CMD_OP(FW_PFVF_CMD) | F_FW_CMD_REQUEST | - F_FW_CMD_WRITE | V_FW_PFVF_CMD_PFN(pf) | - V_FW_PFVF_CMD_VFN(vf)); - c.retval_len16 = htonl(FW_LEN16(c)); - c.niqflint_niq = htonl(V_FW_PFVF_CMD_NIQFLINT(rxqi) | - V_FW_PFVF_CMD_NIQ(rxq)); - c.type_to_neq = htonl(V_FW_PFVF_CMD_CMASK(cmask) | - V_FW_PFVF_CMD_PMASK(pmask) | - V_FW_PFVF_CMD_NEQ(txq)); - c.tc_to_nexactf = htonl(V_FW_PFVF_CMD_TC(tc) | V_FW_PFVF_CMD_NVI(vi) | - V_FW_PFVF_CMD_NEXACTF(nexact)); - c.r_caps_to_nethctrl = htonl(V_FW_PFVF_CMD_R_CAPS(rcaps) | + c.op_to_vfn = cpu_to_be32(V_FW_CMD_OP(FW_PFVF_CMD) | F_FW_CMD_REQUEST | + F_FW_CMD_WRITE | V_FW_PFVF_CMD_PFN(pf) | + V_FW_PFVF_CMD_VFN(vf)); + c.retval_len16 = cpu_to_be32(FW_LEN16(c)); + c.niqflint_niq = cpu_to_be32(V_FW_PFVF_CMD_NIQFLINT(rxqi) | + V_FW_PFVF_CMD_NIQ(rxq)); + c.type_to_neq = cpu_to_be32(V_FW_PFVF_CMD_CMASK(cmask) | + V_FW_PFVF_CMD_PMASK(pmask) | + V_FW_PFVF_CMD_NEQ(txq)); + c.tc_to_nexactf = cpu_to_be32(V_FW_PFVF_CMD_TC(tc) | + V_FW_PFVF_CMD_NVI(vi) | + V_FW_PFVF_CMD_NEXACTF(nexact)); + c.r_caps_to_nethctrl = cpu_to_be32(V_FW_PFVF_CMD_R_CAPS(rcaps) | V_FW_PFVF_CMD_WX_CAPS(wxcaps) | V_FW_PFVF_CMD_NETHCTRL(txq_eth_ctrl)); return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); @@ -4914,6 +6661,7 @@ int t4_cfg_pfvf(struct adapter *adap, unsigned int mbox, unsigned int pf, * * Allocates a virtual interface for the given physical port. If @mac is * not %NULL it contains the MAC addresses of the VI as assigned by FW. + * If @rss_size is %NULL the VI is not assigned any RSS slice by FW. * @mac should be large enough to hold @nmac Ethernet addresses, they are * stored consecutively so the space needed is @nmac * 6 bytes. * Returns a negative error number or the non-negative VI id. @@ -4927,14 +6675,16 @@ int t4_alloc_vi_func(struct adapter *adap, unsigned int mbox, struct fw_vi_cmd c; memset(&c, 0, sizeof(c)); - c.op_to_vfn = htonl(V_FW_CMD_OP(FW_VI_CMD) | F_FW_CMD_REQUEST | - F_FW_CMD_WRITE | F_FW_CMD_EXEC | - V_FW_VI_CMD_PFN(pf) | V_FW_VI_CMD_VFN(vf)); - c.alloc_to_len16 = htonl(F_FW_VI_CMD_ALLOC | FW_LEN16(c)); - c.type_to_viid = htons(V_FW_VI_CMD_TYPE(idstype) | - V_FW_VI_CMD_FUNC(portfunc)); + c.op_to_vfn = cpu_to_be32(V_FW_CMD_OP(FW_VI_CMD) | F_FW_CMD_REQUEST | + F_FW_CMD_WRITE | F_FW_CMD_EXEC | + V_FW_VI_CMD_PFN(pf) | V_FW_VI_CMD_VFN(vf)); + c.alloc_to_len16 = cpu_to_be32(F_FW_VI_CMD_ALLOC | FW_LEN16(c)); + c.type_to_viid = cpu_to_be16(V_FW_VI_CMD_TYPE(idstype) | + V_FW_VI_CMD_FUNC(portfunc)); c.portid_pkd = V_FW_VI_CMD_PORTID(port); c.nmac = nmac - 1; + if(!rss_size) + c.norss_rsssize = F_FW_VI_CMD_NORSS; ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); if (ret) @@ -4954,20 +6704,20 @@ int t4_alloc_vi_func(struct adapter *adap, unsigned int mbox, } } if (rss_size) - *rss_size = G_FW_VI_CMD_RSSSIZE(ntohs(c.norss_rsssize)); - return G_FW_VI_CMD_VIID(htons(c.type_to_viid)); + *rss_size = G_FW_VI_CMD_RSSSIZE(be16_to_cpu(c.norss_rsssize)); + return G_FW_VI_CMD_VIID(be16_to_cpu(c.type_to_viid)); } /** - * t4_alloc_vi - allocate an [Ethernet Function] virtual interface - * @adap: the adapter - * @mbox: mailbox to use for the FW command - * @port: physical port associated with the VI - * @pf: the PF owning the VI - * @vf: the VF owning the VI - * @nmac: number of MAC addresses needed (1 to 5) - * @mac: the MAC addresses of the VI - * @rss_size: size of RSS table slice associated with this VI + * t4_alloc_vi - allocate an [Ethernet Function] virtual interface + * @adap: the adapter + * @mbox: mailbox to use for the FW command + * @port: physical port associated with the VI + * @pf: the PF owning the VI + * @vf: the VF owning the VI + * @nmac: number of MAC addresses needed (1 to 5) + * @mac: the MAC addresses of the VI + * @rss_size: size of RSS table slice associated with this VI * * backwards compatible and convieniance routine to allocate a Virtual * Interface with a Ethernet Port Application Function and Intrustion @@ -4982,14 +6732,14 @@ int t4_alloc_vi(struct adapter *adap, unsigned int mbox, unsigned int port, } /** - * t4_free_vi - free a virtual interface - * @adap: the adapter - * @mbox: mailbox to use for the FW command - * @pf: the PF owning the VI - * @vf: the VF owning the VI - * @viid: virtual interface identifiler + * t4_free_vi - free a virtual interface + * @adap: the adapter + * @mbox: mailbox to use for the FW command + * @pf: the PF owning the VI + * @vf: the VF owning the VI + * @viid: virtual interface identifiler * - * Free a previously allocated virtual interface. + * Free a previously allocated virtual interface. */ int t4_free_vi(struct adapter *adap, unsigned int mbox, unsigned int pf, unsigned int vf, unsigned int viid) @@ -4997,13 +6747,13 @@ int t4_free_vi(struct adapter *adap, unsigned int mbox, unsigned int pf, struct fw_vi_cmd c; memset(&c, 0, sizeof(c)); - c.op_to_vfn = htonl(V_FW_CMD_OP(FW_VI_CMD) | - F_FW_CMD_REQUEST | - F_FW_CMD_EXEC | - V_FW_VI_CMD_PFN(pf) | - V_FW_VI_CMD_VFN(vf)); - c.alloc_to_len16 = htonl(F_FW_VI_CMD_FREE | FW_LEN16(c)); - c.type_to_viid = htons(V_FW_VI_CMD_VIID(viid)); + c.op_to_vfn = cpu_to_be32(V_FW_CMD_OP(FW_VI_CMD) | + F_FW_CMD_REQUEST | + F_FW_CMD_EXEC | + V_FW_VI_CMD_PFN(pf) | + V_FW_VI_CMD_VFN(vf)); + c.alloc_to_len16 = cpu_to_be32(F_FW_VI_CMD_FREE | FW_LEN16(c)); + c.type_to_viid = cpu_to_be16(V_FW_VI_CMD_VIID(viid)); return t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); } @@ -5017,7 +6767,7 @@ int t4_free_vi(struct adapter *adap, unsigned int mbox, unsigned int pf, * @promisc: 1 to enable promiscuous mode, 0 to disable it, -1 no change * @all_multi: 1 to enable all-multi mode, 0 to disable it, -1 no change * @bcast: 1 to enable broadcast Rx, 0 to disable it, -1 no change - * @vlanex: 1 to enable HVLAN extraction, 0 to disable it, -1 no change + * @vlanex: 1 to enable HW VLAN extraction, 0 to disable it, -1 no change * @sleep_ok: if true we may sleep while awaiting command completion * * Sets Rx properties of a virtual interface. @@ -5041,14 +6791,16 @@ int t4_set_rxmode(struct adapter *adap, unsigned int mbox, unsigned int viid, vlanex = M_FW_VI_RXMODE_CMD_VLANEXEN; memset(&c, 0, sizeof(c)); - c.op_to_viid = htonl(V_FW_CMD_OP(FW_VI_RXMODE_CMD) | F_FW_CMD_REQUEST | - F_FW_CMD_WRITE | V_FW_VI_RXMODE_CMD_VIID(viid)); - c.retval_len16 = htonl(FW_LEN16(c)); - c.mtu_to_vlanexen = htonl(V_FW_VI_RXMODE_CMD_MTU(mtu) | - V_FW_VI_RXMODE_CMD_PROMISCEN(promisc) | - V_FW_VI_RXMODE_CMD_ALLMULTIEN(all_multi) | - V_FW_VI_RXMODE_CMD_BROADCASTEN(bcast) | - V_FW_VI_RXMODE_CMD_VLANEXEN(vlanex)); + c.op_to_viid = cpu_to_be32(V_FW_CMD_OP(FW_VI_RXMODE_CMD) | + F_FW_CMD_REQUEST | F_FW_CMD_WRITE | + V_FW_VI_RXMODE_CMD_VIID(viid)); + c.retval_len16 = cpu_to_be32(FW_LEN16(c)); + c.mtu_to_vlanexen = + cpu_to_be32(V_FW_VI_RXMODE_CMD_MTU(mtu) | + V_FW_VI_RXMODE_CMD_PROMISCEN(promisc) | + V_FW_VI_RXMODE_CMD_ALLMULTIEN(all_multi) | + V_FW_VI_RXMODE_CMD_BROADCASTEN(bcast) | + V_FW_VI_RXMODE_CMD_VLANEXEN(vlanex)); return t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), NULL, sleep_ok); } @@ -5081,9 +6833,7 @@ int t4_alloc_mac_filt(struct adapter *adap, unsigned int mbox, int offset, ret = 0; struct fw_vi_mac_cmd c; unsigned int nfilters = 0; - unsigned int max_naddr = is_t4(adap) ? - NUM_MPS_CLS_SRAM_L_INSTANCES : - NUM_MPS_T5_CLS_SRAM_L_INSTANCES; + unsigned int max_naddr = adap->chip_params->mps_tcam_size; unsigned int rem = naddr; if (naddr > max_naddr) @@ -5099,18 +6849,18 @@ int t4_alloc_mac_filt(struct adapter *adap, unsigned int mbox, int i; memset(&c, 0, sizeof(c)); - c.op_to_viid = htonl(V_FW_CMD_OP(FW_VI_MAC_CMD) | - F_FW_CMD_REQUEST | - F_FW_CMD_WRITE | - V_FW_CMD_EXEC(free) | - V_FW_VI_MAC_CMD_VIID(viid)); - c.freemacs_to_len16 = htonl(V_FW_VI_MAC_CMD_FREEMACS(free) | - V_FW_CMD_LEN16(len16)); + c.op_to_viid = cpu_to_be32(V_FW_CMD_OP(FW_VI_MAC_CMD) | + F_FW_CMD_REQUEST | + F_FW_CMD_WRITE | + V_FW_CMD_EXEC(free) | + V_FW_VI_MAC_CMD_VIID(viid)); + c.freemacs_to_len16 = cpu_to_be32(V_FW_VI_MAC_CMD_FREEMACS(free) | + V_FW_CMD_LEN16(len16)); for (i = 0, p = c.u.exact; i < fw_naddr; i++, p++) { - p->valid_to_idx = htons( - F_FW_VI_MAC_CMD_VALID | - V_FW_VI_MAC_CMD_IDX(FW_VI_MAC_ADD_MAC)); + p->valid_to_idx = + cpu_to_be16(F_FW_VI_MAC_CMD_VALID | + V_FW_VI_MAC_CMD_IDX(FW_VI_MAC_ADD_MAC)); memcpy(p->macaddr, addr[offset+i], sizeof(p->macaddr)); } @@ -5124,7 +6874,8 @@ int t4_alloc_mac_filt(struct adapter *adap, unsigned int mbox, break; for (i = 0, p = c.u.exact; i < fw_naddr; i++, p++) { - u16 index = G_FW_VI_MAC_CMD_IDX(ntohs(p->valid_to_idx)); + u16 index = G_FW_VI_MAC_CMD_IDX( + be16_to_cpu(p->valid_to_idx)); if (idx) idx[offset+i] = (index >= max_naddr @@ -5142,7 +6893,7 @@ int t4_alloc_mac_filt(struct adapter *adap, unsigned int mbox, } if (ret == 0 || ret == -FW_ENOMEM) - ret = nfilters; + ret = nfilters; return ret; } @@ -5174,26 +6925,25 @@ int t4_change_mac(struct adapter *adap, unsigned int mbox, unsigned int viid, int ret, mode; struct fw_vi_mac_cmd c; struct fw_vi_mac_exact *p = c.u.exact; - unsigned int max_mac_addr = is_t4(adap) ? - NUM_MPS_CLS_SRAM_L_INSTANCES : - NUM_MPS_T5_CLS_SRAM_L_INSTANCES; + unsigned int max_mac_addr = adap->chip_params->mps_tcam_size; - if (idx < 0) /* new allocation */ + if (idx < 0) /* new allocation */ idx = persist ? FW_VI_MAC_ADD_PERSIST_MAC : FW_VI_MAC_ADD_MAC; mode = add_smt ? FW_VI_MAC_SMT_AND_MPSTCAM : FW_VI_MAC_MPS_TCAM_ENTRY; memset(&c, 0, sizeof(c)); - c.op_to_viid = htonl(V_FW_CMD_OP(FW_VI_MAC_CMD) | F_FW_CMD_REQUEST | - F_FW_CMD_WRITE | V_FW_VI_MAC_CMD_VIID(viid)); - c.freemacs_to_len16 = htonl(V_FW_CMD_LEN16(1)); - p->valid_to_idx = htons(F_FW_VI_MAC_CMD_VALID | - V_FW_VI_MAC_CMD_SMAC_RESULT(mode) | - V_FW_VI_MAC_CMD_IDX(idx)); + c.op_to_viid = cpu_to_be32(V_FW_CMD_OP(FW_VI_MAC_CMD) | + F_FW_CMD_REQUEST | F_FW_CMD_WRITE | + V_FW_VI_MAC_CMD_VIID(viid)); + c.freemacs_to_len16 = cpu_to_be32(V_FW_CMD_LEN16(1)); + p->valid_to_idx = cpu_to_be16(F_FW_VI_MAC_CMD_VALID | + V_FW_VI_MAC_CMD_SMAC_RESULT(mode) | + V_FW_VI_MAC_CMD_IDX(idx)); memcpy(p->macaddr, addr, sizeof(p->macaddr)); ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); if (ret == 0) { - ret = G_FW_VI_MAC_CMD_IDX(ntohs(p->valid_to_idx)); + ret = G_FW_VI_MAC_CMD_IDX(be16_to_cpu(p->valid_to_idx)); if (ret >= max_mac_addr) ret = -ENOMEM; } @@ -5215,18 +6965,48 @@ int t4_set_addr_hash(struct adapter *adap, unsigned int mbox, unsigned int viid, bool ucast, u64 vec, bool sleep_ok) { struct fw_vi_mac_cmd c; + u32 val; memset(&c, 0, sizeof(c)); - c.op_to_viid = htonl(V_FW_CMD_OP(FW_VI_MAC_CMD) | F_FW_CMD_REQUEST | - F_FW_CMD_WRITE | V_FW_VI_ENABLE_CMD_VIID(viid)); - c.freemacs_to_len16 = htonl(F_FW_VI_MAC_CMD_HASHVECEN | - V_FW_VI_MAC_CMD_HASHUNIEN(ucast) | - V_FW_CMD_LEN16(1)); + c.op_to_viid = cpu_to_be32(V_FW_CMD_OP(FW_VI_MAC_CMD) | + F_FW_CMD_REQUEST | F_FW_CMD_WRITE | + V_FW_VI_ENABLE_CMD_VIID(viid)); + val = V_FW_VI_MAC_CMD_ENTRY_TYPE(FW_VI_MAC_TYPE_HASHVEC) | + V_FW_VI_MAC_CMD_HASHUNIEN(ucast) | V_FW_CMD_LEN16(1); + c.freemacs_to_len16 = cpu_to_be32(val); c.u.hash.hashvec = cpu_to_be64(vec); return t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), NULL, sleep_ok); } /** + * t4_enable_vi_params - enable/disable a virtual interface + * @adap: the adapter + * @mbox: mailbox to use for the FW command + * @viid: the VI id + * @rx_en: 1=enable Rx, 0=disable Rx + * @tx_en: 1=enable Tx, 0=disable Tx + * @dcb_en: 1=enable delivery of Data Center Bridging messages. + * + * Enables/disables a virtual interface. Note that setting DCB Enable + * only makes sense when enabling a Virtual Interface ... + */ +int t4_enable_vi_params(struct adapter *adap, unsigned int mbox, + unsigned int viid, bool rx_en, bool tx_en, bool dcb_en) +{ + struct fw_vi_enable_cmd c; + + memset(&c, 0, sizeof(c)); + c.op_to_viid = cpu_to_be32(V_FW_CMD_OP(FW_VI_ENABLE_CMD) | + F_FW_CMD_REQUEST | F_FW_CMD_EXEC | + V_FW_VI_ENABLE_CMD_VIID(viid)); + c.ien_to_len16 = cpu_to_be32(V_FW_VI_ENABLE_CMD_IEN(rx_en) | + V_FW_VI_ENABLE_CMD_EEN(tx_en) | + V_FW_VI_ENABLE_CMD_DCB_INFO(dcb_en) | + FW_LEN16(c)); + return t4_wr_mbox_ns(adap, mbox, &c, sizeof(c), NULL); +} + +/** * t4_enable_vi - enable/disable a virtual interface * @adap: the adapter * @mbox: mailbox to use for the FW command @@ -5234,19 +7014,13 @@ int t4_set_addr_hash(struct adapter *adap, unsigned int mbox, unsigned int viid, * @rx_en: 1=enable Rx, 0=disable Rx * @tx_en: 1=enable Tx, 0=disable Tx * - * Enables/disables a virtual interface. + * Enables/disables a virtual interface. Note that setting DCB Enable + * only makes sense when enabling a Virtual Interface ... */ int t4_enable_vi(struct adapter *adap, unsigned int mbox, unsigned int viid, bool rx_en, bool tx_en) { - struct fw_vi_enable_cmd c; - - memset(&c, 0, sizeof(c)); - c.op_to_viid = htonl(V_FW_CMD_OP(FW_VI_ENABLE_CMD) | F_FW_CMD_REQUEST | - F_FW_CMD_EXEC | V_FW_VI_ENABLE_CMD_VIID(viid)); - c.ien_to_len16 = htonl(V_FW_VI_ENABLE_CMD_IEN(rx_en) | - V_FW_VI_ENABLE_CMD_EEN(tx_en) | FW_LEN16(c)); - return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); + return t4_enable_vi_params(adap, mbox, viid, rx_en, tx_en, 0); } /** @@ -5264,41 +7038,44 @@ int t4_identify_port(struct adapter *adap, unsigned int mbox, unsigned int viid, struct fw_vi_enable_cmd c; memset(&c, 0, sizeof(c)); - c.op_to_viid = htonl(V_FW_CMD_OP(FW_VI_ENABLE_CMD) | F_FW_CMD_REQUEST | - F_FW_CMD_EXEC | V_FW_VI_ENABLE_CMD_VIID(viid)); - c.ien_to_len16 = htonl(F_FW_VI_ENABLE_CMD_LED | FW_LEN16(c)); - c.blinkdur = htons(nblinks); + c.op_to_viid = cpu_to_be32(V_FW_CMD_OP(FW_VI_ENABLE_CMD) | + F_FW_CMD_REQUEST | F_FW_CMD_EXEC | + V_FW_VI_ENABLE_CMD_VIID(viid)); + c.ien_to_len16 = cpu_to_be32(F_FW_VI_ENABLE_CMD_LED | FW_LEN16(c)); + c.blinkdur = cpu_to_be16(nblinks); return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); } /** - * t4_iq_start_stop - enable/disable an ingress queue and its FLs + * t4_iq_stop - stop an ingress queue and its FLs * @adap: the adapter * @mbox: mailbox to use for the FW command - * @start: %true to enable the queues, %false to disable them * @pf: the PF owning the queues * @vf: the VF owning the queues + * @iqtype: the ingress queue type (FW_IQ_TYPE_FL_INT_CAP, etc.) * @iqid: ingress queue id * @fl0id: FL0 queue id or 0xffff if no attached FL0 * @fl1id: FL1 queue id or 0xffff if no attached FL1 * - * Starts or stops an ingress queue and its associated FLs, if any. + * Stops an ingress queue and its associated FLs, if any. This causes + * any current or future data/messages destined for these queues to be + * tossed. */ -int t4_iq_start_stop(struct adapter *adap, unsigned int mbox, bool start, - unsigned int pf, unsigned int vf, unsigned int iqid, - unsigned int fl0id, unsigned int fl1id) +int t4_iq_stop(struct adapter *adap, unsigned int mbox, unsigned int pf, + unsigned int vf, unsigned int iqtype, unsigned int iqid, + unsigned int fl0id, unsigned int fl1id) { struct fw_iq_cmd c; memset(&c, 0, sizeof(c)); - c.op_to_vfn = htonl(V_FW_CMD_OP(FW_IQ_CMD) | F_FW_CMD_REQUEST | - F_FW_CMD_EXEC | V_FW_IQ_CMD_PFN(pf) | - V_FW_IQ_CMD_VFN(vf)); - c.alloc_to_len16 = htonl(V_FW_IQ_CMD_IQSTART(start) | - V_FW_IQ_CMD_IQSTOP(!start) | FW_LEN16(c)); - c.iqid = htons(iqid); - c.fl0id = htons(fl0id); - c.fl1id = htons(fl1id); + c.op_to_vfn = cpu_to_be32(V_FW_CMD_OP(FW_IQ_CMD) | F_FW_CMD_REQUEST | + F_FW_CMD_EXEC | V_FW_IQ_CMD_PFN(pf) | + V_FW_IQ_CMD_VFN(vf)); + c.alloc_to_len16 = cpu_to_be32(F_FW_IQ_CMD_IQSTOP | FW_LEN16(c)); + c.type_to_iqandstindex = cpu_to_be32(V_FW_IQ_CMD_TYPE(iqtype)); + c.iqid = cpu_to_be16(iqid); + c.fl0id = cpu_to_be16(fl0id); + c.fl1id = cpu_to_be16(fl1id); return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); } @@ -5322,14 +7099,14 @@ int t4_iq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, struct fw_iq_cmd c; memset(&c, 0, sizeof(c)); - c.op_to_vfn = htonl(V_FW_CMD_OP(FW_IQ_CMD) | F_FW_CMD_REQUEST | - F_FW_CMD_EXEC | V_FW_IQ_CMD_PFN(pf) | - V_FW_IQ_CMD_VFN(vf)); - c.alloc_to_len16 = htonl(F_FW_IQ_CMD_FREE | FW_LEN16(c)); - c.type_to_iqandstindex = htonl(V_FW_IQ_CMD_TYPE(iqtype)); - c.iqid = htons(iqid); - c.fl0id = htons(fl0id); - c.fl1id = htons(fl1id); + c.op_to_vfn = cpu_to_be32(V_FW_CMD_OP(FW_IQ_CMD) | F_FW_CMD_REQUEST | + F_FW_CMD_EXEC | V_FW_IQ_CMD_PFN(pf) | + V_FW_IQ_CMD_VFN(vf)); + c.alloc_to_len16 = cpu_to_be32(F_FW_IQ_CMD_FREE | FW_LEN16(c)); + c.type_to_iqandstindex = cpu_to_be32(V_FW_IQ_CMD_TYPE(iqtype)); + c.iqid = cpu_to_be16(iqid); + c.fl0id = cpu_to_be16(fl0id); + c.fl1id = cpu_to_be16(fl1id); return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); } @@ -5349,11 +7126,12 @@ int t4_eth_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, struct fw_eq_eth_cmd c; memset(&c, 0, sizeof(c)); - c.op_to_vfn = htonl(V_FW_CMD_OP(FW_EQ_ETH_CMD) | F_FW_CMD_REQUEST | - F_FW_CMD_EXEC | V_FW_EQ_ETH_CMD_PFN(pf) | - V_FW_EQ_ETH_CMD_VFN(vf)); - c.alloc_to_len16 = htonl(F_FW_EQ_ETH_CMD_FREE | FW_LEN16(c)); - c.eqid_pkd = htonl(V_FW_EQ_ETH_CMD_EQID(eqid)); + c.op_to_vfn = cpu_to_be32(V_FW_CMD_OP(FW_EQ_ETH_CMD) | + F_FW_CMD_REQUEST | F_FW_CMD_EXEC | + V_FW_EQ_ETH_CMD_PFN(pf) | + V_FW_EQ_ETH_CMD_VFN(vf)); + c.alloc_to_len16 = cpu_to_be32(F_FW_EQ_ETH_CMD_FREE | FW_LEN16(c)); + c.eqid_pkd = cpu_to_be32(V_FW_EQ_ETH_CMD_EQID(eqid)); return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); } @@ -5373,11 +7151,12 @@ int t4_ctrl_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, struct fw_eq_ctrl_cmd c; memset(&c, 0, sizeof(c)); - c.op_to_vfn = htonl(V_FW_CMD_OP(FW_EQ_CTRL_CMD) | F_FW_CMD_REQUEST | - F_FW_CMD_EXEC | V_FW_EQ_CTRL_CMD_PFN(pf) | - V_FW_EQ_CTRL_CMD_VFN(vf)); - c.alloc_to_len16 = htonl(F_FW_EQ_CTRL_CMD_FREE | FW_LEN16(c)); - c.cmpliqid_eqid = htonl(V_FW_EQ_CTRL_CMD_EQID(eqid)); + c.op_to_vfn = cpu_to_be32(V_FW_CMD_OP(FW_EQ_CTRL_CMD) | + F_FW_CMD_REQUEST | F_FW_CMD_EXEC | + V_FW_EQ_CTRL_CMD_PFN(pf) | + V_FW_EQ_CTRL_CMD_VFN(vf)); + c.alloc_to_len16 = cpu_to_be32(F_FW_EQ_CTRL_CMD_FREE | FW_LEN16(c)); + c.cmpliqid_eqid = cpu_to_be32(V_FW_EQ_CTRL_CMD_EQID(eqid)); return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); } @@ -5397,15 +7176,41 @@ int t4_ofld_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, struct fw_eq_ofld_cmd c; memset(&c, 0, sizeof(c)); - c.op_to_vfn = htonl(V_FW_CMD_OP(FW_EQ_OFLD_CMD) | F_FW_CMD_REQUEST | - F_FW_CMD_EXEC | V_FW_EQ_OFLD_CMD_PFN(pf) | - V_FW_EQ_OFLD_CMD_VFN(vf)); - c.alloc_to_len16 = htonl(F_FW_EQ_OFLD_CMD_FREE | FW_LEN16(c)); - c.eqid_pkd = htonl(V_FW_EQ_OFLD_CMD_EQID(eqid)); + c.op_to_vfn = cpu_to_be32(V_FW_CMD_OP(FW_EQ_OFLD_CMD) | + F_FW_CMD_REQUEST | F_FW_CMD_EXEC | + V_FW_EQ_OFLD_CMD_PFN(pf) | + V_FW_EQ_OFLD_CMD_VFN(vf)); + c.alloc_to_len16 = cpu_to_be32(F_FW_EQ_OFLD_CMD_FREE | FW_LEN16(c)); + c.eqid_pkd = cpu_to_be32(V_FW_EQ_OFLD_CMD_EQID(eqid)); return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); } /** + * t4_link_down_rc_str - return a string for a Link Down Reason Code + * @link_down_rc: Link Down Reason Code + * + * Returns a string representation of the Link Down Reason Code. + */ +const char *t4_link_down_rc_str(unsigned char link_down_rc) +{ + static const char *reason[] = { + "Link Down", + "Remote Fault", + "Auto-negotiation Failure", + "Reserved3", + "Insufficient Airflow", + "Unable To Determine Reason", + "No RX Signal Detected", + "Reserved7", + }; + + if (link_down_rc >= ARRAY_SIZE(reason)) + return "Bad Reason Code"; + + return reason[link_down_rc]; +} + +/** * t4_handle_fw_rpl - process a FW reply message * @adap: the adapter * @rpl: start of the FW message @@ -5416,15 +7221,16 @@ int t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl) { u8 opcode = *(const u8 *)rpl; const struct fw_port_cmd *p = (const void *)rpl; - unsigned int action = G_FW_PORT_CMD_ACTION(ntohl(p->action_to_len16)); + unsigned int action = + G_FW_PORT_CMD_ACTION(be32_to_cpu(p->action_to_len16)); if (opcode == FW_PORT_CMD && action == FW_PORT_ACTION_GET_PORT_INFO) { /* link/module state change message */ int speed = 0, fc = 0, i; - int chan = G_FW_PORT_CMD_PORTID(ntohl(p->op_to_portid)); + int chan = G_FW_PORT_CMD_PORTID(be32_to_cpu(p->op_to_portid)); struct port_info *pi = NULL; struct link_config *lc; - u32 stat = ntohl(p->u.info.lstatus_to_modtype); + u32 stat = be32_to_cpu(p->u.info.lstatus_to_modtype); int link_ok = (stat & F_FW_PORT_CMD_LSTATUS) != 0; u32 mod = G_FW_PORT_CMD_MODTYPE(stat); @@ -5433,13 +7239,13 @@ int t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl) if (stat & F_FW_PORT_CMD_TXPAUSE) fc |= PAUSE_TX; if (stat & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_100M)) - speed = SPEED_100; + speed = 100; else if (stat & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_1G)) - speed = SPEED_1000; + speed = 1000; else if (stat & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_10G)) - speed = SPEED_10000; + speed = 10000; else if (stat & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_40G)) - speed = SPEED_40000; + speed = 40000; for_each_port(adap, i) { pi = adap2pinfo(adap, i); @@ -5464,12 +7270,11 @@ int t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl) lc->link_ok = link_ok; lc->speed = speed; lc->fc = fc; - lc->supported = ntohs(p->u.info.pcap); + lc->supported = be16_to_cpu(p->u.info.pcap); t4_os_link_changed(adap, i, link_ok, reason); } } else { - CH_WARN_RATELIMIT(adap, - "Unknown firmware reply 0x%x (0x%x)\n", opcode, action); + CH_WARN_RATELIMIT(adap, "Unknown firmware reply %d\n", opcode); return -EINVAL; } return 0; @@ -5483,7 +7288,7 @@ int t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl) * Determines a card's PCI mode and associated parameters, such as speed * and width. */ -static void __devinit get_pci_mode(struct adapter *adapter, +static void get_pci_mode(struct adapter *adapter, struct pci_params *p) { u16 val; @@ -5505,8 +7310,7 @@ static void __devinit get_pci_mode(struct adapter *adapter, * Initializes the SW state maintained for each link, including the link's * capabilities and default speed/flow-control/autonegotiation settings. */ -static void __devinit init_link_config(struct link_config *lc, - unsigned int caps) +static void init_link_config(struct link_config *lc, unsigned int caps) { lc->supported = caps; lc->requested_speed = 0; @@ -5522,21 +7326,43 @@ static void __devinit init_link_config(struct link_config *lc, } } -static int __devinit get_flash_params(struct adapter *adapter) +struct flash_desc { + u32 vendor_and_model_id; + u32 size_mb; +}; + +int t4_get_flash_params(struct adapter *adapter) { + /* + * Table for non-Numonix supported flash parts. Numonix parts are left + * to the preexisting well-tested code. All flash parts have 64KB + * sectors. + */ + static struct flash_desc supported_flash[] = { + { 0x150201, 4 << 20 }, /* Spansion 4MB S25FL032P */ + }; + int ret; u32 info = 0; ret = sf1_write(adapter, 1, 1, 0, SF_RD_ID); if (!ret) ret = sf1_read(adapter, 3, 0, 1, &info); - t4_write_reg(adapter, A_SF_OP, 0); /* unlock SF */ + t4_write_reg(adapter, A_SF_OP, 0); /* unlock SF */ if (ret < 0) return ret; - if ((info & 0xff) != 0x20) /* not a Numonix flash */ + for (ret = 0; ret < ARRAY_SIZE(supported_flash); ++ret) + if (supported_flash[ret].vendor_and_model_id == info) { + adapter->params.sf_size = supported_flash[ret].size_mb; + adapter->params.sf_nsec = + adapter->params.sf_size / SF_SEC_SIZE; + return 0; + } + + if ((info & 0xff) != 0x20) /* not a Numonix flash */ return -EINVAL; - info >>= 16; /* log2 of size */ + info >>= 16; /* log2 of size */ if (info >= 0x14 && info < 0x18) adapter->params.sf_nsec = 1 << (info - 16); else if (info == 0x18) @@ -5544,10 +7370,20 @@ static int __devinit get_flash_params(struct adapter *adapter) else return -EINVAL; adapter->params.sf_size = 1 << info; + + /* + * We should ~probably~ reject adapters with FLASHes which are too + * small but we have some legacy FPGAs with small FLASHes that we'd + * still like to use. So instead we emit a scary message ... + */ + if (adapter->params.sf_size < FLASH_MIN_SIZE) + CH_WARN(adapter, "WARNING!!! FLASH size %#x < %#x!!!\n", + adapter->params.sf_size, FLASH_MIN_SIZE); + return 0; } -static void __devinit set_pcie_completion_timeout(struct adapter *adapter, +static void set_pcie_completion_timeout(struct adapter *adapter, u8 range) { u16 val; @@ -5562,16 +7398,64 @@ static void __devinit set_pcie_completion_timeout(struct adapter *adapter, } } +static const struct chip_params *get_chip_params(int chipid) +{ + static const struct chip_params chip_params[] = { + { + /* T4 */ + .nchan = NCHAN, + .pm_stats_cnt = PM_NSTATS, + .cng_ch_bits_log = 2, + .nsched_cls = 15, + .cim_num_obq = CIM_NUM_OBQ, + .mps_rplc_size = 128, + .vfcount = 128, + .sge_fl_db = F_DBPRIO, + .mps_tcam_size = NUM_MPS_CLS_SRAM_L_INSTANCES, + }, + { + /* T5 */ + .nchan = NCHAN, + .pm_stats_cnt = PM_NSTATS, + .cng_ch_bits_log = 2, + .nsched_cls = 16, + .cim_num_obq = CIM_NUM_OBQ_T5, + .mps_rplc_size = 128, + .vfcount = 128, + .sge_fl_db = F_DBPRIO | F_DBTYPE, + .mps_tcam_size = NUM_MPS_T5_CLS_SRAM_L_INSTANCES, + }, + { + /* T6 */ + .nchan = T6_NCHAN, + .pm_stats_cnt = T6_PM_NSTATS, + .cng_ch_bits_log = 3, + .nsched_cls = 16, + .cim_num_obq = CIM_NUM_OBQ_T5, + .mps_rplc_size = 256, + .vfcount = 256, + .sge_fl_db = 0, + .mps_tcam_size = NUM_MPS_T5_CLS_SRAM_L_INSTANCES, + }, + }; + + chipid -= CHELSIO_T4; + if (chipid < 0 || chipid >= ARRAY_SIZE(chip_params)) + return NULL; + + return &chip_params[chipid]; +} + /** * t4_prep_adapter - prepare SW and HW for operation * @adapter: the adapter - * @reset: if true perform a HW reset + * @buf: temporary space of at least VPD_LEN size provided by the caller. * * Initialize adapter SW state for the various HW modules, set initial * values for some adapter tunables, take PHYs out of reset, and * initialize the MDIO interface. */ -int __devinit t4_prep_adapter(struct adapter *adapter) +int t4_prep_adapter(struct adapter *adapter, u8 *buf) { int ret; uint16_t device_id; @@ -5592,20 +7476,25 @@ int __devinit t4_prep_adapter(struct adapter *adapter) return -EINVAL; } } + + adapter->chip_params = get_chip_params(chip_id(adapter)); + if (adapter->chip_params == NULL) + return -EINVAL; + adapter->params.pci.vpd_cap_addr = t4_os_find_pci_capability(adapter, PCI_CAP_ID_VPD); - ret = get_flash_params(adapter); + ret = t4_get_flash_params(adapter); if (ret < 0) return ret; - ret = get_vpd_params(adapter, &adapter->params.vpd); + ret = get_vpd_params(adapter, &adapter->params.vpd, buf); if (ret < 0) return ret; /* Cards with real ASICs have the chipid in the PCIe device id */ t4_os_pci_read_cfg2(adapter, PCI_DEVICE_ID, &device_id); - if (device_id >> 12 == adapter->params.chipid) + if (device_id >> 12 == chip_id(adapter)) adapter->params.cim_la_size = CIMLA_SIZE; else { /* FPGA */ @@ -5628,40 +7517,258 @@ int __devinit t4_prep_adapter(struct adapter *adapter) } /** - * t4_init_tp_params - initialize adap->params.tp + * t4_shutdown_adapter - shut down adapter, host & wire + * @adapter: the adapter + * + * Perform an emergency shutdown of the adapter and stop it from + * continuing any further communication on the ports or DMA to the + * host. This is typically used when the adapter and/or firmware + * have crashed and we want to prevent any further accidental + * communication with the rest of the world. This will also force + * the port Link Status to go down -- if register writes work -- + * which should help our peers figure out that we're down. + */ +int t4_shutdown_adapter(struct adapter *adapter) +{ + int port; + + t4_intr_disable(adapter); + t4_write_reg(adapter, A_DBG_GPIO_EN, 0); + for_each_port(adapter, port) { + u32 a_port_cfg = PORT_REG(port, + is_t4(adapter) + ? A_XGMAC_PORT_CFG + : A_MAC_PORT_CFG); + + t4_write_reg(adapter, a_port_cfg, + t4_read_reg(adapter, a_port_cfg) + & ~V_SIGNAL_DET(1)); + } + t4_set_reg_field(adapter, A_SGE_CONTROL, F_GLOBALENABLE, 0); + + return 0; +} + +/** + * t4_init_devlog_params - initialize adapter->params.devlog * @adap: the adapter + * @fw_attach: whether we can talk to the firmware + * + * Initialize various fields of the adapter's Firmware Device Log + * Parameters structure. + */ +int t4_init_devlog_params(struct adapter *adap, int fw_attach) +{ + struct devlog_params *dparams = &adap->params.devlog; + u32 pf_dparams; + unsigned int devlog_meminfo; + struct fw_devlog_cmd devlog_cmd; + int ret; + + /* If we're dealing with newer firmware, the Device Log Paramerters + * are stored in a designated register which allows us to access the + * Device Log even if we can't talk to the firmware. + */ + pf_dparams = + t4_read_reg(adap, PCIE_FW_REG(A_PCIE_FW_PF, PCIE_FW_PF_DEVLOG)); + if (pf_dparams) { + unsigned int nentries, nentries128; + + dparams->memtype = G_PCIE_FW_PF_DEVLOG_MEMTYPE(pf_dparams); + dparams->start = G_PCIE_FW_PF_DEVLOG_ADDR16(pf_dparams) << 4; + + nentries128 = G_PCIE_FW_PF_DEVLOG_NENTRIES128(pf_dparams); + nentries = (nentries128 + 1) * 128; + dparams->size = nentries * sizeof(struct fw_devlog_e); + + return 0; + } + + /* + * For any failing returns ... + */ + memset(dparams, 0, sizeof *dparams); + + /* + * If we can't talk to the firmware, there's really nothing we can do + * at this point. + */ + if (!fw_attach) + return -ENXIO; + + /* Otherwise, ask the firmware for it's Device Log Parameters. + */ + memset(&devlog_cmd, 0, sizeof devlog_cmd); + devlog_cmd.op_to_write = cpu_to_be32(V_FW_CMD_OP(FW_DEVLOG_CMD) | + F_FW_CMD_REQUEST | F_FW_CMD_READ); + devlog_cmd.retval_len16 = cpu_to_be32(FW_LEN16(devlog_cmd)); + ret = t4_wr_mbox(adap, adap->mbox, &devlog_cmd, sizeof(devlog_cmd), + &devlog_cmd); + if (ret) + return ret; + + devlog_meminfo = + be32_to_cpu(devlog_cmd.memtype_devlog_memaddr16_devlog); + dparams->memtype = G_FW_DEVLOG_CMD_MEMTYPE_DEVLOG(devlog_meminfo); + dparams->start = G_FW_DEVLOG_CMD_MEMADDR16_DEVLOG(devlog_meminfo) << 4; + dparams->size = be32_to_cpu(devlog_cmd.memsize_devlog); + + return 0; +} + +/** + * t4_init_sge_params - initialize adap->params.sge + * @adapter: the adapter * - * Initialize various fields of the adapter's TP Parameters structure. + * Initialize various fields of the adapter's SGE Parameters structure. */ -int __devinit t4_init_tp_params(struct adapter *adap) +int t4_init_sge_params(struct adapter *adapter) +{ + u32 r; + struct sge_params *sp = &adapter->params.sge; + + r = t4_read_reg(adapter, A_SGE_INGRESS_RX_THRESHOLD); + sp->counter_val[0] = G_THRESHOLD_0(r); + sp->counter_val[1] = G_THRESHOLD_1(r); + sp->counter_val[2] = G_THRESHOLD_2(r); + sp->counter_val[3] = G_THRESHOLD_3(r); + + r = t4_read_reg(adapter, A_SGE_TIMER_VALUE_0_AND_1); + sp->timer_val[0] = core_ticks_to_us(adapter, G_TIMERVALUE0(r)); + sp->timer_val[1] = core_ticks_to_us(adapter, G_TIMERVALUE1(r)); + r = t4_read_reg(adapter, A_SGE_TIMER_VALUE_2_AND_3); + sp->timer_val[2] = core_ticks_to_us(adapter, G_TIMERVALUE2(r)); + sp->timer_val[3] = core_ticks_to_us(adapter, G_TIMERVALUE3(r)); + r = t4_read_reg(adapter, A_SGE_TIMER_VALUE_4_AND_5); + sp->timer_val[4] = core_ticks_to_us(adapter, G_TIMERVALUE4(r)); + sp->timer_val[5] = core_ticks_to_us(adapter, G_TIMERVALUE5(r)); + + r = t4_read_reg(adapter, A_SGE_CONM_CTRL); + sp->fl_starve_threshold = G_EGRTHRESHOLD(r) * 2 + 1; + if (is_t4(adapter)) + sp->fl_starve_threshold2 = sp->fl_starve_threshold; + else + sp->fl_starve_threshold2 = G_EGRTHRESHOLDPACKING(r) * 2 + 1; + + /* egress queues: log2 of # of doorbells per BAR2 page */ + r = t4_read_reg(adapter, A_SGE_EGRESS_QUEUES_PER_PAGE_PF); + r >>= S_QUEUESPERPAGEPF0 + + (S_QUEUESPERPAGEPF1 - S_QUEUESPERPAGEPF0) * adapter->pf; + sp->eq_s_qpp = r & M_QUEUESPERPAGEPF0; + + /* ingress queues: log2 of # of doorbells per BAR2 page */ + r = t4_read_reg(adapter, A_SGE_INGRESS_QUEUES_PER_PAGE_PF); + r >>= S_QUEUESPERPAGEPF0 + + (S_QUEUESPERPAGEPF1 - S_QUEUESPERPAGEPF0) * adapter->pf; + sp->iq_s_qpp = r & M_QUEUESPERPAGEPF0; + + r = t4_read_reg(adapter, A_SGE_HOST_PAGE_SIZE); + r >>= S_HOSTPAGESIZEPF0 + + (S_HOSTPAGESIZEPF1 - S_HOSTPAGESIZEPF0) * adapter->pf; + sp->page_shift = (r & M_HOSTPAGESIZEPF0) + 10; + + r = t4_read_reg(adapter, A_SGE_CONTROL); + sp->spg_len = r & F_EGRSTATUSPAGESIZE ? 128 : 64; + sp->fl_pktshift = G_PKTSHIFT(r); + sp->pad_boundary = 1 << (G_INGPADBOUNDARY(r) + 5); + if (is_t4(adapter)) + sp->pack_boundary = sp->pad_boundary; + else { + r = t4_read_reg(adapter, A_SGE_CONTROL2); + if (G_INGPACKBOUNDARY(r) == 0) + sp->pack_boundary = 16; + else + sp->pack_boundary = 1 << (G_INGPACKBOUNDARY(r) + 5); + } + + return 0; +} + +/* + * Read and cache the adapter's compressed filter mode and ingress config. + */ +static void read_filter_mode_and_ingress_config(struct adapter *adap) +{ + struct tp_params *tpp = &adap->params.tp; + + if (t4_use_ldst(adap)) { + t4_fw_tp_pio_rw(adap, &tpp->vlan_pri_map, 1, + A_TP_VLAN_PRI_MAP, 1); + t4_fw_tp_pio_rw(adap, &tpp->ingress_config, 1, + A_TP_INGRESS_CONFIG, 1); + } else { + t4_read_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA, + &tpp->vlan_pri_map, 1, A_TP_VLAN_PRI_MAP); + t4_read_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA, + &tpp->ingress_config, 1, A_TP_INGRESS_CONFIG); + } + + /* + * Now that we have TP_VLAN_PRI_MAP cached, we can calculate the field + * shift positions of several elements of the Compressed Filter Tuple + * for this adapter which we need frequently ... + */ + tpp->fcoe_shift = t4_filter_field_shift(adap, F_FCOE); + tpp->port_shift = t4_filter_field_shift(adap, F_PORT); + tpp->vnic_shift = t4_filter_field_shift(adap, F_VNIC_ID); + tpp->vlan_shift = t4_filter_field_shift(adap, F_VLAN); + tpp->tos_shift = t4_filter_field_shift(adap, F_TOS); + tpp->protocol_shift = t4_filter_field_shift(adap, F_PROTOCOL); + tpp->ethertype_shift = t4_filter_field_shift(adap, F_ETHERTYPE); + tpp->macmatch_shift = t4_filter_field_shift(adap, F_MACMATCH); + tpp->matchtype_shift = t4_filter_field_shift(adap, F_MPSHITTYPE); + tpp->frag_shift = t4_filter_field_shift(adap, F_FRAGMENTATION); + + /* + * If TP_INGRESS_CONFIG.VNID == 0, then TP_VLAN_PRI_MAP.VNIC_ID + * represents the presense of an Outer VLAN instead of a VNIC ID. + */ + if ((tpp->ingress_config & F_VNIC) == 0) + tpp->vnic_shift = -1; +} + +/** + * t4_init_tp_params - initialize adap->params.tp + * @adap: the adapter + * + * Initialize various fields of the adapter's TP Parameters structure. + */ +int t4_init_tp_params(struct adapter *adap) { int chan; u32 v; + struct tp_params *tpp = &adap->params.tp; v = t4_read_reg(adap, A_TP_TIMER_RESOLUTION); - adap->params.tp.tre = G_TIMERRESOLUTION(v); - adap->params.tp.dack_re = G_DELAYEDACKRESOLUTION(v); + tpp->tre = G_TIMERRESOLUTION(v); + tpp->dack_re = G_DELAYEDACKRESOLUTION(v); /* MODQ_REQ_MAP defaults to setting queues 0-3 to chan 0-3 */ - for (chan = 0; chan < NCHAN; chan++) - adap->params.tp.tx_modq[chan] = chan; + for (chan = 0; chan < MAX_NCHAN; chan++) + tpp->tx_modq[chan] = chan; - t4_read_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA, - &adap->params.tp.ingress_config, 1, - A_TP_INGRESS_CONFIG); - refresh_vlan_pri_map(adap); + read_filter_mode_and_ingress_config(adap); + + /* + * For T6, cache the adapter's compressed error vector + * and passing outer header info for encapsulated packets. + */ + if (chip_id(adap) > CHELSIO_T5) { + v = t4_read_reg(adap, A_TP_OUT_CONFIG); + tpp->rx_pkt_encap = (v & F_CRXPKTENC) ? 1 : 0; + } return 0; } /** - * t4_filter_field_shift - calculate filter field shift - * @adap: the adapter - * @filter_sel: the desired field (from TP_VLAN_PRI_MAP bits) + * t4_filter_field_shift - calculate filter field shift + * @adap: the adapter + * @filter_sel: the desired field (from TP_VLAN_PRI_MAP bits) * - * Return the shift position of a filter field within the Compressed - * Filter Tuple. The filter field is specified via its selection bit - * within TP_VLAN_PRI_MAL (filter mode). E.g. F_VLAN. + * Return the shift position of a filter field within the Compressed + * Filter Tuple. The filter field is specified via its selection bit + * within TP_VLAN_PRI_MAL (filter mode). E.g. F_VLAN. */ int t4_filter_field_shift(const struct adapter *adap, int filter_sel) { @@ -5673,29 +7780,49 @@ int t4_filter_field_shift(const struct adapter *adap, int filter_sel) return -1; for (sel = 1, field_shift = 0; sel < filter_sel; sel <<= 1) { - switch (filter_mode & sel) { - case F_FCOE: field_shift += W_FT_FCOE; break; - case F_PORT: field_shift += W_FT_PORT; break; - case F_VNIC_ID: field_shift += W_FT_VNIC_ID; break; - case F_VLAN: field_shift += W_FT_VLAN; break; - case F_TOS: field_shift += W_FT_TOS; break; - case F_PROTOCOL: field_shift += W_FT_PROTOCOL; break; - case F_ETHERTYPE: field_shift += W_FT_ETHERTYPE; break; - case F_MACMATCH: field_shift += W_FT_MACMATCH; break; - case F_MPSHITTYPE: field_shift += W_FT_MPSHITTYPE; break; - case F_FRAGMENTATION: field_shift += W_FT_FRAGMENTATION; break; - } + switch (filter_mode & sel) { + case F_FCOE: + field_shift += W_FT_FCOE; + break; + case F_PORT: + field_shift += W_FT_PORT; + break; + case F_VNIC_ID: + field_shift += W_FT_VNIC_ID; + break; + case F_VLAN: + field_shift += W_FT_VLAN; + break; + case F_TOS: + field_shift += W_FT_TOS; + break; + case F_PROTOCOL: + field_shift += W_FT_PROTOCOL; + break; + case F_ETHERTYPE: + field_shift += W_FT_ETHERTYPE; + break; + case F_MACMATCH: + field_shift += W_FT_MACMATCH; + break; + case F_MPSHITTYPE: + field_shift += W_FT_MPSHITTYPE; + break; + case F_FRAGMENTATION: + field_shift += W_FT_FRAGMENTATION; + break; + } } return field_shift; } -int __devinit t4_port_init(struct port_info *p, int mbox, int pf, int vf) +int t4_port_init(struct adapter *adap, int mbox, int pf, int vf, int port_id) { u8 addr[6]; int ret, i, j; struct fw_port_cmd c; u16 rss_size; - adapter_t *adap = p->adapter; + struct port_info *p = adap2pinfo(adap, port_id); u32 param, val; memset(&c, 0, sizeof(c)); @@ -5722,18 +7849,18 @@ int __devinit t4_port_init(struct port_info *p, int mbox, int pf, int vf) p->vi[0].viid = ret; p->tx_chan = j; - p->rx_chan_map = get_mps_bg_map(adap, j); + p->rx_chan_map = t4_get_mps_bg_map(adap, j); p->lport = j; p->vi[0].rss_size = rss_size; t4_os_set_hw_addr(adap, p->port_id, addr); - ret = ntohl(c.u.info.lstatus_to_modtype); + ret = be32_to_cpu(c.u.info.lstatus_to_modtype); p->mdio_addr = (ret & F_FW_PORT_CMD_MDIOCAP) ? G_FW_PORT_CMD_MDIOADDR(ret) : -1; p->port_type = G_FW_PORT_CMD_PTYPE(ret); p->mod_type = G_FW_PORT_CMD_MODTYPE(ret); - init_link_config(&p->link_cfg, ntohs(c.u.info.pcap)); + init_link_config(&p->link_cfg, be16_to_cpu(c.u.info.pcap)); param = V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_RSSINFO) | @@ -5749,6 +7876,1161 @@ int __devinit t4_port_init(struct port_info *p, int mbox, int pf, int vf) return 0; } +/** + * t4_read_cimq_cfg - read CIM queue configuration + * @adap: the adapter + * @base: holds the queue base addresses in bytes + * @size: holds the queue sizes in bytes + * @thres: holds the queue full thresholds in bytes + * + * Returns the current configuration of the CIM queues, starting with + * the IBQs, then the OBQs. + */ +void t4_read_cimq_cfg(struct adapter *adap, u16 *base, u16 *size, u16 *thres) +{ + unsigned int i, v; + int cim_num_obq = adap->chip_params->cim_num_obq; + + for (i = 0; i < CIM_NUM_IBQ; i++) { + t4_write_reg(adap, A_CIM_QUEUE_CONFIG_REF, F_IBQSELECT | + V_QUENUMSELECT(i)); + v = t4_read_reg(adap, A_CIM_QUEUE_CONFIG_CTRL); + /* value is in 256-byte units */ + *base++ = G_CIMQBASE(v) * 256; + *size++ = G_CIMQSIZE(v) * 256; + *thres++ = G_QUEFULLTHRSH(v) * 8; /* 8-byte unit */ + } + for (i = 0; i < cim_num_obq; i++) { + t4_write_reg(adap, A_CIM_QUEUE_CONFIG_REF, F_OBQSELECT | + V_QUENUMSELECT(i)); + v = t4_read_reg(adap, A_CIM_QUEUE_CONFIG_CTRL); + /* value is in 256-byte units */ + *base++ = G_CIMQBASE(v) * 256; + *size++ = G_CIMQSIZE(v) * 256; + } +} + +/** + * t4_read_cim_ibq - read the contents of a CIM inbound queue + * @adap: the adapter + * @qid: the queue index + * @data: where to store the queue contents + * @n: capacity of @data in 32-bit words + * + * Reads the contents of the selected CIM queue starting at address 0 up + * to the capacity of @data. @n must be a multiple of 4. Returns < 0 on + * error and the number of 32-bit words actually read on success. + */ +int t4_read_cim_ibq(struct adapter *adap, unsigned int qid, u32 *data, size_t n) +{ + int i, err, attempts; + unsigned int addr; + const unsigned int nwords = CIM_IBQ_SIZE * 4; + + if (qid > 5 || (n & 3)) + return -EINVAL; + + addr = qid * nwords; + if (n > nwords) + n = nwords; + + /* It might take 3-10ms before the IBQ debug read access is allowed. + * Wait for 1 Sec with a delay of 1 usec. + */ + attempts = 1000000; + + for (i = 0; i < n; i++, addr++) { + t4_write_reg(adap, A_CIM_IBQ_DBG_CFG, V_IBQDBGADDR(addr) | + F_IBQDBGEN); + err = t4_wait_op_done(adap, A_CIM_IBQ_DBG_CFG, F_IBQDBGBUSY, 0, + attempts, 1); + if (err) + return err; + *data++ = t4_read_reg(adap, A_CIM_IBQ_DBG_DATA); + } + t4_write_reg(adap, A_CIM_IBQ_DBG_CFG, 0); + return i; +} + +/** + * t4_read_cim_obq - read the contents of a CIM outbound queue + * @adap: the adapter + * @qid: the queue index + * @data: where to store the queue contents + * @n: capacity of @data in 32-bit words + * + * Reads the contents of the selected CIM queue starting at address 0 up + * to the capacity of @data. @n must be a multiple of 4. Returns < 0 on + * error and the number of 32-bit words actually read on success. + */ +int t4_read_cim_obq(struct adapter *adap, unsigned int qid, u32 *data, size_t n) +{ + int i, err; + unsigned int addr, v, nwords; + int cim_num_obq = adap->chip_params->cim_num_obq; + + if ((qid > (cim_num_obq - 1)) || (n & 3)) + return -EINVAL; + + t4_write_reg(adap, A_CIM_QUEUE_CONFIG_REF, F_OBQSELECT | + V_QUENUMSELECT(qid)); + v = t4_read_reg(adap, A_CIM_QUEUE_CONFIG_CTRL); + + addr = G_CIMQBASE(v) * 64; /* muliple of 256 -> muliple of 4 */ + nwords = G_CIMQSIZE(v) * 64; /* same */ + if (n > nwords) + n = nwords; + + for (i = 0; i < n; i++, addr++) { + t4_write_reg(adap, A_CIM_OBQ_DBG_CFG, V_OBQDBGADDR(addr) | + F_OBQDBGEN); + err = t4_wait_op_done(adap, A_CIM_OBQ_DBG_CFG, F_OBQDBGBUSY, 0, + 2, 1); + if (err) + return err; + *data++ = t4_read_reg(adap, A_CIM_OBQ_DBG_DATA); + } + t4_write_reg(adap, A_CIM_OBQ_DBG_CFG, 0); + return i; +} + +enum { + CIM_QCTL_BASE = 0, + CIM_CTL_BASE = 0x2000, + CIM_PBT_ADDR_BASE = 0x2800, + CIM_PBT_LRF_BASE = 0x3000, + CIM_PBT_DATA_BASE = 0x3800 +}; + +/** + * t4_cim_read - read a block from CIM internal address space + * @adap: the adapter + * @addr: the start address within the CIM address space + * @n: number of words to read + * @valp: where to store the result + * + * Reads a block of 4-byte words from the CIM intenal address space. + */ +int t4_cim_read(struct adapter *adap, unsigned int addr, unsigned int n, + unsigned int *valp) +{ + int ret = 0; + + if (t4_read_reg(adap, A_CIM_HOST_ACC_CTRL) & F_HOSTBUSY) + return -EBUSY; + + for ( ; !ret && n--; addr += 4) { + t4_write_reg(adap, A_CIM_HOST_ACC_CTRL, addr); + ret = t4_wait_op_done(adap, A_CIM_HOST_ACC_CTRL, F_HOSTBUSY, + 0, 5, 2); + if (!ret) + *valp++ = t4_read_reg(adap, A_CIM_HOST_ACC_DATA); + } + return ret; +} + +/** + * t4_cim_write - write a block into CIM internal address space + * @adap: the adapter + * @addr: the start address within the CIM address space + * @n: number of words to write + * @valp: set of values to write + * + * Writes a block of 4-byte words into the CIM intenal address space. + */ +int t4_cim_write(struct adapter *adap, unsigned int addr, unsigned int n, + const unsigned int *valp) +{ + int ret = 0; + + if (t4_read_reg(adap, A_CIM_HOST_ACC_CTRL) & F_HOSTBUSY) + return -EBUSY; + + for ( ; !ret && n--; addr += 4) { + t4_write_reg(adap, A_CIM_HOST_ACC_DATA, *valp++); + t4_write_reg(adap, A_CIM_HOST_ACC_CTRL, addr | F_HOSTWRITE); + ret = t4_wait_op_done(adap, A_CIM_HOST_ACC_CTRL, F_HOSTBUSY, + 0, 5, 2); + } + return ret; +} + +static int t4_cim_write1(struct adapter *adap, unsigned int addr, + unsigned int val) +{ + return t4_cim_write(adap, addr, 1, &val); +} + +/** + * t4_cim_ctl_read - read a block from CIM control region + * @adap: the adapter + * @addr: the start address within the CIM control region + * @n: number of words to read + * @valp: where to store the result + * + * Reads a block of 4-byte words from the CIM control region. + */ +int t4_cim_ctl_read(struct adapter *adap, unsigned int addr, unsigned int n, + unsigned int *valp) +{ + return t4_cim_read(adap, addr + CIM_CTL_BASE, n, valp); +} + +/** + * t4_cim_read_la - read CIM LA capture buffer + * @adap: the adapter + * @la_buf: where to store the LA data + * @wrptr: the HW write pointer within the capture buffer + * + * Reads the contents of the CIM LA buffer with the most recent entry at + * the end of the returned data and with the entry at @wrptr first. + * We try to leave the LA in the running state we find it in. + */ +int t4_cim_read_la(struct adapter *adap, u32 *la_buf, unsigned int *wrptr) +{ + int i, ret; + unsigned int cfg, val, idx; + + ret = t4_cim_read(adap, A_UP_UP_DBG_LA_CFG, 1, &cfg); + if (ret) + return ret; + + if (cfg & F_UPDBGLAEN) { /* LA is running, freeze it */ + ret = t4_cim_write1(adap, A_UP_UP_DBG_LA_CFG, 0); + if (ret) + return ret; + } + + ret = t4_cim_read(adap, A_UP_UP_DBG_LA_CFG, 1, &val); + if (ret) + goto restart; + + idx = G_UPDBGLAWRPTR(val); + if (wrptr) + *wrptr = idx; + + for (i = 0; i < adap->params.cim_la_size; i++) { + ret = t4_cim_write1(adap, A_UP_UP_DBG_LA_CFG, + V_UPDBGLARDPTR(idx) | F_UPDBGLARDEN); + if (ret) + break; + ret = t4_cim_read(adap, A_UP_UP_DBG_LA_CFG, 1, &val); + if (ret) + break; + if (val & F_UPDBGLARDEN) { + ret = -ETIMEDOUT; + break; + } + ret = t4_cim_read(adap, A_UP_UP_DBG_LA_DATA, 1, &la_buf[i]); + if (ret) + break; + + /* address can't exceed 0xfff (UpDbgLaRdPtr is of 12-bits) */ + idx = (idx + 1) & M_UPDBGLARDPTR; + /* + * Bits 0-3 of UpDbgLaRdPtr can be between 0000 to 1001 to + * identify the 32-bit portion of the full 312-bit data + */ + if (is_t6(adap)) + while ((idx & 0xf) > 9) + idx = (idx + 1) % M_UPDBGLARDPTR; + } +restart: + if (cfg & F_UPDBGLAEN) { + int r = t4_cim_write1(adap, A_UP_UP_DBG_LA_CFG, + cfg & ~F_UPDBGLARDEN); + if (!ret) + ret = r; + } + return ret; +} + +/** + * t4_tp_read_la - read TP LA capture buffer + * @adap: the adapter + * @la_buf: where to store the LA data + * @wrptr: the HW write pointer within the capture buffer + * + * Reads the contents of the TP LA buffer with the most recent entry at + * the end of the returned data and with the entry at @wrptr first. + * We leave the LA in the running state we find it in. + */ +void t4_tp_read_la(struct adapter *adap, u64 *la_buf, unsigned int *wrptr) +{ + bool last_incomplete; + unsigned int i, cfg, val, idx; + + cfg = t4_read_reg(adap, A_TP_DBG_LA_CONFIG) & 0xffff; + if (cfg & F_DBGLAENABLE) /* freeze LA */ + t4_write_reg(adap, A_TP_DBG_LA_CONFIG, + adap->params.tp.la_mask | (cfg ^ F_DBGLAENABLE)); + + val = t4_read_reg(adap, A_TP_DBG_LA_CONFIG); + idx = G_DBGLAWPTR(val); + last_incomplete = G_DBGLAMODE(val) >= 2 && (val & F_DBGLAWHLF) == 0; + if (last_incomplete) + idx = (idx + 1) & M_DBGLARPTR; + if (wrptr) + *wrptr = idx; + + val &= 0xffff; + val &= ~V_DBGLARPTR(M_DBGLARPTR); + val |= adap->params.tp.la_mask; + + for (i = 0; i < TPLA_SIZE; i++) { + t4_write_reg(adap, A_TP_DBG_LA_CONFIG, V_DBGLARPTR(idx) | val); + la_buf[i] = t4_read_reg64(adap, A_TP_DBG_LA_DATAL); + idx = (idx + 1) & M_DBGLARPTR; + } + + /* Wipe out last entry if it isn't valid */ + if (last_incomplete) + la_buf[TPLA_SIZE - 1] = ~0ULL; + + if (cfg & F_DBGLAENABLE) /* restore running state */ + t4_write_reg(adap, A_TP_DBG_LA_CONFIG, + cfg | adap->params.tp.la_mask); +} + +/* + * SGE Hung Ingress DMA Warning Threshold time and Warning Repeat Rate (in + * seconds). If we find one of the SGE Ingress DMA State Machines in the same + * state for more than the Warning Threshold then we'll issue a warning about + * a potential hang. We'll repeat the warning as the SGE Ingress DMA Channel + * appears to be hung every Warning Repeat second till the situation clears. + * If the situation clears, we'll note that as well. + */ +#define SGE_IDMA_WARN_THRESH 1 +#define SGE_IDMA_WARN_REPEAT 300 + +/** + * t4_idma_monitor_init - initialize SGE Ingress DMA Monitor + * @adapter: the adapter + * @idma: the adapter IDMA Monitor state + * + * Initialize the state of an SGE Ingress DMA Monitor. + */ +void t4_idma_monitor_init(struct adapter *adapter, + struct sge_idma_monitor_state *idma) +{ + /* Initialize the state variables for detecting an SGE Ingress DMA + * hang. The SGE has internal counters which count up on each clock + * tick whenever the SGE finds its Ingress DMA State Engines in the + * same state they were on the previous clock tick. The clock used is + * the Core Clock so we have a limit on the maximum "time" they can + * record; typically a very small number of seconds. For instance, + * with a 600MHz Core Clock, we can only count up to a bit more than + * 7s. So we'll synthesize a larger counter in order to not run the + * risk of having the "timers" overflow and give us the flexibility to + * maintain a Hung SGE State Machine of our own which operates across + * a longer time frame. + */ + idma->idma_1s_thresh = core_ticks_per_usec(adapter) * 1000000; /* 1s */ + idma->idma_stalled[0] = idma->idma_stalled[1] = 0; +} + +/** + * t4_idma_monitor - monitor SGE Ingress DMA state + * @adapter: the adapter + * @idma: the adapter IDMA Monitor state + * @hz: number of ticks/second + * @ticks: number of ticks since the last IDMA Monitor call + */ +void t4_idma_monitor(struct adapter *adapter, + struct sge_idma_monitor_state *idma, + int hz, int ticks) +{ + int i, idma_same_state_cnt[2]; + + /* Read the SGE Debug Ingress DMA Same State Count registers. These + * are counters inside the SGE which count up on each clock when the + * SGE finds its Ingress DMA State Engines in the same states they + * were in the previous clock. The counters will peg out at + * 0xffffffff without wrapping around so once they pass the 1s + * threshold they'll stay above that till the IDMA state changes. + */ + t4_write_reg(adapter, A_SGE_DEBUG_INDEX, 13); + idma_same_state_cnt[0] = t4_read_reg(adapter, A_SGE_DEBUG_DATA_HIGH); + idma_same_state_cnt[1] = t4_read_reg(adapter, A_SGE_DEBUG_DATA_LOW); + + for (i = 0; i < 2; i++) { + u32 debug0, debug11; + + /* If the Ingress DMA Same State Counter ("timer") is less + * than 1s, then we can reset our synthesized Stall Timer and + * continue. If we have previously emitted warnings about a + * potential stalled Ingress Queue, issue a note indicating + * that the Ingress Queue has resumed forward progress. + */ + if (idma_same_state_cnt[i] < idma->idma_1s_thresh) { + if (idma->idma_stalled[i] >= SGE_IDMA_WARN_THRESH*hz) + CH_WARN(adapter, "SGE idma%d, queue %u, " + "resumed after %d seconds\n", + i, idma->idma_qid[i], + idma->idma_stalled[i]/hz); + idma->idma_stalled[i] = 0; + continue; + } + + /* Synthesize an SGE Ingress DMA Same State Timer in the Hz + * domain. The first time we get here it'll be because we + * passed the 1s Threshold; each additional time it'll be + * because the RX Timer Callback is being fired on its regular + * schedule. + * + * If the stall is below our Potential Hung Ingress Queue + * Warning Threshold, continue. + */ + if (idma->idma_stalled[i] == 0) { + idma->idma_stalled[i] = hz; + idma->idma_warn[i] = 0; + } else { + idma->idma_stalled[i] += ticks; + idma->idma_warn[i] -= ticks; + } + + if (idma->idma_stalled[i] < SGE_IDMA_WARN_THRESH*hz) + continue; + + /* We'll issue a warning every SGE_IDMA_WARN_REPEAT seconds. + */ + if (idma->idma_warn[i] > 0) + continue; + idma->idma_warn[i] = SGE_IDMA_WARN_REPEAT*hz; + + /* Read and save the SGE IDMA State and Queue ID information. + * We do this every time in case it changes across time ... + * can't be too careful ... + */ + t4_write_reg(adapter, A_SGE_DEBUG_INDEX, 0); + debug0 = t4_read_reg(adapter, A_SGE_DEBUG_DATA_LOW); + idma->idma_state[i] = (debug0 >> (i * 9)) & 0x3f; + + t4_write_reg(adapter, A_SGE_DEBUG_INDEX, 11); + debug11 = t4_read_reg(adapter, A_SGE_DEBUG_DATA_LOW); + idma->idma_qid[i] = (debug11 >> (i * 16)) & 0xffff; + + CH_WARN(adapter, "SGE idma%u, queue %u, potentially stuck in " + " state %u for %d seconds (debug0=%#x, debug11=%#x)\n", + i, idma->idma_qid[i], idma->idma_state[i], + idma->idma_stalled[i]/hz, + debug0, debug11); + t4_sge_decode_idma_state(adapter, idma->idma_state[i]); + } +} + +/** + * t4_read_pace_tbl - read the pace table + * @adap: the adapter + * @pace_vals: holds the returned values + * + * Returns the values of TP's pace table in microseconds. + */ +void t4_read_pace_tbl(struct adapter *adap, unsigned int pace_vals[NTX_SCHED]) +{ + unsigned int i, v; + + for (i = 0; i < NTX_SCHED; i++) { + t4_write_reg(adap, A_TP_PACE_TABLE, 0xffff0000 + i); + v = t4_read_reg(adap, A_TP_PACE_TABLE); + pace_vals[i] = dack_ticks_to_usec(adap, v); + } +} + +/** + * t4_get_tx_sched - get the configuration of a Tx HW traffic scheduler + * @adap: the adapter + * @sched: the scheduler index + * @kbps: the byte rate in Kbps + * @ipg: the interpacket delay in tenths of nanoseconds + * + * Return the current configuration of a HW Tx scheduler. + */ +void t4_get_tx_sched(struct adapter *adap, unsigned int sched, unsigned int *kbps, + unsigned int *ipg) +{ + unsigned int v, addr, bpt, cpt; + + if (kbps) { + addr = A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2; + t4_write_reg(adap, A_TP_TM_PIO_ADDR, addr); + v = t4_read_reg(adap, A_TP_TM_PIO_DATA); + if (sched & 1) + v >>= 16; + bpt = (v >> 8) & 0xff; + cpt = v & 0xff; + if (!cpt) + *kbps = 0; /* scheduler disabled */ + else { + v = (adap->params.vpd.cclk * 1000) / cpt; /* ticks/s */ + *kbps = (v * bpt) / 125; + } + } + if (ipg) { + addr = A_TP_TX_MOD_Q1_Q0_TIMER_SEPARATOR - sched / 2; + t4_write_reg(adap, A_TP_TM_PIO_ADDR, addr); + v = t4_read_reg(adap, A_TP_TM_PIO_DATA); + if (sched & 1) + v >>= 16; + v &= 0xffff; + *ipg = (10000 * v) / core_ticks_per_usec(adap); + } +} + +/** + * t4_load_cfg - download config file + * @adap: the adapter + * @cfg_data: the cfg text file to write + * @size: text file size + * + * Write the supplied config text file to the card's serial flash. + */ +int t4_load_cfg(struct adapter *adap, const u8 *cfg_data, unsigned int size) +{ + int ret, i, n, cfg_addr; + unsigned int addr; + unsigned int flash_cfg_start_sec; + unsigned int sf_sec_size = adap->params.sf_size / adap->params.sf_nsec; + + cfg_addr = t4_flash_cfg_addr(adap); + if (cfg_addr < 0) + return cfg_addr; + + addr = cfg_addr; + flash_cfg_start_sec = addr / SF_SEC_SIZE; + + if (size > FLASH_CFG_MAX_SIZE) { + CH_ERR(adap, "cfg file too large, max is %u bytes\n", + FLASH_CFG_MAX_SIZE); + return -EFBIG; + } + + i = DIV_ROUND_UP(FLASH_CFG_MAX_SIZE, /* # of sectors spanned */ + sf_sec_size); + ret = t4_flash_erase_sectors(adap, flash_cfg_start_sec, + flash_cfg_start_sec + i - 1); + /* + * If size == 0 then we're simply erasing the FLASH sectors associated + * with the on-adapter Firmware Configuration File. + */ + if (ret || size == 0) + goto out; + + /* this will write to the flash up to SF_PAGE_SIZE at a time */ + for (i = 0; i< size; i+= SF_PAGE_SIZE) { + if ( (size - i) < SF_PAGE_SIZE) + n = size - i; + else + n = SF_PAGE_SIZE; + ret = t4_write_flash(adap, addr, n, cfg_data, 1); + if (ret) + goto out; + + addr += SF_PAGE_SIZE; + cfg_data += SF_PAGE_SIZE; + } + +out: + if (ret) + CH_ERR(adap, "config file %s failed %d\n", + (size == 0 ? "clear" : "download"), ret); + return ret; +} + +/** + * t5_fw_init_extern_mem - initialize the external memory + * @adap: the adapter + * + * Initializes the external memory on T5. + */ +int t5_fw_init_extern_mem(struct adapter *adap) +{ + u32 params[1], val[1]; + int ret; + + if (!is_t5(adap)) + return 0; + + val[0] = 0xff; /* Initialize all MCs */ + params[0] = (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | + V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_MCINIT)); + ret = t4_set_params_timeout(adap, adap->mbox, adap->pf, 0, 1, params, val, + FW_CMD_MAX_TIMEOUT); + + return ret; +} + +/* BIOS boot headers */ +typedef struct pci_expansion_rom_header { + u8 signature[2]; /* ROM Signature. Should be 0xaa55 */ + u8 reserved[22]; /* Reserved per processor Architecture data */ + u8 pcir_offset[2]; /* Offset to PCI Data Structure */ +} pci_exp_rom_header_t; /* PCI_EXPANSION_ROM_HEADER */ + +/* Legacy PCI Expansion ROM Header */ +typedef struct legacy_pci_expansion_rom_header { + u8 signature[2]; /* ROM Signature. Should be 0xaa55 */ + u8 size512; /* Current Image Size in units of 512 bytes */ + u8 initentry_point[4]; + u8 cksum; /* Checksum computed on the entire Image */ + u8 reserved[16]; /* Reserved */ + u8 pcir_offset[2]; /* Offset to PCI Data Struture */ +} legacy_pci_exp_rom_header_t; /* LEGACY_PCI_EXPANSION_ROM_HEADER */ + +/* EFI PCI Expansion ROM Header */ +typedef struct efi_pci_expansion_rom_header { + u8 signature[2]; // ROM signature. The value 0xaa55 + u8 initialization_size[2]; /* Units 512. Includes this header */ + u8 efi_signature[4]; /* Signature from EFI image header. 0x0EF1 */ + u8 efi_subsystem[2]; /* Subsystem value for EFI image header */ + u8 efi_machine_type[2]; /* Machine type from EFI image header */ + u8 compression_type[2]; /* Compression type. */ + /* + * Compression type definition + * 0x0: uncompressed + * 0x1: Compressed + * 0x2-0xFFFF: Reserved + */ + u8 reserved[8]; /* Reserved */ + u8 efi_image_header_offset[2]; /* Offset to EFI Image */ + u8 pcir_offset[2]; /* Offset to PCI Data Structure */ +} efi_pci_exp_rom_header_t; /* EFI PCI Expansion ROM Header */ + +/* PCI Data Structure Format */ +typedef struct pcir_data_structure { /* PCI Data Structure */ + u8 signature[4]; /* Signature. The string "PCIR" */ + u8 vendor_id[2]; /* Vendor Identification */ + u8 device_id[2]; /* Device Identification */ + u8 vital_product[2]; /* Pointer to Vital Product Data */ + u8 length[2]; /* PCIR Data Structure Length */ + u8 revision; /* PCIR Data Structure Revision */ + u8 class_code[3]; /* Class Code */ + u8 image_length[2]; /* Image Length. Multiple of 512B */ + u8 code_revision[2]; /* Revision Level of Code/Data */ + u8 code_type; /* Code Type. */ + /* + * PCI Expansion ROM Code Types + * 0x00: Intel IA-32, PC-AT compatible. Legacy + * 0x01: Open Firmware standard for PCI. FCODE + * 0x02: Hewlett-Packard PA RISC. HP reserved + * 0x03: EFI Image. EFI + * 0x04-0xFF: Reserved. + */ + u8 indicator; /* Indicator. Identifies the last image in the ROM */ + u8 reserved[2]; /* Reserved */ +} pcir_data_t; /* PCI__DATA_STRUCTURE */ + +/* BOOT constants */ +enum { + BOOT_FLASH_BOOT_ADDR = 0x0,/* start address of boot image in flash */ + BOOT_SIGNATURE = 0xaa55, /* signature of BIOS boot ROM */ + BOOT_SIZE_INC = 512, /* image size measured in 512B chunks */ + BOOT_MIN_SIZE = sizeof(pci_exp_rom_header_t), /* basic header */ + BOOT_MAX_SIZE = 1024*BOOT_SIZE_INC, /* 1 byte * length increment */ + VENDOR_ID = 0x1425, /* Vendor ID */ + PCIR_SIGNATURE = 0x52494350 /* PCIR signature */ +}; + +/* + * modify_device_id - Modifies the device ID of the Boot BIOS image + * @adatper: the device ID to write. + * @boot_data: the boot image to modify. + * + * Write the supplied device ID to the boot BIOS image. + */ +static void modify_device_id(int device_id, u8 *boot_data) +{ + legacy_pci_exp_rom_header_t *header; + pcir_data_t *pcir_header; + u32 cur_header = 0; + + /* + * Loop through all chained images and change the device ID's + */ + while (1) { + header = (legacy_pci_exp_rom_header_t *) &boot_data[cur_header]; + pcir_header = (pcir_data_t *) &boot_data[cur_header + + le16_to_cpu(*(u16*)header->pcir_offset)]; + + /* + * Only modify the Device ID if code type is Legacy or HP. + * 0x00: Okay to modify + * 0x01: FCODE. Do not be modify + * 0x03: Okay to modify + * 0x04-0xFF: Do not modify + */ + if (pcir_header->code_type == 0x00) { + u8 csum = 0; + int i; + + /* + * Modify Device ID to match current adatper + */ + *(u16*) pcir_header->device_id = device_id; + + /* + * Set checksum temporarily to 0. + * We will recalculate it later. + */ + header->cksum = 0x0; + + /* + * Calculate and update checksum + */ + for (i = 0; i < (header->size512 * 512); i++) + csum += (u8)boot_data[cur_header + i]; + + /* + * Invert summed value to create the checksum + * Writing new checksum value directly to the boot data + */ + boot_data[cur_header + 7] = -csum; + + } else if (pcir_header->code_type == 0x03) { + + /* + * Modify Device ID to match current adatper + */ + *(u16*) pcir_header->device_id = device_id; + + } + + + /* + * Check indicator element to identify if this is the last + * image in the ROM. + */ + if (pcir_header->indicator & 0x80) + break; + + /* + * Move header pointer up to the next image in the ROM. + */ + cur_header += header->size512 * 512; + } +} + +/* + * t4_load_boot - download boot flash + * @adapter: the adapter + * @boot_data: the boot image to write + * @boot_addr: offset in flash to write boot_data + * @size: image size + * + * Write the supplied boot image to the card's serial flash. + * The boot image has the following sections: a 28-byte header and the + * boot image. + */ +int t4_load_boot(struct adapter *adap, u8 *boot_data, + unsigned int boot_addr, unsigned int size) +{ + pci_exp_rom_header_t *header; + int pcir_offset ; + pcir_data_t *pcir_header; + int ret, addr; + uint16_t device_id; + unsigned int i; + unsigned int boot_sector = (boot_addr * 1024 ); + unsigned int sf_sec_size = adap->params.sf_size / adap->params.sf_nsec; + + /* + * Make sure the boot image does not encroach on the firmware region + */ + if ((boot_sector + size) >> 16 > FLASH_FW_START_SEC) { + CH_ERR(adap, "boot image encroaching on firmware region\n"); + return -EFBIG; + } + + /* + * The boot sector is comprised of the Expansion-ROM boot, iSCSI boot, + * and Boot configuration data sections. These 3 boot sections span + * sectors 0 to 7 in flash and live right before the FW image location. + */ + i = DIV_ROUND_UP(size ? size : FLASH_FW_START, + sf_sec_size); + ret = t4_flash_erase_sectors(adap, boot_sector >> 16, + (boot_sector >> 16) + i - 1); + + /* + * If size == 0 then we're simply erasing the FLASH sectors associated + * with the on-adapter option ROM file + */ + if (ret || (size == 0)) + goto out; + + /* Get boot header */ + header = (pci_exp_rom_header_t *)boot_data; + pcir_offset = le16_to_cpu(*(u16 *)header->pcir_offset); + /* PCIR Data Structure */ + pcir_header = (pcir_data_t *) &boot_data[pcir_offset]; + + /* + * Perform some primitive sanity testing to avoid accidentally + * writing garbage over the boot sectors. We ought to check for + * more but it's not worth it for now ... + */ + if (size < BOOT_MIN_SIZE || size > BOOT_MAX_SIZE) { + CH_ERR(adap, "boot image too small/large\n"); + return -EFBIG; + } + +#ifndef CHELSIO_T4_DIAGS + /* + * Check BOOT ROM header signature + */ + if (le16_to_cpu(*(u16*)header->signature) != BOOT_SIGNATURE ) { + CH_ERR(adap, "Boot image missing signature\n"); + return -EINVAL; + } + + /* + * Check PCI header signature + */ + if (le32_to_cpu(*(u32*)pcir_header->signature) != PCIR_SIGNATURE) { + CH_ERR(adap, "PCI header missing signature\n"); + return -EINVAL; + } + + /* + * Check Vendor ID matches Chelsio ID + */ + if (le16_to_cpu(*(u16*)pcir_header->vendor_id) != VENDOR_ID) { + CH_ERR(adap, "Vendor ID missing signature\n"); + return -EINVAL; + } +#endif + + /* + * Retrieve adapter's device ID + */ + t4_os_pci_read_cfg2(adap, PCI_DEVICE_ID, &device_id); + /* Want to deal with PF 0 so I strip off PF 4 indicator */ + device_id = device_id & 0xf0ff; + + /* + * Check PCIE Device ID + */ + if (le16_to_cpu(*(u16*)pcir_header->device_id) != device_id) { + /* + * Change the device ID in the Boot BIOS image to match + * the Device ID of the current adapter. + */ + modify_device_id(device_id, boot_data); + } + + /* + * Skip over the first SF_PAGE_SIZE worth of data and write it after + * we finish copying the rest of the boot image. This will ensure + * that the BIOS boot header will only be written if the boot image + * was written in full. + */ + addr = boot_sector; + for (size -= SF_PAGE_SIZE; size; size -= SF_PAGE_SIZE) { + addr += SF_PAGE_SIZE; + boot_data += SF_PAGE_SIZE; + ret = t4_write_flash(adap, addr, SF_PAGE_SIZE, boot_data, 0); + if (ret) + goto out; + } + + ret = t4_write_flash(adap, boot_sector, SF_PAGE_SIZE, + (const u8 *)header, 0); + +out: + if (ret) + CH_ERR(adap, "boot image download failed, error %d\n", ret); + return ret; +} + +/* + * t4_flash_bootcfg_addr - return the address of the flash optionrom configuration + * @adapter: the adapter + * + * Return the address within the flash where the OptionROM Configuration + * is stored, or an error if the device FLASH is too small to contain + * a OptionROM Configuration. + */ +static int t4_flash_bootcfg_addr(struct adapter *adapter) +{ + /* + * If the device FLASH isn't large enough to hold a Firmware + * Configuration File, return an error. + */ + if (adapter->params.sf_size < FLASH_BOOTCFG_START + FLASH_BOOTCFG_MAX_SIZE) + return -ENOSPC; + + return FLASH_BOOTCFG_START; +} + +int t4_load_bootcfg(struct adapter *adap,const u8 *cfg_data, unsigned int size) +{ + int ret, i, n, cfg_addr; + unsigned int addr; + unsigned int flash_cfg_start_sec; + unsigned int sf_sec_size = adap->params.sf_size / adap->params.sf_nsec; + + cfg_addr = t4_flash_bootcfg_addr(adap); + if (cfg_addr < 0) + return cfg_addr; + + addr = cfg_addr; + flash_cfg_start_sec = addr / SF_SEC_SIZE; + + if (size > FLASH_BOOTCFG_MAX_SIZE) { + CH_ERR(adap, "bootcfg file too large, max is %u bytes\n", + FLASH_BOOTCFG_MAX_SIZE); + return -EFBIG; + } + + i = DIV_ROUND_UP(FLASH_BOOTCFG_MAX_SIZE,/* # of sectors spanned */ + sf_sec_size); + ret = t4_flash_erase_sectors(adap, flash_cfg_start_sec, + flash_cfg_start_sec + i - 1); + + /* + * If size == 0 then we're simply erasing the FLASH sectors associated + * with the on-adapter OptionROM Configuration File. + */ + if (ret || size == 0) + goto out; + + /* this will write to the flash up to SF_PAGE_SIZE at a time */ + for (i = 0; i< size; i+= SF_PAGE_SIZE) { + if ( (size - i) < SF_PAGE_SIZE) + n = size - i; + else + n = SF_PAGE_SIZE; + ret = t4_write_flash(adap, addr, n, cfg_data, 0); + if (ret) + goto out; + + addr += SF_PAGE_SIZE; + cfg_data += SF_PAGE_SIZE; + } + +out: + if (ret) + CH_ERR(adap, "boot config data %s failed %d\n", + (size == 0 ? "clear" : "download"), ret); + return ret; +} + +/** + * t4_set_filter_mode - configure the optional components of filter tuples + * @adap: the adapter + * @mode_map: a bitmap selcting which optional filter components to enable + * + * Sets the filter mode by selecting the optional components to enable + * in filter tuples. Returns 0 on success and a negative error if the + * requested mode needs more bits than are available for optional + * components. + */ +int t4_set_filter_mode(struct adapter *adap, unsigned int mode_map) +{ + static u8 width[] = { 1, 3, 17, 17, 8, 8, 16, 9, 3, 1 }; + + int i, nbits = 0; + + for (i = S_FCOE; i <= S_FRAGMENTATION; i++) + if (mode_map & (1 << i)) + nbits += width[i]; + if (nbits > FILTER_OPT_LEN) + return -EINVAL; + if (t4_use_ldst(adap)) + t4_fw_tp_pio_rw(adap, &mode_map, 1, A_TP_VLAN_PRI_MAP, 0); + else + t4_write_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA, &mode_map, + 1, A_TP_VLAN_PRI_MAP); + read_filter_mode_and_ingress_config(adap); + + return 0; +} + +/** + * t4_clr_port_stats - clear port statistics + * @adap: the adapter + * @idx: the port index + * + * Clear HW statistics for the given port. + */ +void t4_clr_port_stats(struct adapter *adap, int idx) +{ + unsigned int i; + u32 bgmap = t4_get_mps_bg_map(adap, idx); + u32 port_base_addr; + + if (is_t4(adap)) + port_base_addr = PORT_BASE(idx); + else + port_base_addr = T5_PORT_BASE(idx); + + for (i = A_MPS_PORT_STAT_TX_PORT_BYTES_L; + i <= A_MPS_PORT_STAT_TX_PORT_PPP7_H; i += 8) + t4_write_reg(adap, port_base_addr + i, 0); + for (i = A_MPS_PORT_STAT_RX_PORT_BYTES_L; + i <= A_MPS_PORT_STAT_RX_PORT_LESS_64B_H; i += 8) + t4_write_reg(adap, port_base_addr + i, 0); + for (i = 0; i < 4; i++) + if (bgmap & (1 << i)) { + t4_write_reg(adap, + A_MPS_STAT_RX_BG_0_MAC_DROP_FRAME_L + i * 8, 0); + t4_write_reg(adap, + A_MPS_STAT_RX_BG_0_MAC_TRUNC_FRAME_L + i * 8, 0); + } +} + +/** + * t4_i2c_rd - read I2C data from adapter + * @adap: the adapter + * @port: Port number if per-port device; <0 if not + * @devid: per-port device ID or absolute device ID + * @offset: byte offset into device I2C space + * @len: byte length of I2C space data + * @buf: buffer in which to return I2C data + * + * Reads the I2C data from the indicated device and location. + */ +int t4_i2c_rd(struct adapter *adap, unsigned int mbox, + int port, unsigned int devid, + unsigned int offset, unsigned int len, + u8 *buf) +{ + u32 ldst_addrspace; + struct fw_ldst_cmd ldst; + int ret; + + if (port >= 4 || + devid >= 256 || + offset >= 256 || + len > sizeof ldst.u.i2c.data) + return -EINVAL; + + memset(&ldst, 0, sizeof ldst); + ldst_addrspace = V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_I2C); + ldst.op_to_addrspace = + cpu_to_be32(V_FW_CMD_OP(FW_LDST_CMD) | + F_FW_CMD_REQUEST | + F_FW_CMD_READ | + ldst_addrspace); + ldst.cycles_to_len16 = cpu_to_be32(FW_LEN16(ldst)); + ldst.u.i2c.pid = (port < 0 ? 0xff : port); + ldst.u.i2c.did = devid; + ldst.u.i2c.boffset = offset; + ldst.u.i2c.blen = len; + ret = t4_wr_mbox(adap, mbox, &ldst, sizeof ldst, &ldst); + if (!ret) + memcpy(buf, ldst.u.i2c.data, len); + return ret; +} + +/** + * t4_i2c_wr - write I2C data to adapter + * @adap: the adapter + * @port: Port number if per-port device; <0 if not + * @devid: per-port device ID or absolute device ID + * @offset: byte offset into device I2C space + * @len: byte length of I2C space data + * @buf: buffer containing new I2C data + * + * Write the I2C data to the indicated device and location. + */ +int t4_i2c_wr(struct adapter *adap, unsigned int mbox, + int port, unsigned int devid, + unsigned int offset, unsigned int len, + u8 *buf) +{ + u32 ldst_addrspace; + struct fw_ldst_cmd ldst; + + if (port >= 4 || + devid >= 256 || + offset >= 256 || + len > sizeof ldst.u.i2c.data) + return -EINVAL; + + memset(&ldst, 0, sizeof ldst); + ldst_addrspace = V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_I2C); + ldst.op_to_addrspace = + cpu_to_be32(V_FW_CMD_OP(FW_LDST_CMD) | + F_FW_CMD_REQUEST | + F_FW_CMD_WRITE | + ldst_addrspace); + ldst.cycles_to_len16 = cpu_to_be32(FW_LEN16(ldst)); + ldst.u.i2c.pid = (port < 0 ? 0xff : port); + ldst.u.i2c.did = devid; + ldst.u.i2c.boffset = offset; + ldst.u.i2c.blen = len; + memcpy(ldst.u.i2c.data, buf, len); + return t4_wr_mbox(adap, mbox, &ldst, sizeof ldst, &ldst); +} + +/** + * t4_sge_ctxt_rd - read an SGE context through FW + * @adap: the adapter + * @mbox: mailbox to use for the FW command + * @cid: the context id + * @ctype: the context type + * @data: where to store the context data + * + * Issues a FW command through the given mailbox to read an SGE context. + */ +int t4_sge_ctxt_rd(struct adapter *adap, unsigned int mbox, unsigned int cid, + enum ctxt_type ctype, u32 *data) +{ + int ret; + struct fw_ldst_cmd c; + + if (ctype == CTXT_EGRESS) + ret = FW_LDST_ADDRSPC_SGE_EGRC; + else if (ctype == CTXT_INGRESS) + ret = FW_LDST_ADDRSPC_SGE_INGC; + else if (ctype == CTXT_FLM) + ret = FW_LDST_ADDRSPC_SGE_FLMC; + else + ret = FW_LDST_ADDRSPC_SGE_CONMC; + + memset(&c, 0, sizeof(c)); + c.op_to_addrspace = cpu_to_be32(V_FW_CMD_OP(FW_LDST_CMD) | + F_FW_CMD_REQUEST | F_FW_CMD_READ | + V_FW_LDST_CMD_ADDRSPACE(ret)); + c.cycles_to_len16 = cpu_to_be32(FW_LEN16(c)); + c.u.idctxt.physid = cpu_to_be32(cid); + + ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); + if (ret == 0) { + data[0] = be32_to_cpu(c.u.idctxt.ctxt_data0); + data[1] = be32_to_cpu(c.u.idctxt.ctxt_data1); + data[2] = be32_to_cpu(c.u.idctxt.ctxt_data2); + data[3] = be32_to_cpu(c.u.idctxt.ctxt_data3); + data[4] = be32_to_cpu(c.u.idctxt.ctxt_data4); + data[5] = be32_to_cpu(c.u.idctxt.ctxt_data5); + } + return ret; +} + +/** + * t4_sge_ctxt_rd_bd - read an SGE context bypassing FW + * @adap: the adapter + * @cid: the context id + * @ctype: the context type + * @data: where to store the context data + * + * Reads an SGE context directly, bypassing FW. This is only for + * debugging when FW is unavailable. + */ +int t4_sge_ctxt_rd_bd(struct adapter *adap, unsigned int cid, enum ctxt_type ctype, + u32 *data) +{ + int i, ret; + + t4_write_reg(adap, A_SGE_CTXT_CMD, V_CTXTQID(cid) | V_CTXTTYPE(ctype)); + ret = t4_wait_op_done(adap, A_SGE_CTXT_CMD, F_BUSY, 0, 3, 1); + if (!ret) + for (i = A_SGE_CTXT_DATA0; i <= A_SGE_CTXT_DATA5; i += 4) + *data++ = t4_read_reg(adap, i); + return ret; +} + int t4_sched_config(struct adapter *adapter, int type, int minmaxen, int sleep_ok) { @@ -5797,3 +9079,78 @@ int t4_sched_params(struct adapter *adapter, int type, int level, int mode, return t4_wr_mbox_meat(adapter,adapter->mbox, &cmd, sizeof(cmd), NULL, sleep_ok); } + +/* + * t4_config_watchdog - configure (enable/disable) a watchdog timer + * @adapter: the adapter + * @mbox: mailbox to use for the FW command + * @pf: the PF owning the queue + * @vf: the VF owning the queue + * @timeout: watchdog timeout in ms + * @action: watchdog timer / action + * + * There are separate watchdog timers for each possible watchdog + * action. Configure one of the watchdog timers by setting a non-zero + * timeout. Disable a watchdog timer by using a timeout of zero. + */ +int t4_config_watchdog(struct adapter *adapter, unsigned int mbox, + unsigned int pf, unsigned int vf, + unsigned int timeout, unsigned int action) +{ + struct fw_watchdog_cmd wdog; + unsigned int ticks; + + /* + * The watchdog command expects a timeout in units of 10ms so we need + * to convert it here (via rounding) and force a minimum of one 10ms + * "tick" if the timeout is non-zero but the convertion results in 0 + * ticks. + */ + ticks = (timeout + 5)/10; + if (timeout && !ticks) + ticks = 1; + + memset(&wdog, 0, sizeof wdog); + wdog.op_to_vfn = cpu_to_be32(V_FW_CMD_OP(FW_WATCHDOG_CMD) | + F_FW_CMD_REQUEST | + F_FW_CMD_WRITE | + V_FW_PARAMS_CMD_PFN(pf) | + V_FW_PARAMS_CMD_VFN(vf)); + wdog.retval_len16 = cpu_to_be32(FW_LEN16(wdog)); + wdog.timeout = cpu_to_be32(ticks); + wdog.action = cpu_to_be32(action); + + return t4_wr_mbox(adapter, mbox, &wdog, sizeof wdog, NULL); +} + +int t4_get_devlog_level(struct adapter *adapter, unsigned int *level) +{ + struct fw_devlog_cmd devlog_cmd; + int ret; + + memset(&devlog_cmd, 0, sizeof(devlog_cmd)); + devlog_cmd.op_to_write = cpu_to_be32(V_FW_CMD_OP(FW_DEVLOG_CMD) | + F_FW_CMD_REQUEST | F_FW_CMD_READ); + devlog_cmd.retval_len16 = cpu_to_be32(FW_LEN16(devlog_cmd)); + ret = t4_wr_mbox(adapter, adapter->mbox, &devlog_cmd, + sizeof(devlog_cmd), &devlog_cmd); + if (ret) + return ret; + + *level = devlog_cmd.level; + return 0; +} + +int t4_set_devlog_level(struct adapter *adapter, unsigned int level) +{ + struct fw_devlog_cmd devlog_cmd; + + memset(&devlog_cmd, 0, sizeof(devlog_cmd)); + devlog_cmd.op_to_write = cpu_to_be32(V_FW_CMD_OP(FW_DEVLOG_CMD) | + F_FW_CMD_REQUEST | + F_FW_CMD_WRITE); + devlog_cmd.level = level; + devlog_cmd.retval_len16 = cpu_to_be32(FW_LEN16(devlog_cmd)); + return t4_wr_mbox(adapter, adapter->mbox, &devlog_cmd, + sizeof(devlog_cmd), &devlog_cmd); +} |