1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-11-29 08:08:37 +00:00

cxgbe(4): Add general purpose routines that offer safe access to the

chip's memory windows.  Convert existing users of these windows to the
new routines.
This commit is contained in:
Navdeep Parhar 2016-03-10 06:15:31 +00:00
parent 6cac5eb749
commit c912289045
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=296603
3 changed files with 176 additions and 121 deletions

View File

@ -437,6 +437,29 @@ struct hw_buf_info {
int size;
};
enum {
NUM_MEMWIN = 3,
MEMWIN0_APERTURE = 2048,
MEMWIN0_BASE = 0x1b800,
MEMWIN1_APERTURE = 32768,
MEMWIN1_BASE = 0x28000,
MEMWIN2_APERTURE_T4 = 65536,
MEMWIN2_BASE_T4 = 0x30000,
MEMWIN2_APERTURE_T5 = 128 * 1024,
MEMWIN2_BASE_T5 = 0x60000,
};
struct memwin {
struct rwlock mw_lock __aligned(CACHE_LINE_SIZE);
uint32_t mw_base; /* constant after setup_memwin */
uint32_t mw_aperture; /* ditto */
uint32_t mw_curpos; /* protected by mw_lock */
};
enum {
FL_STARVING = (1 << 0), /* on the adapter's list of starving fl's */
FL_DOOMED = (1 << 1), /* about to be destroyed */
@ -806,6 +829,8 @@ struct adapter {
struct mtx reg_lock; /* for indirect register access */
struct memwin memwin[NUM_MEMWIN]; /* memory windows */
an_handler_t an_handler __aligned(CACHE_LINE_SIZE);
fw_msg_handler_t fw_msg_handler[7]; /* NUM_FW6_TYPES */
cpl_handler_t cpl_handler[0xef]; /* NUM_CPL_CMDS */

View File

@ -52,20 +52,6 @@ enum {
enum { MEM_EDC0, MEM_EDC1, MEM_MC, MEM_MC0 = MEM_MC, MEM_MC1 };
enum {
MEMWIN0_APERTURE = 2048,
MEMWIN0_BASE = 0x1b800,
MEMWIN1_APERTURE = 32768,
MEMWIN1_BASE = 0x28000,
MEMWIN2_APERTURE_T4 = 65536,
MEMWIN2_BASE_T4 = 0x30000,
MEMWIN2_APERTURE_T5 = 128 * 1024,
MEMWIN2_BASE_T5 = 0x60000,
};
enum dev_master { MASTER_CANT, MASTER_MAY, MASTER_MUST };
enum dev_state { DEV_STATE_UNINIT, DEV_STATE_INIT, DEV_STATE_ERR };
@ -76,11 +62,6 @@ enum {
PAUSE_AUTONEG = 1 << 2
};
struct memwin {
uint32_t base;
uint32_t aperture;
};
struct port_stats {
u64 tx_octets; /* total # of octets in good frames */
u64 tx_frames; /* all good frames */

View File

@ -399,12 +399,16 @@ struct filter_entry {
static int map_bars_0_and_4(struct adapter *);
static int map_bar_2(struct adapter *);
static void setup_memwin(struct adapter *);
static void position_memwin(struct adapter *, int, uint32_t);
static int rw_via_memwin(struct adapter *, int, uint32_t, uint32_t *, int, int);
static inline int read_via_memwin(struct adapter *, int, uint32_t, uint32_t *,
int);
static inline int write_via_memwin(struct adapter *, int, uint32_t,
const uint32_t *, int);
static int validate_mem_range(struct adapter *, uint32_t, int);
static int fwmtype_to_hwmtype(int);
static int validate_mt_off_len(struct adapter *, int, uint32_t, int,
uint32_t *);
static void memwin_info(struct adapter *, int, uint32_t *, uint32_t *);
static uint32_t position_memwin(struct adapter *, int, uint32_t);
static int cfg_itype_and_nqueues(struct adapter *, int, int, int,
struct intrs_and_queues *);
static int prep_firmware(struct adapter *);
@ -1164,6 +1168,13 @@ t4_detach(device_t dev)
if (mtx_initialized(&sc->reg_lock))
mtx_destroy(&sc->reg_lock);
for (i = 0; i < NUM_MEMWIN; i++) {
struct memwin *mw = &sc->memwin[i];
if (rw_initialized(&mw->mw_lock))
rw_destroy(&mw->mw_lock);
}
bzero(sc, sizeof(*sc));
return (0);
@ -1965,13 +1976,18 @@ map_bar_2(struct adapter *sc)
return (0);
}
static const struct memwin t4_memwin[] = {
struct memwin_init {
uint32_t base;
uint32_t aperture;
};
static const struct memwin_init t4_memwin[NUM_MEMWIN] = {
{ MEMWIN0_BASE, MEMWIN0_APERTURE },
{ MEMWIN1_BASE, MEMWIN1_APERTURE },
{ MEMWIN2_BASE_T4, MEMWIN2_APERTURE_T4 }
};
static const struct memwin t5_memwin[] = {
static const struct memwin_init t5_memwin[NUM_MEMWIN] = {
{ MEMWIN0_BASE, MEMWIN0_APERTURE },
{ MEMWIN1_BASE, MEMWIN1_APERTURE },
{ MEMWIN2_BASE_T5, MEMWIN2_APERTURE_T5 },
@ -1980,8 +1996,9 @@ static const struct memwin t5_memwin[] = {
static void
setup_memwin(struct adapter *sc)
{
const struct memwin *mw;
int i, n;
const struct memwin_init *mw_init;
struct memwin *mw;
int i;
uint32_t bar0;
if (is_t4(sc)) {
@ -1995,27 +2012,125 @@ setup_memwin(struct adapter *sc)
bar0 = t4_hw_pci_read_cfg4(sc, PCIR_BAR(0));
bar0 &= (uint32_t) PCIM_BAR_MEM_BASE;
mw = &t4_memwin[0];
n = nitems(t4_memwin);
mw_init = &t4_memwin[0];
} else {
/* T5 uses the relative offset inside the PCIe BAR */
/* T5+ use the relative offset inside the PCIe BAR */
bar0 = 0;
mw = &t5_memwin[0];
n = nitems(t5_memwin);
mw_init = &t5_memwin[0];
}
for (i = 0; i < n; i++, mw++) {
for (i = 0, mw = &sc->memwin[0]; i < NUM_MEMWIN; i++, mw_init++, mw++) {
rw_init(&mw->mw_lock, "memory window access");
mw->mw_base = mw_init->base;
mw->mw_aperture = mw_init->aperture;
mw->mw_curpos = 0;
t4_write_reg(sc,
PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, i),
(mw->base + bar0) | V_BIR(0) |
V_WINDOW(ilog2(mw->aperture) - 10));
(mw->mw_base + bar0) | V_BIR(0) |
V_WINDOW(ilog2(mw->mw_aperture) - 10));
rw_wlock(&mw->mw_lock);
position_memwin(sc, i, 0);
rw_wunlock(&mw->mw_lock);
}
/* flush */
t4_read_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 2));
}
/*
* Positions the memory window at the given address in the card's address space.
* There are some alignment requirements and the actual position may be at an
* address prior to the requested address. mw->mw_curpos always has the actual
* position of the window.
*/
static void
position_memwin(struct adapter *sc, int idx, uint32_t addr)
{
struct memwin *mw;
uint32_t pf;
uint32_t reg;
MPASS(idx >= 0 && idx < NUM_MEMWIN);
mw = &sc->memwin[idx];
rw_assert(&mw->mw_lock, RA_WLOCKED);
if (is_t4(sc)) {
pf = 0;
mw->mw_curpos = addr & ~0xf; /* start must be 16B aligned */
} else {
pf = V_PFNUM(sc->pf);
mw->mw_curpos = addr & ~0x7f; /* start must be 128B aligned */
}
reg = PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, idx);
t4_write_reg(sc, reg, mw->mw_curpos | pf);
t4_read_reg(sc, reg); /* flush */
}
static int
rw_via_memwin(struct adapter *sc, int idx, uint32_t addr, uint32_t *val,
int len, int rw)
{
struct memwin *mw;
uint32_t mw_end, v;
MPASS(idx >= 0 && idx < NUM_MEMWIN);
/* Memory can only be accessed in naturally aligned 4 byte units */
if (addr & 3 || len & 3 || len <= 0)
return (EINVAL);
mw = &sc->memwin[idx];
while (len > 0) {
rw_rlock(&mw->mw_lock);
mw_end = mw->mw_curpos + mw->mw_aperture;
if (addr >= mw_end || addr + len <= mw->mw_curpos) {
/* Will need to reposition the window */
if (!rw_try_upgrade(&mw->mw_lock)) {
rw_runlock(&mw->mw_lock);
rw_wlock(&mw->mw_lock);
}
rw_assert(&mw->mw_lock, RA_WLOCKED);
position_memwin(sc, idx, addr);
rw_downgrade(&mw->mw_lock);
mw_end = mw->mw_curpos + mw->mw_aperture;
}
rw_assert(&mw->mw_lock, RA_RLOCKED);
while (addr < mw_end && len > 0) {
if (rw == 0) {
v = t4_read_reg(sc, mw->mw_base + addr -
mw->mw_curpos);
*val++ = le32toh(v);
} else {
v = *val++;
t4_write_reg(sc, mw->mw_base + addr -
mw->mw_curpos, htole32(v));;
}
addr += 4;
len -= 4;
}
rw_runlock(&mw->mw_lock);
}
return (0);
}
static inline int
read_via_memwin(struct adapter *sc, int idx, uint32_t addr, uint32_t *val,
int len)
{
return (rw_via_memwin(sc, idx, addr, val, len, 0));
}
static inline int
write_via_memwin(struct adapter *sc, int idx, uint32_t addr,
const uint32_t *val, int len)
{
return (rw_via_memwin(sc, idx, addr, (void *)(uintptr_t)val, len, 1));
}
static int
t4_range_cmp(const void *a, const void *b)
{
@ -2217,58 +2332,6 @@ validate_mt_off_len(struct adapter *sc, int mtype, uint32_t off, int len,
return (validate_mem_range(sc, *addr, len));
}
static void
memwin_info(struct adapter *sc, int win, uint32_t *base, uint32_t *aperture)
{
const struct memwin *mw;
if (is_t4(sc)) {
KASSERT(win >= 0 && win < nitems(t4_memwin),
("%s: incorrect memwin# (%d)", __func__, win));
mw = &t4_memwin[win];
} else {
KASSERT(win >= 0 && win < nitems(t5_memwin),
("%s: incorrect memwin# (%d)", __func__, win));
mw = &t5_memwin[win];
}
if (base != NULL)
*base = mw->base;
if (aperture != NULL)
*aperture = mw->aperture;
}
/*
* Positions the memory window such that it can be used to access the specified
* address in the chip's address space. The return value is the offset of addr
* from the start of the window.
*/
static uint32_t
position_memwin(struct adapter *sc, int n, uint32_t addr)
{
uint32_t start, pf;
uint32_t reg;
KASSERT(n >= 0 && n <= 3,
("%s: invalid window %d.", __func__, n));
KASSERT((addr & 3) == 0,
("%s: addr (0x%x) is not at a 4B boundary.", __func__, addr));
if (is_t4(sc)) {
pf = 0;
start = addr & ~0xf; /* start must be 16B aligned */
} else {
pf = V_PFNUM(sc->pf);
start = addr & ~0x7f; /* start must be 128B aligned */
}
reg = PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, n);
t4_write_reg(sc, reg, start | pf);
t4_read_reg(sc, reg);
return (addr - start);
}
static int
cfg_itype_and_nqueues(struct adapter *sc, int n10g, int n1g, int num_vis,
struct intrs_and_queues *iaq)
@ -2869,9 +2932,9 @@ partition_resources(struct adapter *sc, const struct firmware *default_cfg,
}
if (strncmp(sc->cfg_file, FLASH_CF, sizeof(sc->cfg_file)) != 0) {
u_int cflen, i, n;
u_int cflen;
const uint32_t *cfdata;
uint32_t param, val, addr, off, mw_base, mw_aperture;
uint32_t param, val, addr;
KASSERT(cfg != NULL || default_cfg != NULL,
("%s: no config to upload", __func__));
@ -2921,16 +2984,7 @@ partition_resources(struct adapter *sc, const struct firmware *default_cfg,
__func__, mtype, moff, cflen, rc);
goto use_config_on_flash;
}
memwin_info(sc, 2, &mw_base, &mw_aperture);
while (cflen) {
off = position_memwin(sc, 2, addr);
n = min(cflen, mw_aperture - off);
for (i = 0; i < n; i += 4)
t4_write_reg(sc, mw_base + off + i, *cfdata++);
cflen -= n;
addr += n;
}
write_via_memwin(sc, 2, addr, cfdata, cflen);
} else {
use_config_on_flash:
mtype = FW_MEMTYPE_FLASH;
@ -7486,22 +7540,22 @@ set_filter_mode(struct adapter *sc, uint32_t mode)
static inline uint64_t
get_filter_hits(struct adapter *sc, uint32_t fid)
{
uint32_t mw_base, off, tcb_base = t4_read_reg(sc, A_TP_CMM_TCB_BASE);
uint64_t hits;
uint32_t tcb_addr;
memwin_info(sc, 0, &mw_base, NULL);
tcb_addr = t4_read_reg(sc, A_TP_CMM_TCB_BASE) +
(fid + sc->tids.ftid_base) * TCB_SIZE;
off = position_memwin(sc, 0,
tcb_base + (fid + sc->tids.ftid_base) * TCB_SIZE);
if (is_t4(sc)) {
hits = t4_read_reg64(sc, mw_base + off + 16);
hits = be64toh(hits);
} else {
hits = t4_read_reg(sc, mw_base + off + 24);
hits = be32toh(hits);
}
uint64_t hits;
return (hits);
read_via_memwin(sc, 0, tcb_addr + 16, (uint32_t *)&hits, 8);
return (be64toh(hits));
} else {
uint32_t hits;
read_via_memwin(sc, 0, tcb_addr + 24, &hits, 4);
return (be32toh(hits));
}
}
static int
@ -7975,12 +8029,12 @@ load_fw(struct adapter *sc, struct t4_data *fw)
return (rc);
}
#define MAX_READ_BUF_SIZE (128 * 1024)
static int
read_card_mem(struct adapter *sc, int win, struct t4_mem_range *mr)
{
uint32_t addr, off, remaining, i, n;
uint32_t *buf, *b;
uint32_t mw_base, mw_aperture;
uint32_t addr, remaining, n;
uint32_t *buf;
int rc;
uint8_t *dst;
@ -7988,25 +8042,19 @@ read_card_mem(struct adapter *sc, int win, struct t4_mem_range *mr)
if (rc != 0)
return (rc);
memwin_info(sc, win, &mw_base, &mw_aperture);
buf = b = malloc(min(mr->len, mw_aperture), M_CXGBE, M_WAITOK);
buf = malloc(min(mr->len, MAX_READ_BUF_SIZE), M_CXGBE, M_WAITOK);
addr = mr->addr;
remaining = mr->len;
dst = (void *)mr->data;
while (remaining) {
off = position_memwin(sc, win, addr);
/* number of bytes that we'll copy in the inner loop */
n = min(remaining, mw_aperture - off);
for (i = 0; i < n; i += 4)
*b++ = t4_read_reg(sc, mw_base + off + i);
n = min(remaining, MAX_READ_BUF_SIZE);
read_via_memwin(sc, 2, addr, buf, n);
rc = copyout(buf, dst, n);
if (rc != 0)
break;
b = buf;
dst += n;
remaining -= n;
addr += n;
@ -8015,6 +8063,7 @@ read_card_mem(struct adapter *sc, int win, struct t4_mem_range *mr)
free(buf, M_CXGBE);
return (rc);
}
#undef MAX_READ_BUF_SIZE
static int
read_i2c(struct adapter *sc, struct t4_i2c_data *i2cd)