1
0
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:
Navdeep Parhar 2012-10-10 17:13:46 +00:00
parent aa95b6533b
commit 8d92e1db93
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=241399
4 changed files with 69 additions and 0 deletions

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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;
}