mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-24 11:29:10 +00:00
Add a driver ioctl to read a byte from any device on a port's i2c bus.
This lets userspace read arbitrary information from the SFP+ modules etc. on this bus. Reading multiple bytes in the same transaction isn't possible right now. I'll update the driver once the chip's firmware supports this. MFC after: 3 days
This commit is contained in:
parent
aa95b6533b
commit
8d92e1db93
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=241399
@ -521,6 +521,8 @@ int t4_enable_vi(struct adapter *adap, unsigned int mbox, unsigned int viid,
|
||||
bool rx_en, bool tx_en);
|
||||
int t4_identify_port(struct adapter *adap, unsigned int mbox, unsigned int viid,
|
||||
unsigned int nblinks);
|
||||
int t4_i2c_rd(struct adapter *adap, unsigned int mbox, unsigned int port_id,
|
||||
u8 dev_addr, u8 offset, u8 *valp);
|
||||
int t4_mdio_rd(struct adapter *adap, unsigned int mbox, unsigned int phy_addr,
|
||||
unsigned int mmd, unsigned int reg, unsigned int *valp);
|
||||
int t4_mdio_wr(struct adapter *adap, unsigned int mbox, unsigned int phy_addr,
|
||||
|
@ -3884,6 +3884,36 @@ int t4_fwaddrspace_write(struct adapter *adap, unsigned int mbox, u32 addr, u32
|
||||
return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* t4_i2c_rd - read a byte from an i2c addressable device
|
||||
* @adap: the adapter
|
||||
* @mbox: mailbox to use for the FW command
|
||||
* @port_id: the port id
|
||||
* @dev_addr: the i2c device address
|
||||
* @offset: the byte offset to read from
|
||||
* @valp: where to store the value
|
||||
*/
|
||||
int t4_i2c_rd(struct adapter *adap, unsigned int mbox, unsigned int port_id,
|
||||
u8 dev_addr, u8 offset, u8 *valp)
|
||||
{
|
||||
int ret;
|
||||
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_FUNC_I2C));
|
||||
c.cycles_to_len16 = htonl(FW_LEN16(c));
|
||||
c.u.i2c.pid_pkd = V_FW_LDST_CMD_PID(port_id);
|
||||
c.u.i2c.base = dev_addr;
|
||||
c.u.i2c.boffset = offset;
|
||||
|
||||
ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
|
||||
if (ret == 0)
|
||||
*valp = c.u.i2c.data;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* t4_mdio_rd - read a PHY register through MDIO
|
||||
* @adap: the adapter
|
||||
|
@ -49,6 +49,7 @@ enum {
|
||||
T4_GET_SGE_CONTEXT, /* get SGE context for a queue */
|
||||
T4_LOAD_FW, /* flash firmware */
|
||||
T4_GET_MEM, /* read memory */
|
||||
T4_GET_I2C, /* read from i2c addressible device */
|
||||
};
|
||||
|
||||
struct t4_reg {
|
||||
@ -69,6 +70,14 @@ struct t4_data {
|
||||
uint8_t *data;
|
||||
};
|
||||
|
||||
struct t4_i2c_data {
|
||||
uint8_t port_id;
|
||||
uint8_t dev_addr;
|
||||
uint8_t offset;
|
||||
uint8_t len;
|
||||
uint8_t data[8];
|
||||
};
|
||||
|
||||
/*
|
||||
* A hardware filter is some valid combination of these.
|
||||
*/
|
||||
@ -224,4 +233,5 @@ struct t4_mem_range {
|
||||
struct t4_sge_context)
|
||||
#define CHELSIO_T4_LOAD_FW _IOW('f', T4_LOAD_FW, struct t4_data)
|
||||
#define CHELSIO_T4_GET_MEM _IOW('f', T4_GET_MEM, struct t4_mem_range)
|
||||
#define CHELSIO_T4_GET_I2C _IOWR('f', T4_GET_I2C, struct t4_i2c_data)
|
||||
#endif
|
||||
|
@ -349,6 +349,7 @@ static int set_filter_wr(struct adapter *, int);
|
||||
static int del_filter_wr(struct adapter *, int);
|
||||
static int get_sge_context(struct adapter *, struct t4_sge_context *);
|
||||
static int read_card_mem(struct adapter *, struct t4_mem_range *);
|
||||
static int read_i2c(struct adapter *, struct t4_i2c_data *);
|
||||
#ifdef TCP_OFFLOAD
|
||||
static int toe_capability(struct port_info *, int);
|
||||
#endif
|
||||
@ -5170,6 +5171,27 @@ read_card_mem(struct adapter *sc, struct t4_mem_range *mr)
|
||||
return (rc);
|
||||
}
|
||||
|
||||
static int
|
||||
read_i2c(struct adapter *sc, struct t4_i2c_data *i2cd)
|
||||
{
|
||||
int rc;
|
||||
|
||||
ADAPTER_LOCK_ASSERT_OWNED(sc); /* for mbox */
|
||||
|
||||
if (i2cd->len == 0 || i2cd->port_id >= sc->params.nports)
|
||||
return (EINVAL);
|
||||
|
||||
if (i2cd->len > 1) {
|
||||
/* XXX: need fw support for longer reads in one go */
|
||||
return (ENOTSUP);
|
||||
}
|
||||
|
||||
rc = -t4_i2c_rd(sc, sc->mbox, i2cd->port_id, i2cd->dev_addr,
|
||||
i2cd->offset, &i2cd->data[0]);
|
||||
|
||||
return (rc);
|
||||
}
|
||||
|
||||
int
|
||||
t4_os_find_pci_capability(struct adapter *sc, int cap)
|
||||
{
|
||||
@ -5373,6 +5395,11 @@ t4_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data, int fflag,
|
||||
case CHELSIO_T4_GET_MEM:
|
||||
rc = read_card_mem(sc, (struct t4_mem_range *)data);
|
||||
break;
|
||||
case CHELSIO_T4_GET_I2C:
|
||||
ADAPTER_LOCK(sc);
|
||||
rc = read_i2c(sc, (struct t4_i2c_data *)data);
|
||||
ADAPTER_UNLOCK(sc);
|
||||
break;
|
||||
default:
|
||||
rc = EINVAL;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user