-/* $OpenBSD: if_mcx.c,v 1.105 2022/06/26 15:33:37 jmatthew Exp $ */
+/* $OpenBSD: if_mcx.c,v 1.106 2022/11/22 06:48:32 jmatthew Exp $ */
/*
* Copyright (c) 2017 David Gwynne <dlg@openbsd.org>
#define MCX_HARDMTU 9500
+enum mcx_cmdq_slot {
+ MCX_CMDQ_SLOT_POLL = 0,
+ MCX_CMDQ_SLOT_IOCTL,
+ MCX_CMDQ_SLOT_KSTAT,
+ MCX_CMDQ_SLOT_LINK,
+
+ MCX_CMDQ_NUM_SLOTS
+};
+
#define MCX_PAGE_SHIFT 12
#define MCX_PAGE_SIZE (1 << MCX_PAGE_SHIFT)
unsigned int sc_cmdq_size;
unsigned int sc_cmdq_token;
+ struct mutex sc_cmdq_mtx;
+ struct rwlock sc_cmdq_kstat_lk;
+ struct rwlock sc_cmdq_ioctl_lk;
struct mcx_hwmem sc_boot_pages;
struct mcx_hwmem sc_init_pages;
static int mcx_enable_hca(struct mcx_softc *);
static int mcx_teardown_hca(struct mcx_softc *, uint16_t);
static int mcx_access_hca_reg(struct mcx_softc *, uint16_t, int, void *,
- int);
+ int, enum mcx_cmdq_slot);
static int mcx_issi(struct mcx_softc *);
static int mcx_pages(struct mcx_softc *, struct mcx_hwmem *, uint16_t);
static int mcx_hca_max_caps(struct mcx_softc *);
sc->sc_cmdq_mask = cq_size - 1;
sc->sc_cmdq_size = cq_stride;
+ rw_init(&sc->sc_cmdq_kstat_lk, "mcxkstat");
+ rw_init(&sc->sc_cmdq_ioctl_lk, "mcxioctl");
+ mtx_init(&sc->sc_cmdq_mtx, IPL_NET);
if (mcx_enable_hca(sc) != 0) {
/* error printed by mcx_enable_hca */
{
uint8_t token;
+ mtx_enter(&sc->sc_cmdq_mtx);
do {
token = ++sc->sc_cmdq_token;
} while (token == 0);
+ mtx_leave(&sc->sc_cmdq_mtx);
return (token);
}
+static struct mcx_cmdq_entry *
+mcx_get_cmdq_entry(struct mcx_softc *sc, enum mcx_cmdq_slot slot)
+{
+ struct mcx_cmdq_entry *cqe;
+
+ cqe = MCX_DMA_KVA(&sc->sc_cmdq_mem);
+ cqe += slot;
+
+ /* make sure the slot isn't running a command already */
+ bus_dmamap_sync(sc->sc_dmat, MCX_DMA_MAP(&sc->sc_cmdq_mem),
+ 0, MCX_DMA_LEN(&sc->sc_cmdq_mem), BUS_DMASYNC_POSTRW);
+ if ((cqe->cq_status & MCX_CQ_STATUS_OWN_MASK) !=
+ MCX_CQ_STATUS_OWN_SW)
+ cqe = NULL;
+
+ return (cqe);
+}
+
static void
mcx_cmdq_init(struct mcx_softc *sc, struct mcx_cmdq_entry *cqe,
uint32_t ilen, uint32_t olen, uint8_t token)
BUS_SPACE_BARRIER_WRITE);
}
+static int
+mcx_cmdq_exec(struct mcx_softc *sc, struct mcx_cmdq_entry *cqe,
+ unsigned int slot, unsigned int msec)
+{
+ int err;
+
+ if (slot == MCX_CMDQ_SLOT_POLL) {
+ mcx_cmdq_post(sc, cqe, slot);
+ return (mcx_cmdq_poll(sc, cqe, msec));
+ }
+
+ mtx_enter(&sc->sc_cmdq_mtx);
+ mcx_cmdq_post(sc, cqe, slot);
+
+ err = 0;
+ while (err == 0) {
+ err = msleep_nsec(&sc->sc_cmdq_token, &sc->sc_cmdq_mtx, 0,
+ "mcxcmd", msec * 1000);
+ bus_dmamap_sync(sc->sc_dmat, MCX_DMA_MAP(&sc->sc_cmdq_mem), 0,
+ MCX_DMA_LEN(&sc->sc_cmdq_mem), BUS_DMASYNC_POSTRW);
+ if ((cqe->cq_status & MCX_CQ_STATUS_OWN_MASK) ==
+ MCX_CQ_STATUS_OWN_SW) {
+ err = 0;
+ break;
+ }
+ }
+
+ mtx_leave(&sc->sc_cmdq_mtx);
+ return (err);
+}
+
static int
mcx_enable_hca(struct mcx_softc *sc)
{
static int
mcx_access_hca_reg(struct mcx_softc *sc, uint16_t reg, int op, void *data,
- int len)
+ int len, enum mcx_cmdq_slot slot)
{
struct mcx_dmamem mxm;
struct mcx_cmdq_entry *cqe;
uint8_t token = mcx_cmdq_token(sc);
int error, nmb;
- cqe = MCX_DMA_KVA(&sc->sc_cmdq_mem);
+ cqe = mcx_get_cmdq_entry(sc, slot);
+ if (cqe == NULL)
+ return (-1);
+
mcx_cmdq_init(sc, cqe, sizeof(*in) + len, sizeof(*out) + len,
token);
mcx_cmdq_mboxes_sign(&mxm, nmb);
mcx_cmdq_mboxes_sync(sc, &mxm, BUS_DMASYNC_PRERW);
- mcx_cmdq_post(sc, cqe, 0);
- error = mcx_cmdq_poll(sc, cqe, 1000);
+ error = mcx_cmdq_exec(sc, cqe, slot, 1000);
mcx_cmdq_mboxes_sync(sc, &mxm, BUS_DMASYNC_POSTRW);
if (error != 0) {
memset(&pmtu, 0, sizeof(pmtu));
pmtu.rp_local_port = 1;
error = mcx_access_hca_reg(sc, MCX_REG_PMTU, MCX_REG_OP_READ, &pmtu,
- sizeof(pmtu));
+ sizeof(pmtu), MCX_CMDQ_SLOT_POLL);
if (error != 0) {
printf(", unable to get port MTU\n");
return error;
mtu = min(mtu, betoh16(pmtu.rp_max_mtu));
pmtu.rp_admin_mtu = htobe16(mtu);
error = mcx_access_hca_reg(sc, MCX_REG_PMTU, MCX_REG_OP_WRITE, &pmtu,
- sizeof(pmtu));
+ sizeof(pmtu), MCX_CMDQ_SLOT_POLL);
if (error != 0) {
printf(", unable to set port MTU\n");
return error;
uint8_t token = mcx_cmdq_token(sc);
int error;
- cqe = MCX_DMA_KVA(&sc->sc_cmdq_mem);
+ cqe = mcx_get_cmdq_entry(sc, MCX_CMDQ_SLOT_KSTAT);
+ if (cqe == NULL)
+ return (-1);
+
mcx_cmdq_init(sc, cqe, sizeof(*in), sizeof(*out) + sizeof(*mbout) + 16,
token);
mcx_cmdq_mboxes_sign(&mxm, 1);
- mcx_cmdq_post(sc, cqe, 0);
- error = mcx_cmdq_poll(sc, cqe, 1000);
+ error = mcx_cmdq_exec(sc, cqe, MCX_CMDQ_SLOT_KSTAT, 1000);
if (error != 0) {
printf("%s: query rq timeout\n", DEVNAME(sc));
goto free;
uint8_t token = mcx_cmdq_token(sc);
int error;
- cqe = MCX_DMA_KVA(&sc->sc_cmdq_mem);
+ cqe = mcx_get_cmdq_entry(sc, MCX_CMDQ_SLOT_KSTAT);
+ if (cqe == NULL)
+ return (-1);
+
mcx_cmdq_init(sc, cqe, sizeof(*in), sizeof(*out) + sizeof(*mbout) + 16,
token);
mcx_cmdq_mboxes_sign(&mxm, 1);
- mcx_cmdq_post(sc, cqe, 0);
- error = mcx_cmdq_poll(sc, cqe, 1000);
+ error = mcx_cmdq_exec(sc, cqe, MCX_CMDQ_SLOT_KSTAT, 1000);
if (error != 0) {
printf("%s: query sq timeout\n", DEVNAME(sc));
goto free;
uint8_t token = mcx_cmdq_token(sc);
int error;
- cqe = MCX_DMA_KVA(&sc->sc_cmdq_mem);
+ cqe = mcx_get_cmdq_entry(sc, MCX_CMDQ_SLOT_KSTAT);
+ if (cqe == NULL)
+ return (-1);
+
mcx_cmdq_init(sc, cqe, sizeof(*in), sizeof(*out) + sizeof(*ctx) + 16,
token);
mcx_cmdq_mboxes_sign(&mxm, 1);
- mcx_cmdq_post(sc, cqe, 0);
- error = mcx_cmdq_poll(sc, cqe, 1000);
+ error = mcx_cmdq_exec(sc, cqe, MCX_CMDQ_SLOT_KSTAT, 1000);
if (error != 0) {
printf("%s: query cq timeout\n", DEVNAME(sc));
goto free;
uint8_t token = mcx_cmdq_token(sc);
int error;
- cqe = MCX_DMA_KVA(&sc->sc_cmdq_mem);
+ cqe = mcx_get_cmdq_entry(sc, MCX_CMDQ_SLOT_KSTAT);
+ if (cqe == NULL)
+ return (-1);
+
mcx_cmdq_init(sc, cqe, sizeof(*in), sizeof(*out) + sizeof(*ctx) + 16,
token);
mcx_cmdq_mboxes_sign(&mxm, 1);
- mcx_cmdq_post(sc, cqe, 0);
- error = mcx_cmdq_poll(sc, cqe, 1000);
+ error = mcx_cmdq_exec(sc, cqe, MCX_CMDQ_SLOT_KSTAT, 1000);
if (error != 0) {
printf("%s: query eq timeout\n", DEVNAME(sc));
goto free;
break;
case MCX_EVENT_TYPE_CMD_COMPLETION:
- /* wakeup probably */
+ mtx_enter(&sc->sc_cmdq_mtx);
+ wakeup(&sc->sc_cmdq_token);
+ mtx_leave(&sc->sc_cmdq_mtx);
break;
case MCX_EVENT_TYPE_PORT_CHANGE:
struct mcx_reg_pmlp pmlp;
int offset, error;
+ rw_enter_write(&sc->sc_cmdq_ioctl_lk);
+
/* get module number */
memset(&pmlp, 0, sizeof(pmlp));
pmlp.rp_local_port = 1;
error = mcx_access_hca_reg(sc, MCX_REG_PMLP, MCX_REG_OP_READ, &pmlp,
- sizeof(pmlp));
+ sizeof(pmlp), MCX_CMDQ_SLOT_IOCTL);
if (error != 0) {
printf("%s: unable to get eeprom module number\n",
DEVNAME(sc));
- return error;
+ goto out;
}
for (offset = 0; offset < 256; offset += MCX_MCIA_EEPROM_BYTES) {
mcia.rm_size = htobe16(MCX_MCIA_EEPROM_BYTES);
error = mcx_access_hca_reg(sc, MCX_REG_MCIA, MCX_REG_OP_READ,
- &mcia, sizeof(mcia));
+ &mcia, sizeof(mcia), MCX_CMDQ_SLOT_IOCTL);
if (error != 0) {
printf("%s: unable to read eeprom at %x\n",
DEVNAME(sc), offset);
- return error;
+ goto out;
}
memcpy(sff->sff_data + offset, mcia.rm_data,
MCX_MCIA_EEPROM_BYTES);
}
- return 0;
+ out:
+ rw_exit_write(&sc->sc_cmdq_ioctl_lk);
+ return (error);
}
static int
ptys.rp_local_port = 1;
ptys.rp_proto_mask = MCX_REG_PTYS_PROTO_MASK_ETH;
if (mcx_access_hca_reg(sc, MCX_REG_PTYS, MCX_REG_OP_READ, &ptys,
- sizeof(ptys)) != 0) {
+ sizeof(ptys), MCX_CMDQ_SLOT_POLL) != 0) {
printf("%s: unable to read port type/speed\n", DEVNAME(sc));
return;
}
ptys.rp_local_port = 1;
ptys.rp_proto_mask = MCX_REG_PTYS_PROTO_MASK_ETH;
+ rw_enter_write(&sc->sc_cmdq_ioctl_lk);
if (mcx_access_hca_reg(sc, MCX_REG_PTYS, MCX_REG_OP_READ, &ptys,
- sizeof(ptys)) != 0) {
+ sizeof(ptys), MCX_CMDQ_SLOT_IOCTL) != 0) {
printf("%s: unable to read port type/speed\n", DEVNAME(sc));
- return;
+ goto out;
}
proto_oper = betoh32(ptys.rp_eth_proto_oper);
ifmr->ifm_active = IFM_ETHER | IFM_AUTO | media_oper;
/* txpause, rxpause, duplex? */
}
+ out:
+ rw_exit_write(&sc->sc_cmdq_ioctl_lk);
}
static int
return EINVAL;
error = 0;
+ rw_enter_write(&sc->sc_cmdq_ioctl_lk);
if (IFM_SUBTYPE(sc->sc_media.ifm_media) == IFM_AUTO) {
/* read ptys to get supported media */
ptys.rp_local_port = 1;
ptys.rp_proto_mask = MCX_REG_PTYS_PROTO_MASK_ETH;
if (mcx_access_hca_reg(sc, MCX_REG_PTYS, MCX_REG_OP_READ,
- &ptys, sizeof(ptys)) != 0) {
+ &ptys, sizeof(ptys), MCX_CMDQ_SLOT_IOCTL) != 0) {
printf("%s: unable to read port type/speed\n",
DEVNAME(sc));
- return EIO;
+ error = EIO;
+ goto out;
}
media = betoh32(ptys.rp_eth_proto_cap);
paos.rp_admin_status = MCX_REG_PAOS_ADMIN_STATUS_DOWN;
paos.rp_admin_state_update = MCX_REG_PAOS_ADMIN_STATE_UPDATE_EN;
if (mcx_access_hca_reg(sc, MCX_REG_PAOS, MCX_REG_OP_WRITE, &paos,
- sizeof(paos)) != 0) {
+ sizeof(paos), MCX_CMDQ_SLOT_IOCTL) != 0) {
printf("%s: unable to set port state to down\n", DEVNAME(sc));
- return EIO;
+ error = EIO;
+ goto out;
}
memset(&ptys, 0, sizeof(ptys));
ptys.rp_proto_mask = MCX_REG_PTYS_PROTO_MASK_ETH;
ptys.rp_eth_proto_admin = htobe32(media);
if (mcx_access_hca_reg(sc, MCX_REG_PTYS, MCX_REG_OP_WRITE, &ptys,
- sizeof(ptys)) != 0) {
+ sizeof(ptys), MCX_CMDQ_SLOT_IOCTL) != 0) {
printf("%s: unable to set port media type/speed\n",
DEVNAME(sc));
error = EIO;
+ /* continue on */
}
/* re-enable the port to start negotiation */
paos.rp_admin_status = MCX_REG_PAOS_ADMIN_STATUS_UP;
paos.rp_admin_state_update = MCX_REG_PAOS_ADMIN_STATE_UPDATE_EN;
if (mcx_access_hca_reg(sc, MCX_REG_PAOS, MCX_REG_OP_WRITE, &paos,
- sizeof(paos)) != 0) {
+ sizeof(paos), MCX_CMDQ_SLOT_IOCTL) != 0) {
printf("%s: unable to set port state to up\n", DEVNAME(sc));
error = EIO;
}
+ out:
+ rw_exit_write(&sc->sc_cmdq_ioctl_lk);
return error;
}
.rp_proto_mask = MCX_REG_PTYS_PROTO_MASK_ETH,
};
int link_state = LINK_STATE_DOWN;
+ int slot;
+
+ if (cold) {
+ slot = MCX_CMDQ_SLOT_POLL;
+ } else
+ slot = MCX_CMDQ_SLOT_LINK;
if (mcx_access_hca_reg(sc, MCX_REG_PTYS, MCX_REG_OP_READ, &ptys,
- sizeof(ptys)) == 0) {
+ sizeof(ptys), slot) == 0) {
uint32_t proto_oper = betoh32(ptys.rp_eth_proto_oper);
uint64_t baudrate = 0;
unsigned int i;
ks->ks_data = kvs;
ks->ks_datalen = ksp->ksp_n * sizeof(*kvs);
ks->ks_read = mcx_kstat_ppcnt_read;
+ kstat_set_wlock(ks, &sc->sc_cmdq_kstat_lk);
kstat_install(ks);
unsigned int i;
int rv;
- KERNEL_LOCK(); /* XXX */
rv = mcx_access_hca_reg(sc, MCX_REG_PPCNT, MCX_REG_OP_READ,
- &ppcnt, sizeof(ppcnt));
- KERNEL_UNLOCK();
+ &ppcnt, sizeof(ppcnt), MCX_CMDQ_SLOT_KSTAT);
if (rv != 0)
return (EIO);
}
if (mcx_access_hca_reg(sc, MCX_REG_MCAM, MCX_REG_OP_READ,
- &mcam, sizeof(mcam)) != 0) {
+ &mcam, sizeof(mcam), MCX_CMDQ_SLOT_POLL) != 0) {
/* unable to check management capabilities? */
return;
}
}
if (mcx_access_hca_reg(sc, MCX_REG_MTCAP, MCX_REG_OP_READ,
- &mtcap, sizeof(mtcap)) != 0) {
+ &mtcap, sizeof(mtcap), MCX_CMDQ_SLOT_POLL) != 0) {
/* unable to find temperature sensors */
return;
}
ks->ks_datalen = sizeof(*ktmp);
TIMEVAL_TO_TIMESPEC(&mcx_kstat_mtmp_rate, &ks->ks_interval);
ks->ks_read = mcx_kstat_mtmp_read;
+ kstat_set_wlock(ks, &sc->sc_cmdq_kstat_lk);
ks->ks_softc = sc;
kstat_install(ks);
memset(&mtmp, 0, sizeof(mtmp));
htobem16(&mtmp.mtmp_sensor_index, ks->ks_unit);
- KERNEL_LOCK(); /* XXX */
rv = mcx_access_hca_reg(sc, MCX_REG_MTMP, MCX_REG_OP_READ,
- &mtmp, sizeof(mtmp));
- KERNEL_UNLOCK();
+ &mtmp, sizeof(mtmp), MCX_CMDQ_SLOT_KSTAT);
if (rv != 0)
return (EIO);
const char *text;
int error = 0;
- KERNEL_LOCK();
-
if (mcx_query_rq(sc, &q->q_rx, &u.rq) != 0) {
error = EIO;
goto out;
nanouptime(&ks->ks_updated);
out:
- KERNEL_UNLOCK();
return (error);
}