All of lore.kernel.org
 help / color / mirror / Atom feed
* [Intel-wired-lan] [PATCH intel-next 1/3] ice: remove u16 arithmetic in ice_gnss
@ 2022-04-15 10:31 Karol Kolacinski
  2022-04-15 10:31 ` [Intel-wired-lan] [PATCH intel-next 2/3] ice: add i2c write command Karol Kolacinski
                   ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: Karol Kolacinski @ 2022-04-15 10:31 UTC (permalink / raw)
  To: intel-wired-lan

Change u16 to u32 where arithmetic occured.

Signed-off-by: Karol Kolacinski <karol.kolacinski@intel.com>
---
 drivers/net/ethernet/intel/ice/ice_gnss.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/intel/ice/ice_gnss.c b/drivers/net/ethernet/intel/ice/ice_gnss.c
index 57586a2e6dec..f0b2091c3b5f 100644
--- a/drivers/net/ethernet/intel/ice/ice_gnss.c
+++ b/drivers/net/ethernet/intel/ice/ice_gnss.c
@@ -23,7 +23,7 @@ static void ice_gnss_read(struct kthread_work *work)
 	struct ice_hw *hw;
 	__be16 data_len_b;
 	char *buf = NULL;
-	u16 i, data_len;
+	u32 i, data_len;
 	int err = 0;
 
 	pf = gnss->back;
@@ -65,7 +65,7 @@ static void ice_gnss_read(struct kthread_work *work)
 		mdelay(10);
 	}
 
-	data_len = min(data_len, (u16)PAGE_SIZE);
+	data_len = min_t(typeof(data_len), data_len, PAGE_SIZE);
 	data_len = tty_buffer_request_room(port, data_len);
 	if (!data_len) {
 		err = -ENOMEM;
@@ -74,7 +74,7 @@ static void ice_gnss_read(struct kthread_work *work)
 
 	/* Read received data */
 	for (i = 0; i < data_len; i += bytes_read) {
-		u16 bytes_left = data_len - i;
+		u32 bytes_left = data_len - i;
 
 		bytes_read = min_t(typeof(bytes_left), bytes_left, ICE_MAX_I2C_DATA_SIZE);
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [Intel-wired-lan] [PATCH intel-next 2/3] ice: add i2c write command
  2022-04-15 10:31 [Intel-wired-lan] [PATCH intel-next 1/3] ice: remove u16 arithmetic in ice_gnss Karol Kolacinski
@ 2022-04-15 10:31 ` Karol Kolacinski
  2022-04-15 13:54   ` Paul Menzel
  2022-04-15 10:31 ` [Intel-wired-lan] [PATCH intel-next 3/3] ice: add write functionality for GNSS TTY Karol Kolacinski
  2022-04-15 13:50 ` [Intel-wired-lan] [PATCH intel-next 1/3] ice: remove u16 arithmetic in ice_gnss Paul Menzel
  2 siblings, 1 reply; 9+ messages in thread
From: Karol Kolacinski @ 2022-04-15 10:31 UTC (permalink / raw)
  To: intel-wired-lan

Add the possibility to write to connected i2c devices. FW may reject
the write if the device is not on allowlist.

Signed-off-by: Karol Kolacinski <karol.kolacinski@intel.com>
---
 .../net/ethernet/intel/ice/ice_adminq_cmd.h   |  7 +--
 drivers/net/ethernet/intel/ice/ice_common.c   | 45 ++++++++++++++++++-
 drivers/net/ethernet/intel/ice/ice_common.h   |  4 ++
 3 files changed, 52 insertions(+), 4 deletions(-)

diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
index b25e27c4d887..bedc19f12cbd 100644
--- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
+++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
@@ -1401,7 +1401,7 @@ struct ice_aqc_get_link_topo {
 	u8 rsvd[9];
 };
 
-/* Read I2C (direct, 0x06E2) */
+/* Read/Write I2C (direct, 0x06E2/0x06E3) */
 struct ice_aqc_i2c {
 	struct ice_aqc_link_topo_addr topo_addr;
 	__le16 i2c_addr;
@@ -1411,7 +1411,7 @@ struct ice_aqc_i2c {
 
 	u8 rsvd;
 	__le16 i2c_bus_addr;
-	u8 rsvd2[4];
+	u8 i2c_data[4]; /* Used only by write command, reserved in read. */
 };
 
 /* Read I2C Response (direct, 0x06E2) */
@@ -2130,7 +2130,7 @@ struct ice_aq_desc {
 		struct ice_aqc_get_link_status get_link_status;
 		struct ice_aqc_event_lan_overflow lan_overflow;
 		struct ice_aqc_get_link_topo get_link_topo;
-		struct ice_aqc_i2c read_i2c;
+		struct ice_aqc_i2c read_write_i2c;
 		struct ice_aqc_read_i2c_resp read_i2c_resp;
 	} params;
 };
@@ -2247,6 +2247,7 @@ enum ice_adminq_opc {
 	ice_aqc_opc_set_mac_lb				= 0x0620,
 	ice_aqc_opc_get_link_topo			= 0x06E0,
 	ice_aqc_opc_read_i2c				= 0x06E2,
+	ice_aqc_opc_write_i2c				= 0x06E3,
 	ice_aqc_opc_set_port_id_led			= 0x06E9,
 	ice_aqc_opc_set_gpio				= 0x06EC,
 	ice_aqc_opc_get_gpio				= 0x06ED,
diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c
index 9619bdb9e49a..85dd30f99814 100644
--- a/drivers/net/ethernet/intel/ice/ice_common.c
+++ b/drivers/net/ethernet/intel/ice/ice_common.c
@@ -4823,7 +4823,7 @@ ice_aq_read_i2c(struct ice_hw *hw, struct ice_aqc_link_topo_addr topo_addr,
 	int status;
 
 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_read_i2c);
-	cmd = &desc.params.read_i2c;
+	cmd = &desc.params.read_write_i2c;
 
 	if (!data)
 		return -EINVAL;
@@ -4850,6 +4850,49 @@ ice_aq_read_i2c(struct ice_hw *hw, struct ice_aqc_link_topo_addr topo_addr,
 	return status;
 }
 
+/**
+ * ice_aq_write_i2c
+ * @hw: pointer to the hw struct
+ * @topo_addr: topology address for a device to communicate with
+ * @bus_addr: 7-bit I2C bus address
+ * @addr: I2C memory address (I2C offset) with up to 16 bits
+ * @params: I2C parameters: bit [4] - I2C address type, bits [3:0] - data size to write (0-7 bytes)
+ * @data: pointer to data (0 to 4 bytes) to be written to the I2C device
+ * @cd: pointer to command details structure or NULL
+ *
+ * Write I2C (0x06E3)
+ */
+int
+ice_aq_write_i2c(struct ice_hw *hw, struct ice_aqc_link_topo_addr topo_addr,
+		 u16 bus_addr, __le16 addr, u8 params, u8 *data,
+		 struct ice_sq_cd *cd)
+{
+	struct ice_aq_desc desc = { 0 };
+	struct ice_aqc_i2c *cmd;
+	u8 i, data_size;
+
+	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_write_i2c);
+	cmd = &desc.params.read_write_i2c;
+
+	data_size = FIELD_GET(ICE_AQC_I2C_DATA_SIZE_M, params);
+
+	/* data_size limited to 4 */
+	if (data_size > 4)
+		return -EINVAL;
+
+	cmd->i2c_bus_addr = cpu_to_le16(bus_addr);
+	cmd->topo_addr = topo_addr;
+	cmd->i2c_params = params;
+	cmd->i2c_addr = addr;
+
+	for (i = 0; i < data_size; i++) {
+		cmd->i2c_data[i] = *data;
+		data++;
+	}
+
+	return ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
+}
+
 /**
  * ice_aq_set_driver_param - Set driver parameter to share via firmware
  * @hw: pointer to the HW struct
diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h
index 872ea7d2332d..61b7c60db689 100644
--- a/drivers/net/ethernet/intel/ice/ice_common.h
+++ b/drivers/net/ethernet/intel/ice/ice_common.h
@@ -214,5 +214,9 @@ int
 ice_aq_read_i2c(struct ice_hw *hw, struct ice_aqc_link_topo_addr topo_addr,
 		u16 bus_addr, __le16 addr, u8 params, u8 *data,
 		struct ice_sq_cd *cd);
+int
+ice_aq_write_i2c(struct ice_hw *hw, struct ice_aqc_link_topo_addr topo_addr,
+		 u16 bus_addr, __le16 addr, u8 params, u8 *data,
+		 struct ice_sq_cd *cd);
 bool ice_fw_supports_report_dflt_cfg(struct ice_hw *hw);
 #endif /* _ICE_COMMON_H_ */
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [Intel-wired-lan] [PATCH intel-next 3/3] ice: add write functionality for GNSS TTY
  2022-04-15 10:31 [Intel-wired-lan] [PATCH intel-next 1/3] ice: remove u16 arithmetic in ice_gnss Karol Kolacinski
  2022-04-15 10:31 ` [Intel-wired-lan] [PATCH intel-next 2/3] ice: add i2c write command Karol Kolacinski
@ 2022-04-15 10:31 ` Karol Kolacinski
  2022-04-15 17:11   ` Paul Menzel
  2022-04-15 13:50 ` [Intel-wired-lan] [PATCH intel-next 1/3] ice: remove u16 arithmetic in ice_gnss Paul Menzel
  2 siblings, 1 reply; 9+ messages in thread
From: Karol Kolacinski @ 2022-04-15 10:31 UTC (permalink / raw)
  To: intel-wired-lan

Add the possibility to write raw bytes to the GNSS module through the
first TTY device. This allow user to configure the module.

Create a second read-only TTY device.

Signed-off-by: Karol Kolacinski <karol.kolacinski@intel.com>
---
 drivers/net/ethernet/intel/ice/ice.h      |   4 +-
 drivers/net/ethernet/intel/ice/ice_gnss.c | 230 +++++++++++++++++++---
 drivers/net/ethernet/intel/ice/ice_gnss.h |  23 ++-
 3 files changed, 231 insertions(+), 26 deletions(-)

diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h
index 17fb1ddea7b0..41bd0c7c7da5 100644
--- a/drivers/net/ethernet/intel/ice/ice.h
+++ b/drivers/net/ethernet/intel/ice/ice.h
@@ -558,8 +558,8 @@ struct ice_pf {
 	u32 msg_enable;
 	struct ice_ptp ptp;
 	struct tty_driver *ice_gnss_tty_driver;
-	struct tty_port gnss_tty_port;
-	struct gnss_serial *gnss_serial;
+	struct tty_port *gnss_tty_port[ICE_GNSS_TTY_MINOR_DEVICES];
+	struct gnss_serial *gnss_serial[ICE_GNSS_TTY_MINOR_DEVICES];
 	u16 num_rdma_msix;		/* Total MSIX vectors for RDMA driver */
 	u16 rdma_base_vector;
 
diff --git a/drivers/net/ethernet/intel/ice/ice_gnss.c b/drivers/net/ethernet/intel/ice/ice_gnss.c
index f0b2091c3b5f..eafebd873236 100644
--- a/drivers/net/ethernet/intel/ice/ice_gnss.c
+++ b/drivers/net/ethernet/intel/ice/ice_gnss.c
@@ -5,6 +5,99 @@
 #include "ice_lib.h"
 #include <linux/tty_driver.h>
 
+/**
+ * ice_gnss_do_write - Write data to internal GNSS
+ * @pf: board private structure
+ * @buf: command buffer
+ * @size: command buffer size
+ *
+ * Write UBX command data to the GNSS receiver
+ */
+static void ice_gnss_do_write(struct ice_pf *pf, u8 *buf, u32 size)
+{
+	u32 i, num_writes, part_writes_num, last_write_bytes, offset = 0;
+	struct ice_aqc_link_topo_addr link_topo;
+	struct ice_hw *hw = &pf->hw;
+	int err = 0;
+
+	memset(&link_topo, 0, sizeof(struct ice_aqc_link_topo_addr));
+	link_topo.topo_params.index = ICE_E810T_GNSS_I2C_BUS;
+	link_topo.topo_params.node_type_ctx |=
+		ICE_AQC_LINK_TOPO_NODE_CTX_OVERRIDE <<
+		ICE_AQC_LINK_TOPO_NODE_CTX_S;
+
+	/* Write all bytes except the last partial write */
+	last_write_bytes = size % ICE_GNSS_UBX_WRITE_BYTES;
+	if (last_write_bytes == 0)
+		part_writes_num = 0;
+	else if (last_write_bytes == 1)
+		part_writes_num = 2;
+	else
+		part_writes_num = 1;
+
+	num_writes = size / ICE_GNSS_UBX_WRITE_BYTES - part_writes_num;
+
+	for (i = 0; i < num_writes; i++) {
+		err = ice_aq_write_i2c(hw, link_topo, ICE_GNSS_UBX_I2C_BUS_ADDR,
+				       cpu_to_le16(buf[offset]),
+				       ICE_MAX_I2C_WRITE_BYTES,
+				       &buf[offset + 1], NULL);
+		if (err)
+			goto err;
+
+		offset += ICE_GNSS_UBX_WRITE_BYTES;
+	}
+
+	if (part_writes_num == 2) {
+		/* We cannot write a single byte to ublox. Do 2 last writes
+		 * instead of 1.
+		 */
+		err = ice_aq_write_i2c(hw, link_topo, ICE_GNSS_UBX_I2C_BUS_ADDR,
+				       cpu_to_le16(buf[offset]),
+				       ICE_MAX_I2C_WRITE_BYTES - 1,
+				       &buf[offset + 1], NULL);
+		if (err)
+			goto err;
+
+		offset += ICE_GNSS_UBX_WRITE_BYTES - 1;
+		last_write_bytes = 2;
+	}
+
+	if (part_writes_num)
+		err = ice_aq_write_i2c(hw, link_topo, ICE_GNSS_UBX_I2C_BUS_ADDR,
+				       cpu_to_le16(buf[offset]),
+				       last_write_bytes - 1, &buf[offset + 1],
+				       NULL);
+
+err:
+	if (err)
+		dev_err(ice_pf_to_dev(pf), "GNSS failed to write err=%d\n",
+			err);
+}
+
+/**
+ * ice_gnss_write_pending - Write all pending data to internal GNSS
+ * @work: GNSS write work structure
+ */
+static void ice_gnss_write_pending(struct kthread_work *work)
+{
+	struct gnss_serial *gnss = container_of(work, struct gnss_serial,
+						write_work);
+	struct ice_pf *pf = gnss->back;
+
+	if (!list_empty(&gnss->queue)) {
+		struct gnss_write_buf *write_buf = NULL;
+
+		write_buf = list_first_entry(&gnss->queue,
+					     struct gnss_write_buf, queue);
+		list_del(&write_buf->queue);
+
+		ice_gnss_do_write(pf, write_buf->buf, write_buf->size);
+		kfree(write_buf->buf);
+		kfree(write_buf);
+	}
+}
+
 /**
  * ice_gnss_read - Read data from internal GNSS module
  * @work: GNSS read work structure
@@ -103,8 +196,9 @@ static void ice_gnss_read(struct kthread_work *work)
 /**
  * ice_gnss_struct_init - Initialize GNSS structure for the TTY
  * @pf: Board private structure
+ * @index: TTY device index
  */
-static struct gnss_serial *ice_gnss_struct_init(struct ice_pf *pf)
+static struct gnss_serial *ice_gnss_struct_init(struct ice_pf *pf, int index)
 {
 	struct device *dev = ice_pf_to_dev(pf);
 	struct kthread_worker *kworker;
@@ -117,9 +211,11 @@ static struct gnss_serial *ice_gnss_struct_init(struct ice_pf *pf)
 	mutex_init(&gnss->gnss_mutex);
 	gnss->open_count = 0;
 	gnss->back = pf;
-	pf->gnss_serial = gnss;
+	pf->gnss_serial[index] = gnss;
 
 	kthread_init_delayed_work(&gnss->read_work, ice_gnss_read);
+	INIT_LIST_HEAD(&gnss->queue);
+	kthread_init_work(&gnss->write_work, ice_gnss_write_pending);
 	/* Allocate a kworker for handling work required for the GNSS TTY
 	 * writes.
 	 */
@@ -155,10 +251,10 @@ static int ice_gnss_tty_open(struct tty_struct *tty, struct file *filp)
 	tty->driver_data = NULL;
 
 	/* Get the serial object associated with this tty pointer */
-	gnss = pf->gnss_serial;
+	gnss = pf->gnss_serial[tty->index];
 	if (!gnss) {
 		/* Initialize GNSS struct on the first device open */
-		gnss = ice_gnss_struct_init(pf);
+		gnss = ice_gnss_struct_init(pf, tty->index);
 		if (!gnss)
 			return -ENOMEM;
 	}
@@ -211,25 +307,96 @@ static void ice_gnss_tty_close(struct tty_struct *tty, struct file *filp)
 }
 
 /**
- * ice_gnss_tty_write - Dummy TTY write function to avoid kernel panic
+ * ice_gnss_tty_write - Write GNSS data
  * @tty: pointer to the tty_struct
  * @buf: pointer to the user data
  * @cnt: the number of characters that was able to be sent to the hardware (or
  *       queued to be sent at a later time)
+ *
+ * The write function call is called by the user when there is data to be sent
+ * to the hardware. First the tty core receives the call, and then it passes the
+ * data on to the tty driver?s write function. The tty core also tells the tty
+ * driver the size of the data being sent.
+ * If any errors happen during the write call, a negative error value should be
+ * returned instead of the number of characters that were written.
  */
 static int
 ice_gnss_tty_write(struct tty_struct *tty, const unsigned char *buf, int cnt)
 {
-	return 0;
+	struct gnss_write_buf *write_buf;
+	struct gnss_serial *gnss;
+	struct ice_pf *pf;
+	u8 *cmd_buf;
+
+	/* We cannot write a single byte using our I2C implementation. */
+	if (cnt <= 1 || cnt > ICE_GNSS_TTY_WRITE_BUF)
+		return -EINVAL;
+
+	gnss = tty->driver_data;
+	if (!gnss)
+		return -EFAULT;
+
+	pf = (struct ice_pf *)tty->driver->driver_state;
+	if (!pf)
+		return -EFAULT;
+
+	/* Allow write only on TTY 0 */
+	if (gnss != pf->gnss_serial[0])
+		return -EIO;
+
+	mutex_lock(&gnss->gnss_mutex);
+
+	if (!gnss->open_count) {
+		mutex_unlock(&gnss->gnss_mutex);
+		return -EINVAL;
+	}
+
+	cmd_buf = kzalloc(sizeof(*buf) * cnt, GFP_KERNEL);
+	if (!cmd_buf)
+		return -ENOMEM;
+
+	memcpy(cmd_buf, buf, cnt);
+
+	/* Send the data out to a hardware port */
+	write_buf = kzalloc(sizeof(*write_buf), GFP_KERNEL);
+	if (!write_buf)
+		return -ENOMEM;
+
+	write_buf->buf = cmd_buf;
+	write_buf->size = cnt;
+	INIT_LIST_HEAD(&write_buf->queue);
+	list_add_tail(&write_buf->queue, &gnss->queue);
+	kthread_queue_work(gnss->kworker, &gnss->write_work);
+	mutex_unlock(&gnss->gnss_mutex);
+	return cnt;
 }
 
 /**
- * ice_gnss_tty_write_room - Dummy TTY write_room function to avoid kernel panic
+ * ice_gnss_tty_write_room - Returns the numbers of characters to be written.
  * @tty: pointer to the tty_struct
+ *
+ * This routine returns the numbers of characters the tty driver will accept
+ * for queuing to be written. This number is subject to change as output buffers
+ * get emptied, or if the output flow control is acted.
  */
 static unsigned int ice_gnss_tty_write_room(struct tty_struct *tty)
 {
-	return 0;
+	struct gnss_serial *gnss = tty->driver_data;
+	unsigned int room = 0;
+
+	/* Allow write only on TTY 0 */
+	if (!gnss || gnss != gnss->back->gnss_serial[0])
+		return room;
+
+	mutex_lock(&gnss->gnss_mutex);
+
+	if (!gnss->open_count)
+		goto exit;
+
+	room = ICE_GNSS_TTY_WRITE_BUF;
+exit:
+	mutex_unlock(&gnss->gnss_mutex);
+	return room;
 }
 
 static const struct tty_operations tty_gps_ops = {
@@ -250,10 +417,12 @@ static struct tty_driver *ice_gnss_create_tty_driver(struct ice_pf *pf)
 	struct tty_driver *tty_driver;
 	char *ttydrv_name;
 	int err;
+	u32 i;
 
-	tty_driver = tty_alloc_driver(1, TTY_DRIVER_REAL_RAW);
+	tty_driver = tty_alloc_driver(ICE_GNSS_TTY_MINOR_DEVICES,
+				      TTY_DRIVER_REAL_RAW);
 	if (IS_ERR(tty_driver)) {
-		dev_err(ice_pf_to_dev(pf), "Failed to allocate memory for GNSS TTY\n");
+		dev_err(dev, "Failed to allocate memory for GNSS TTY\n");
 		return NULL;
 	}
 
@@ -283,23 +452,32 @@ static struct tty_driver *ice_gnss_create_tty_driver(struct ice_pf *pf)
 	tty_driver->driver_state = pf;
 	tty_set_operations(tty_driver, &tty_gps_ops);
 
-	pf->gnss_serial = NULL;
+	for (i = 0; i < ICE_GNSS_TTY_MINOR_DEVICES; i++) {
+		pf->gnss_tty_port[i] = kzalloc(sizeof(*pf->gnss_tty_port[i]),
+					       GFP_KERNEL);
+		pf->gnss_serial[i] = NULL;
 
-	tty_port_init(&pf->gnss_tty_port);
-	tty_port_link_device(&pf->gnss_tty_port, tty_driver, 0);
+		tty_port_init(pf->gnss_tty_port[i]);
+		tty_port_link_device(pf->gnss_tty_port[i], tty_driver, i);
+	}
 
 	err = tty_register_driver(tty_driver);
 	if (err) {
-		dev_err(ice_pf_to_dev(pf), "Failed to register TTY driver err=%d\n",
-			err);
+		dev_err(dev, "Failed to register TTY driver err=%d\n", err);
 
-		tty_port_destroy(&pf->gnss_tty_port);
+		for (i = 0; i < ICE_GNSS_TTY_MINOR_DEVICES; i++) {
+			tty_port_destroy(pf->gnss_tty_port[i]);
+			kfree(pf->gnss_tty_port[i]);
+		}
 		kfree(ttydrv_name);
 		tty_driver_kref_put(pf->ice_gnss_tty_driver);
 
 		return NULL;
 	}
 
+	for (i = 0; i < ICE_GNSS_TTY_MINOR_DEVICES; i++)
+		dev_info(dev, "%s%d registered\n", ttydrv_name, i);
+
 	return tty_driver;
 }
 
@@ -327,17 +505,25 @@ void ice_gnss_init(struct ice_pf *pf)
  */
 void ice_gnss_exit(struct ice_pf *pf)
 {
+	u32 i;
+
 	if (!test_bit(ICE_FLAG_GNSS, pf->flags) || !pf->ice_gnss_tty_driver)
 		return;
 
-	tty_port_destroy(&pf->gnss_tty_port);
+	for (i = 0; i < ICE_GNSS_TTY_MINOR_DEVICES; i++) {
+		if (pf->gnss_tty_port[i]) {
+			tty_port_destroy(pf->gnss_tty_port[i]);
+			kfree(pf->gnss_tty_port[i]);
+		}
 
-	if (pf->gnss_serial) {
-		struct gnss_serial *gnss = pf->gnss_serial;
+		if (pf->gnss_serial[i]) {
+			struct gnss_serial *gnss = pf->gnss_serial[i];
 
-		kthread_cancel_delayed_work_sync(&gnss->read_work);
-		kfree(gnss);
-		pf->gnss_serial = NULL;
+			kthread_cancel_work_sync(&gnss->write_work);
+			kthread_cancel_delayed_work_sync(&gnss->read_work);
+			kfree(gnss);
+			pf->gnss_serial[i] = NULL;
+		}
 	}
 
 	tty_unregister_driver(pf->ice_gnss_tty_driver);
diff --git a/drivers/net/ethernet/intel/ice/ice_gnss.h b/drivers/net/ethernet/intel/ice/ice_gnss.h
index 9211adb2372c..59ba5749143e 100644
--- a/drivers/net/ethernet/intel/ice/ice_gnss.h
+++ b/drivers/net/ethernet/intel/ice/ice_gnss.h
@@ -8,14 +8,31 @@
 #include <linux/tty_flip.h>
 
 #define ICE_E810T_GNSS_I2C_BUS		0x2
+#define ICE_GNSS_TIMER_DELAY_TIME	(HZ / 10) /* 0.1 second per message */
+#define ICE_GNSS_TTY_MINOR_DEVICES	2
+#define ICE_GNSS_TTY_WRITE_BUF		250
+#define ICE_MAX_I2C_DATA_SIZE		FIELD_MAX(ICE_AQC_I2C_DATA_SIZE_M)
+#define ICE_MAX_I2C_WRITE_BYTES		4
+
+/* ublox specific deifinitions */
 #define ICE_GNSS_UBX_I2C_BUS_ADDR	0x42
 /* Data length register is big endian */
 #define ICE_GNSS_UBX_DATA_LEN_H		0xFD
 #define ICE_GNSS_UBX_DATA_LEN_WIDTH	2
 #define ICE_GNSS_UBX_EMPTY_DATA		0xFF
-#define ICE_GNSS_TIMER_DELAY_TIME	(HZ / 10) /* 0.1 second per message */
-#define ICE_MAX_I2C_DATA_SIZE		FIELD_MAX(ICE_AQC_I2C_DATA_SIZE_M)
+/* For ublox writes are performed without address so the first byte to write is
+ * passed as I2C addr parameter.
+ */
+#define ICE_GNSS_UBX_WRITE_BYTES	(ICE_MAX_I2C_WRITE_BYTES + 1)
 #define ICE_MAX_UBX_READ_TRIES		255
+#define ICE_MAX_UBX_ACK_READ_TRIES	4095
+
+struct gnss_write_buf {
+	struct list_head queue;
+	u32 size;
+	u8 *buf;
+};
+
 
 /**
  * struct gnss_serial - data used to initialize GNSS TTY port
@@ -33,6 +50,8 @@ struct gnss_serial {
 	struct mutex gnss_mutex; /* protects GNSS serial structure */
 	struct kthread_worker *kworker;
 	struct kthread_delayed_work read_work;
+	struct kthread_work write_work;
+	struct list_head queue;
 };
 
 #if IS_ENABLED(CONFIG_TTY)
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [Intel-wired-lan] [PATCH intel-next 1/3] ice: remove u16 arithmetic in ice_gnss
  2022-04-15 10:31 [Intel-wired-lan] [PATCH intel-next 1/3] ice: remove u16 arithmetic in ice_gnss Karol Kolacinski
  2022-04-15 10:31 ` [Intel-wired-lan] [PATCH intel-next 2/3] ice: add i2c write command Karol Kolacinski
  2022-04-15 10:31 ` [Intel-wired-lan] [PATCH intel-next 3/3] ice: add write functionality for GNSS TTY Karol Kolacinski
@ 2022-04-15 13:50 ` Paul Menzel
  2022-04-22 11:44   ` Kolacinski, Karol
  2 siblings, 1 reply; 9+ messages in thread
From: Paul Menzel @ 2022-04-15 13:50 UTC (permalink / raw)
  To: intel-wired-lan

Dear Karol,


Am 15.04.22 um 12:31 schrieb Karol Kolacinski:
> Change u16 to u32 where arithmetic occured.

occur*r*e*s*

Why does 16-bit width not work?


Kind regards,

Paul


> Signed-off-by: Karol Kolacinski <karol.kolacinski@intel.com>
> ---
>   drivers/net/ethernet/intel/ice/ice_gnss.c | 6 +++---
>   1 file changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/net/ethernet/intel/ice/ice_gnss.c b/drivers/net/ethernet/intel/ice/ice_gnss.c
> index 57586a2e6dec..f0b2091c3b5f 100644
> --- a/drivers/net/ethernet/intel/ice/ice_gnss.c
> +++ b/drivers/net/ethernet/intel/ice/ice_gnss.c
> @@ -23,7 +23,7 @@ static void ice_gnss_read(struct kthread_work *work)
>   	struct ice_hw *hw;
>   	__be16 data_len_b;
>   	char *buf = NULL;
> -	u16 i, data_len;
> +	u32 i, data_len;

Why does the length need to be specified at all, and no native types can 
be used?


Kind regards,

Paul


>   	int err = 0;
>   
>   	pf = gnss->back;
> @@ -65,7 +65,7 @@ static void ice_gnss_read(struct kthread_work *work)
>   		mdelay(10);
>   	}
>   
> -	data_len = min(data_len, (u16)PAGE_SIZE);
> +	data_len = min_t(typeof(data_len), data_len, PAGE_SIZE);
>   	data_len = tty_buffer_request_room(port, data_len);
>   	if (!data_len) {
>   		err = -ENOMEM;
> @@ -74,7 +74,7 @@ static void ice_gnss_read(struct kthread_work *work)
>   
>   	/* Read received data */
>   	for (i = 0; i < data_len; i += bytes_read) {
> -		u16 bytes_left = data_len - i;
> +		u32 bytes_left = data_len - i;
>   
>   		bytes_read = min_t(typeof(bytes_left), bytes_left, ICE_MAX_I2C_DATA_SIZE);
>   

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [Intel-wired-lan] [PATCH intel-next 2/3] ice: add i2c write command
  2022-04-15 10:31 ` [Intel-wired-lan] [PATCH intel-next 2/3] ice: add i2c write command Karol Kolacinski
@ 2022-04-15 13:54   ` Paul Menzel
  2022-04-22 11:46     ` Kolacinski, Karol
  0 siblings, 1 reply; 9+ messages in thread
From: Paul Menzel @ 2022-04-15 13:54 UTC (permalink / raw)
  To: intel-wired-lan

Dear Karol,


Thank you for your patch.

Am 15.04.22 um 12:31 schrieb Karol Kolacinski:
> Add the possibility to write to connected i2c devices. FW may reject
> the write if the device is not on allowlist.

Did you use a datasheet for implementing this. If so, please mention the 
name and revision.

> Signed-off-by: Karol Kolacinski <karol.kolacinski@intel.com>
> ---
>   .../net/ethernet/intel/ice/ice_adminq_cmd.h   |  7 +--
>   drivers/net/ethernet/intel/ice/ice_common.c   | 45 ++++++++++++++++++-
>   drivers/net/ethernet/intel/ice/ice_common.h   |  4 ++
>   3 files changed, 52 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
> index b25e27c4d887..bedc19f12cbd 100644
> --- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
> +++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
> @@ -1401,7 +1401,7 @@ struct ice_aqc_get_link_topo {
>   	u8 rsvd[9];
>   };
>   
> -/* Read I2C (direct, 0x06E2) */
> +/* Read/Write I2C (direct, 0x06E2/0x06E3) */
>   struct ice_aqc_i2c {
>   	struct ice_aqc_link_topo_addr topo_addr;
>   	__le16 i2c_addr;
> @@ -1411,7 +1411,7 @@ struct ice_aqc_i2c {
>   
>   	u8 rsvd;
>   	__le16 i2c_bus_addr;
> -	u8 rsvd2[4];
> +	u8 i2c_data[4]; /* Used only by write command, reserved in read. */
>   };
>   
>   /* Read I2C Response (direct, 0x06E2) */
> @@ -2130,7 +2130,7 @@ struct ice_aq_desc {
>   		struct ice_aqc_get_link_status get_link_status;
>   		struct ice_aqc_event_lan_overflow lan_overflow;
>   		struct ice_aqc_get_link_topo get_link_topo;
> -		struct ice_aqc_i2c read_i2c;
> +		struct ice_aqc_i2c read_write_i2c;
>   		struct ice_aqc_read_i2c_resp read_i2c_resp;
>   	} params;
>   };
> @@ -2247,6 +2247,7 @@ enum ice_adminq_opc {
>   	ice_aqc_opc_set_mac_lb				= 0x0620,
>   	ice_aqc_opc_get_link_topo			= 0x06E0,
>   	ice_aqc_opc_read_i2c				= 0x06E2,
> +	ice_aqc_opc_write_i2c				= 0x06E3,
>   	ice_aqc_opc_set_port_id_led			= 0x06E9,
>   	ice_aqc_opc_set_gpio				= 0x06EC,
>   	ice_aqc_opc_get_gpio				= 0x06ED,
> diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c
> index 9619bdb9e49a..85dd30f99814 100644
> --- a/drivers/net/ethernet/intel/ice/ice_common.c
> +++ b/drivers/net/ethernet/intel/ice/ice_common.c
> @@ -4823,7 +4823,7 @@ ice_aq_read_i2c(struct ice_hw *hw, struct ice_aqc_link_topo_addr topo_addr,
>   	int status;
>   
>   	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_read_i2c);
> -	cmd = &desc.params.read_i2c;
> +	cmd = &desc.params.read_write_i2c;
>   
>   	if (!data)
>   		return -EINVAL;
> @@ -4850,6 +4850,49 @@ ice_aq_read_i2c(struct ice_hw *hw, struct ice_aqc_link_topo_addr topo_addr,
>   	return status;
>   }
>   
> +/**
> + * ice_aq_write_i2c
> + * @hw: pointer to the hw struct
> + * @topo_addr: topology address for a device to communicate with
> + * @bus_addr: 7-bit I2C bus address
> + * @addr: I2C memory address (I2C offset) with up to 16 bits
> + * @params: I2C parameters: bit [4] - I2C address type, bits [3:0] - data size to write (0-7 bytes)
> + * @data: pointer to data (0 to 4 bytes) to be written to the I2C device
> + * @cd: pointer to command details structure or NULL

Also document the return value?

> + *
> + * Write I2C (0x06E3)
> + */
> +int
> +ice_aq_write_i2c(struct ice_hw *hw, struct ice_aqc_link_topo_addr topo_addr,
> +		 u16 bus_addr, __le16 addr, u8 params, u8 *data,
> +		 struct ice_sq_cd *cd)
> +{
> +	struct ice_aq_desc desc = { 0 };
> +	struct ice_aqc_i2c *cmd;
> +	u8 i, data_size;

The loop variable should be a native type.

> +
> +	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_write_i2c);
> +	cmd = &desc.params.read_write_i2c;
> +
> +	data_size = FIELD_GET(ICE_AQC_I2C_DATA_SIZE_M, params);
> +
> +	/* data_size limited to 4 */
> +	if (data_size > 4)
> +		return -EINVAL;
> +
> +	cmd->i2c_bus_addr = cpu_to_le16(bus_addr);
> +	cmd->topo_addr = topo_addr;
> +	cmd->i2c_params = params;
> +	cmd->i2c_addr = addr;
> +
> +	for (i = 0; i < data_size; i++) {
> +		cmd->i2c_data[i] = *data;
> +		data++;
> +	}
> +
> +	return ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
> +}
> +
>   /**
>    * ice_aq_set_driver_param - Set driver parameter to share via firmware
>    * @hw: pointer to the HW struct
> diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h
> index 872ea7d2332d..61b7c60db689 100644
> --- a/drivers/net/ethernet/intel/ice/ice_common.h
> +++ b/drivers/net/ethernet/intel/ice/ice_common.h
> @@ -214,5 +214,9 @@ int
>   ice_aq_read_i2c(struct ice_hw *hw, struct ice_aqc_link_topo_addr topo_addr,
>   		u16 bus_addr, __le16 addr, u8 params, u8 *data,
>   		struct ice_sq_cd *cd);
> +int
> +ice_aq_write_i2c(struct ice_hw *hw, struct ice_aqc_link_topo_addr topo_addr,
> +		 u16 bus_addr, __le16 addr, u8 params, u8 *data,
> +		 struct ice_sq_cd *cd);
>   bool ice_fw_supports_report_dflt_cfg(struct ice_hw *hw);
>   #endif /* _ICE_COMMON_H_ */


Kind regards,

Paul

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [Intel-wired-lan] [PATCH intel-next 3/3] ice: add write functionality for GNSS TTY
  2022-04-15 10:31 ` [Intel-wired-lan] [PATCH intel-next 3/3] ice: add write functionality for GNSS TTY Karol Kolacinski
@ 2022-04-15 17:11   ` Paul Menzel
  2022-04-22 11:46     ` Kolacinski, Karol
  0 siblings, 1 reply; 9+ messages in thread
From: Paul Menzel @ 2022-04-15 17:11 UTC (permalink / raw)
  To: intel-wired-lan

Dear Karol,


Thank you for the patch.

Am 15.04.22 um 12:31 schrieb Karol Kolacinski:
> Add the possibility to write raw bytes to the GNSS module through the
> first TTY device. This allow user to configure the module.

allow*s*

> 
> Create a second read-only TTY device.

Could you please give an example how to configure the module?

> Signed-off-by: Karol Kolacinski <karol.kolacinski@intel.com>
> ---
>   drivers/net/ethernet/intel/ice/ice.h      |   4 +-
>   drivers/net/ethernet/intel/ice/ice_gnss.c | 230 +++++++++++++++++++---
>   drivers/net/ethernet/intel/ice/ice_gnss.h |  23 ++-
>   3 files changed, 231 insertions(+), 26 deletions(-)
> 
> diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h
> index 17fb1ddea7b0..41bd0c7c7da5 100644
> --- a/drivers/net/ethernet/intel/ice/ice.h
> +++ b/drivers/net/ethernet/intel/ice/ice.h
> @@ -558,8 +558,8 @@ struct ice_pf {
>   	u32 msg_enable;
>   	struct ice_ptp ptp;
>   	struct tty_driver *ice_gnss_tty_driver;
> -	struct tty_port gnss_tty_port;
> -	struct gnss_serial *gnss_serial;
> +	struct tty_port *gnss_tty_port[ICE_GNSS_TTY_MINOR_DEVICES];
> +	struct gnss_serial *gnss_serial[ICE_GNSS_TTY_MINOR_DEVICES];
>   	u16 num_rdma_msix;		/* Total MSIX vectors for RDMA driver */
>   	u16 rdma_base_vector;
>   
> diff --git a/drivers/net/ethernet/intel/ice/ice_gnss.c b/drivers/net/ethernet/intel/ice/ice_gnss.c
> index f0b2091c3b5f..eafebd873236 100644
> --- a/drivers/net/ethernet/intel/ice/ice_gnss.c
> +++ b/drivers/net/ethernet/intel/ice/ice_gnss.c
> @@ -5,6 +5,99 @@
>   #include "ice_lib.h"
>   #include <linux/tty_driver.h>
>   
> +/**
> + * ice_gnss_do_write - Write data to internal GNSS
> + * @pf: board private structure
> + * @buf: command buffer
> + * @size: command buffer size
> + *
> + * Write UBX command data to the GNSS receiver
> + */
> +static void ice_gnss_do_write(struct ice_pf *pf, u8 *buf, u32 size)
> +{
> +	u32 i, num_writes, part_writes_num, last_write_bytes, offset = 0;

Can native types be used at least for the loop variable?

Write out `partial_writes_num`?

> +	struct ice_aqc_link_topo_addr link_topo;
> +	struct ice_hw *hw = &pf->hw;
> +	int err = 0;
> +
> +	memset(&link_topo, 0, sizeof(struct ice_aqc_link_topo_addr));
> +	link_topo.topo_params.index = ICE_E810T_GNSS_I2C_BUS;
> +	link_topo.topo_params.node_type_ctx |=
> +		ICE_AQC_LINK_TOPO_NODE_CTX_OVERRIDE <<
> +		ICE_AQC_LINK_TOPO_NODE_CTX_S;
> +
> +	/* Write all bytes except the last partial write */
> +	last_write_bytes = size % ICE_GNSS_UBX_WRITE_BYTES;
> +	if (last_write_bytes == 0)
> +		part_writes_num = 0;
> +	else if (last_write_bytes == 1)
> +		part_writes_num = 2;
> +	else
> +		part_writes_num = 1;

I do not fully understand the formula. But I am ignorant, so please 
ignore, if it?s obvious.

> +
> +	num_writes = size / ICE_GNSS_UBX_WRITE_BYTES - part_writes_num;
> +
> +	for (i = 0; i < num_writes; i++) {
> +		err = ice_aq_write_i2c(hw, link_topo, ICE_GNSS_UBX_I2C_BUS_ADDR,
> +				       cpu_to_le16(buf[offset]),
> +				       ICE_MAX_I2C_WRITE_BYTES,
> +				       &buf[offset + 1], NULL);
> +		if (err)
> +			goto err;
> +
> +		offset += ICE_GNSS_UBX_WRITE_BYTES;
> +	}
> +
> +	if (part_writes_num == 2) {
> +		/* We cannot write a single byte to ublox. Do 2 last writes
> +		 * instead of 1.
> +		 */
> +		err = ice_aq_write_i2c(hw, link_topo, ICE_GNSS_UBX_I2C_BUS_ADDR,
> +				       cpu_to_le16(buf[offset]),
> +				       ICE_MAX_I2C_WRITE_BYTES - 1,
> +				       &buf[offset + 1], NULL);
> +		if (err)
> +			goto err;
> +
> +		offset += ICE_GNSS_UBX_WRITE_BYTES - 1;
> +		last_write_bytes = 2;
> +	}
> +
> +	if (part_writes_num)

Please add a comment here, how you the logic works (that 
`part_writes_num == 2` is also effected).

> +		err = ice_aq_write_i2c(hw, link_topo, ICE_GNSS_UBX_I2C_BUS_ADDR,
> +				       cpu_to_le16(buf[offset]),
> +				       last_write_bytes - 1, &buf[offset + 1],
> +				       NULL);
> +

I wonder if some kind of while could model the algorithm better.

> +err:
> +	if (err)
> +		dev_err(ice_pf_to_dev(pf), "GNSS failed to write err=%d\n",
> +			err);

Please add the offset, and other values to the message.

> +}
> +
> +/**
> + * ice_gnss_write_pending - Write all pending data to internal GNSS
> + * @work: GNSS write work structure
> + */
> +static void ice_gnss_write_pending(struct kthread_work *work)
> +{
> +	struct gnss_serial *gnss = container_of(work, struct gnss_serial,
> +						write_work);
> +	struct ice_pf *pf = gnss->back;
> +
> +	if (!list_empty(&gnss->queue)) {
> +		struct gnss_write_buf *write_buf = NULL;
> +
> +		write_buf = list_first_entry(&gnss->queue,
> +					     struct gnss_write_buf, queue);
> +		list_del(&write_buf->queue);

Why does the queue need to be deleted here, and not after the write below?

> +
> +		ice_gnss_do_write(pf, write_buf->buf, write_buf->size);

Should `ice_gnss_do_write` return some success/failure code, or the 
number of writes?

> +		kfree(write_buf->buf);
> +		kfree(write_buf);
> +	}
> +}
> +
>   /**
>    * ice_gnss_read - Read data from internal GNSS module
>    * @work: GNSS read work structure
> @@ -103,8 +196,9 @@ static void ice_gnss_read(struct kthread_work *work)
>   /**
>    * ice_gnss_struct_init - Initialize GNSS structure for the TTY
>    * @pf: Board private structure
> + * @index: TTY device index
>    */
> -static struct gnss_serial *ice_gnss_struct_init(struct ice_pf *pf)
> +static struct gnss_serial *ice_gnss_struct_init(struct ice_pf *pf, int index)
>   {
>   	struct device *dev = ice_pf_to_dev(pf);
>   	struct kthread_worker *kworker;
> @@ -117,9 +211,11 @@ static struct gnss_serial *ice_gnss_struct_init(struct ice_pf *pf)
>   	mutex_init(&gnss->gnss_mutex);
>   	gnss->open_count = 0;
>   	gnss->back = pf;
> -	pf->gnss_serial = gnss;
> +	pf->gnss_serial[index] = gnss;
>   
>   	kthread_init_delayed_work(&gnss->read_work, ice_gnss_read);
> +	INIT_LIST_HEAD(&gnss->queue);
> +	kthread_init_work(&gnss->write_work, ice_gnss_write_pending);
>   	/* Allocate a kworker for handling work required for the GNSS TTY
>   	 * writes.
>   	 */
> @@ -155,10 +251,10 @@ static int ice_gnss_tty_open(struct tty_struct *tty, struct file *filp)
>   	tty->driver_data = NULL;
>   
>   	/* Get the serial object associated with this tty pointer */
> -	gnss = pf->gnss_serial;
> +	gnss = pf->gnss_serial[tty->index];
>   	if (!gnss) {
>   		/* Initialize GNSS struct on the first device open */
> -		gnss = ice_gnss_struct_init(pf);
> +		gnss = ice_gnss_struct_init(pf, tty->index);
>   		if (!gnss)
>   			return -ENOMEM;
>   	}
> @@ -211,25 +307,96 @@ static void ice_gnss_tty_close(struct tty_struct *tty, struct file *filp)
>   }
>   
>   /**
> - * ice_gnss_tty_write - Dummy TTY write function to avoid kernel panic
> + * ice_gnss_tty_write - Write GNSS data
>    * @tty: pointer to the tty_struct
>    * @buf: pointer to the user data
>    * @cnt: the number of characters that was able to be sent to the hardware (or

s/was/were/

>    *       queued to be sent at a later time)

But you are passing `cnt` in, and not set it in the implementation 
below, aren?t you?

> + *
> + * The write function call is called by the user when there is data to be sent
> + * to the hardware. First the tty core receives the call, and then it passes the
> + * data on to the tty driver?s write function. The tty core also tells the tty
> + * driver the size of the data being sent.
> + * If any errors happen during the write call, a negative error value should be
> + * returned instead of the number of characters that were written.
>    */
>   static int
>   ice_gnss_tty_write(struct tty_struct *tty, const unsigned char *buf, int cnt)

Should `cnt` be unsigned? Also, I?d use `count`.

>   {
> -	return 0;
> +	struct gnss_write_buf *write_buf;
> +	struct gnss_serial *gnss;
> +	struct ice_pf *pf;
> +	u8 *cmd_buf;
> +
> +	/* We cannot write a single byte using our I2C implementation. */
> +	if (cnt <= 1 || cnt > ICE_GNSS_TTY_WRITE_BUF)
> +		return -EINVAL;
> +
> +	gnss = tty->driver_data;
> +	if (!gnss)
> +		return -EFAULT;
> +
> +	pf = (struct ice_pf *)tty->driver->driver_state;
> +	if (!pf)
> +		return -EFAULT;
> +
> +	/* Allow write only on TTY 0 */

Only allow to write on TTY 0

> +	if (gnss != pf->gnss_serial[0])
> +		return -EIO;
> +
> +	mutex_lock(&gnss->gnss_mutex);
> +
> +	if (!gnss->open_count) {
> +		mutex_unlock(&gnss->gnss_mutex);
> +		return -EINVAL;
> +	}
> +
> +	cmd_buf = kzalloc(sizeof(*buf) * cnt, GFP_KERNEL);
> +	if (!cmd_buf)
> +		return -ENOMEM;

Does some unlocking need to happen here?

> +
> +	memcpy(cmd_buf, buf, cnt);
> +
> +	/* Send the data out to a hardware port */
> +	write_buf = kzalloc(sizeof(*write_buf), GFP_KERNEL);
> +	if (!write_buf)
> +		return -ENOMEM;

Ditto.

> +
> +	write_buf->buf = cmd_buf;
> +	write_buf->size = cnt;
> +	INIT_LIST_HEAD(&write_buf->queue);
> +	list_add_tail(&write_buf->queue, &gnss->queue);
> +	kthread_queue_work(gnss->kworker, &gnss->write_work);
> +	mutex_unlock(&gnss->gnss_mutex);
> +	return cnt;
>   }
>   
>   /**
> - * ice_gnss_tty_write_room - Dummy TTY write_room function to avoid kernel panic
> + * ice_gnss_tty_write_room - Returns the numbers of characters to be written.
>    * @tty: pointer to the tty_struct
> + *
> + * This routine returns the numbers of characters the tty driver will accept
> + * for queuing to be written. This number is subject to change as output buffers
> + * get emptied, or if the output flow control is acted.

What do you mean by ?is acted??

>    */
>   static unsigned int ice_gnss_tty_write_room(struct tty_struct *tty)
>   {
> -	return 0;
> +	struct gnss_serial *gnss = tty->driver_data;
> +	unsigned int room = 0;
> +
> +	/* Allow write only on TTY 0 */

Ditto.

> +	if (!gnss || gnss != gnss->back->gnss_serial[0])
> +		return room;

Do you need `room`? `return 0` here, and the macro in the end?

> +
> +	mutex_lock(&gnss->gnss_mutex);
> +
> +	if (!gnss->open_count)
> +		goto exit;
> +
> +	room = ICE_GNSS_TTY_WRITE_BUF;
> +exit:
> +	mutex_unlock(&gnss->gnss_mutex);
> +	return room;
>   }
>   
>   static const struct tty_operations tty_gps_ops = {
> @@ -250,10 +417,12 @@ static struct tty_driver *ice_gnss_create_tty_driver(struct ice_pf *pf)
>   	struct tty_driver *tty_driver;
>   	char *ttydrv_name;
>   	int err;
> +	u32 i;

Use native types?

>   
> -	tty_driver = tty_alloc_driver(1, TTY_DRIVER_REAL_RAW);
> +	tty_driver = tty_alloc_driver(ICE_GNSS_TTY_MINOR_DEVICES,
> +				      TTY_DRIVER_REAL_RAW);
>   	if (IS_ERR(tty_driver)) {
> -		dev_err(ice_pf_to_dev(pf), "Failed to allocate memory for GNSS TTY\n");
> +		dev_err(dev, "Failed to allocate memory for GNSS TTY\n");
>   		return NULL;
>   	}
>   
> @@ -283,23 +452,32 @@ static struct tty_driver *ice_gnss_create_tty_driver(struct ice_pf *pf)
>   	tty_driver->driver_state = pf;
>   	tty_set_operations(tty_driver, &tty_gps_ops);
>   
> -	pf->gnss_serial = NULL;
> +	for (i = 0; i < ICE_GNSS_TTY_MINOR_DEVICES; i++) {
> +		pf->gnss_tty_port[i] = kzalloc(sizeof(*pf->gnss_tty_port[i]),
> +					       GFP_KERNEL);
> +		pf->gnss_serial[i] = NULL;
>   
> -	tty_port_init(&pf->gnss_tty_port);
> -	tty_port_link_device(&pf->gnss_tty_port, tty_driver, 0);
> +		tty_port_init(pf->gnss_tty_port[i]);
> +		tty_port_link_device(pf->gnss_tty_port[i], tty_driver, i);
> +	}
>   
>   	err = tty_register_driver(tty_driver);
>   	if (err) {
> -		dev_err(ice_pf_to_dev(pf), "Failed to register TTY driver err=%d\n",
> -			err);
> +		dev_err(dev, "Failed to register TTY driver err=%d\n", err);
>   
> -		tty_port_destroy(&pf->gnss_tty_port);
> +		for (i = 0; i < ICE_GNSS_TTY_MINOR_DEVICES; i++) {
> +			tty_port_destroy(pf->gnss_tty_port[i]);
> +			kfree(pf->gnss_tty_port[i]);
> +		}
>   		kfree(ttydrv_name);
>   		tty_driver_kref_put(pf->ice_gnss_tty_driver);
>   
>   		return NULL;
>   	}
>   
> +	for (i = 0; i < ICE_GNSS_TTY_MINOR_DEVICES; i++)
> +		dev_info(dev, "%s%d registered\n", ttydrv_name, i);
> +
>   	return tty_driver;
>   }
>   
> @@ -327,17 +505,25 @@ void ice_gnss_init(struct ice_pf *pf)
>    */
>   void ice_gnss_exit(struct ice_pf *pf)
>   {
> +	u32 i;

Ditto.

> +
>   	if (!test_bit(ICE_FLAG_GNSS, pf->flags) || !pf->ice_gnss_tty_driver)
>   		return;
>   
> -	tty_port_destroy(&pf->gnss_tty_port);
> +	for (i = 0; i < ICE_GNSS_TTY_MINOR_DEVICES; i++) {
> +		if (pf->gnss_tty_port[i]) {
> +			tty_port_destroy(pf->gnss_tty_port[i]);
> +			kfree(pf->gnss_tty_port[i]);
> +		}
>   
> -	if (pf->gnss_serial) {
> -		struct gnss_serial *gnss = pf->gnss_serial;
> +		if (pf->gnss_serial[i]) {
> +			struct gnss_serial *gnss = pf->gnss_serial[i];
>   
> -		kthread_cancel_delayed_work_sync(&gnss->read_work);
> -		kfree(gnss);
> -		pf->gnss_serial = NULL;
> +			kthread_cancel_work_sync(&gnss->write_work);
> +			kthread_cancel_delayed_work_sync(&gnss->read_work);
> +			kfree(gnss);
> +			pf->gnss_serial[i] = NULL;
> +		}
>   	}
>   
>   	tty_unregister_driver(pf->ice_gnss_tty_driver);
> diff --git a/drivers/net/ethernet/intel/ice/ice_gnss.h b/drivers/net/ethernet/intel/ice/ice_gnss.h
> index 9211adb2372c..59ba5749143e 100644
> --- a/drivers/net/ethernet/intel/ice/ice_gnss.h
> +++ b/drivers/net/ethernet/intel/ice/ice_gnss.h
> @@ -8,14 +8,31 @@
>   #include <linux/tty_flip.h>
>   
>   #define ICE_E810T_GNSS_I2C_BUS		0x2
> +#define ICE_GNSS_TIMER_DELAY_TIME	(HZ / 10) /* 0.1 second per message */
> +#define ICE_GNSS_TTY_MINOR_DEVICES	2
> +#define ICE_GNSS_TTY_WRITE_BUF		250
> +#define ICE_MAX_I2C_DATA_SIZE		FIELD_MAX(ICE_AQC_I2C_DATA_SIZE_M)
> +#define ICE_MAX_I2C_WRITE_BYTES		4
> +
> +/* ublox specific deifinitions */
>   #define ICE_GNSS_UBX_I2C_BUS_ADDR	0x42
>   /* Data length register is big endian */
>   #define ICE_GNSS_UBX_DATA_LEN_H		0xFD
>   #define ICE_GNSS_UBX_DATA_LEN_WIDTH	2
>   #define ICE_GNSS_UBX_EMPTY_DATA		0xFF
> -#define ICE_GNSS_TIMER_DELAY_TIME	(HZ / 10) /* 0.1 second per message */
> -#define ICE_MAX_I2C_DATA_SIZE		FIELD_MAX(ICE_AQC_I2C_DATA_SIZE_M)
> +/* For ublox writes are performed without address so the first byte to write is
> + * passed as I2C addr parameter.
> + */
> +#define ICE_GNSS_UBX_WRITE_BYTES	(ICE_MAX_I2C_WRITE_BYTES + 1)
>   #define ICE_MAX_UBX_READ_TRIES		255
> +#define ICE_MAX_UBX_ACK_READ_TRIES	4095
> +
> +struct gnss_write_buf {
> +	struct list_head queue;
> +	u32 size;

Use native types.

> +	u8 *buf;
> +};
> +
>   
>   /**
>    * struct gnss_serial - data used to initialize GNSS TTY port
> @@ -33,6 +50,8 @@ struct gnss_serial {
>   	struct mutex gnss_mutex; /* protects GNSS serial structure */
>   	struct kthread_worker *kworker;
>   	struct kthread_delayed_work read_work;
> +	struct kthread_work write_work;
> +	struct list_head queue;
>   };
>   
>   #if IS_ENABLED(CONFIG_TTY)


Kind regards,

Paul

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [Intel-wired-lan] [PATCH intel-next 1/3] ice: remove u16 arithmetic in ice_gnss
  2022-04-15 13:50 ` [Intel-wired-lan] [PATCH intel-next 1/3] ice: remove u16 arithmetic in ice_gnss Paul Menzel
@ 2022-04-22 11:44   ` Kolacinski, Karol
  0 siblings, 0 replies; 9+ messages in thread
From: Kolacinski, Karol @ 2022-04-22 11:44 UTC (permalink / raw)
  To: intel-wired-lan

Dear Paul,

Thank you for your review.

On 4/15/22 3:51 PM, Paul Menzel wrote:
>> Change u16 to u32 where arithmetic occured.
>
>occur*r*e*s*
>
>Why does 16-bit width not work?

In the previous GNSS patch review, David Laight wrote that I should not do
arithmetic on anything smaller than 'int'.

>
>> Signed-off-by: Karol Kolacinski <karol.kolacinski@intel.com>
>> ---
>>?? drivers/net/ethernet/intel/ice/ice_gnss.c | 6 +++---
>>?? 1 file changed, 3 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/net/ethernet/intel/ice/ice_gnss.c b/drivers/net/ethernet/intel/ice/ice_gnss.c
>> index 57586a2e6dec..f0b2091c3b5f 100644
>> --- a/drivers/net/ethernet/intel/ice/ice_gnss.c
>> +++ b/drivers/net/ethernet/intel/ice/ice_gnss.c
>> @@ -23,7 +23,7 @@ static void ice_gnss_read(struct kthread_work *work)
>>??????? struct ice_hw *hw;
>>??????? __be16 data_len_b;
>>??????? char *buf = NULL;
>> -???? u16 i, data_len;
>> +???? u32 i, data_len;
>
>Why does the length need to be specified at all, and no native types can
>be used?

I changed it to use native type. Length of the buffer is read from the device
and then used in a read loop.

Kind regards,
Karol

---------------------------------------------------------------------

Intel Technology Poland sp. z o.o.
ul. Slowackiego 173, 80-298 Gdansk
KRS 101882
NIP 957-07-52-316

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [Intel-wired-lan] [PATCH intel-next 2/3] ice: add i2c write command
  2022-04-15 13:54   ` Paul Menzel
@ 2022-04-22 11:46     ` Kolacinski, Karol
  0 siblings, 0 replies; 9+ messages in thread
From: Kolacinski, Karol @ 2022-04-22 11:46 UTC (permalink / raw)
  To: intel-wired-lan

Dear Paul,

Thank you for your review.

On 4/15/22 3:55 PM, Paul Menzel wrote:
>> Add the possibility to write to connected i2c devices. FW may reject
>> the write if the device is not on allowlist.
>
>Did you use a datasheet for implementing this. If so, please mention the 
>name and revision.

Unfortunately, the original author did not leave the datasheet.

>> +/**
>> + * ice_aq_write_i2c
>> + * @hw: pointer to the hw struct
>> + * @topo_addr: topology address for a device to communicate with
>> + * @bus_addr: 7-bit I2C bus address
>> + * @addr: I2C memory address (I2C offset) with up to 16 bits
>> + * @params: I2C parameters: bit [4] - I2C address type, bits [3:0] - data size to write (0-7 bytes)
>> + * @data: pointer to data (0 to 4 bytes) to be written to the I2C device
>> + * @cd: pointer to command details structure or NULL
>
>Also document the return value?

Done.

>> + *
>> + * Write I2C (0x06E3)
>> + */
>> +int
>> +ice_aq_write_i2c(struct ice_hw *hw, struct ice_aqc_link_topo_addr topo_addr,
>> +????????????? u16 bus_addr, __le16 addr, u8 params, u8 *data,
>> +????????????? struct ice_sq_cd *cd)
>> +{
>> +???? struct ice_aq_desc desc = { 0 };
>> +???? struct ice_aqc_i2c *cmd;
>> +???? u8 i, data_size;
>
>The loop variable should be a native type.

Done.

Kind regards,
Karol

---------------------------------------------------------------------

Intel Technology Poland sp. z o.o.
ul. Slowackiego 173, 80-298 Gdansk
KRS 101882
NIP 957-07-52-316

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [Intel-wired-lan] [PATCH intel-next 3/3] ice: add write functionality for GNSS TTY
  2022-04-15 17:11   ` Paul Menzel
@ 2022-04-22 11:46     ` Kolacinski, Karol
  0 siblings, 0 replies; 9+ messages in thread
From: Kolacinski, Karol @ 2022-04-22 11:46 UTC (permalink / raw)
  To: intel-wired-lan

Dear Paul,

Thank you for your review.

On 4/15/22 7:12 PM, Paul Menzel wrote:
>> Add the possibility to write raw bytes to the GNSS module through the
>> first TTY device. This allow user to configure the module.
>
>allow*s*

Done.

>>
>> Create a second read-only TTY device.
>
>Could you please give an example how to configure the module?

The module is configured using the u-blox UBX protocol, I updated the commit message to
reflect this.

>> Signed-off-by: Karol Kolacinski <karol.kolacinski@intel.com>
>> ---
>>   drivers/net/ethernet/intel/ice/ice.h      |   4 +-
>>   drivers/net/ethernet/intel/ice/ice_gnss.c | 230 +++++++++++++++++++---
>>   drivers/net/ethernet/intel/ice/ice_gnss.h |  23 ++-
>>   3 files changed, 231 insertions(+), 26 deletions(-)
>>
>> diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h
>> index 17fb1ddea7b0..41bd0c7c7da5 100644
>> --- a/drivers/net/ethernet/intel/ice/ice.h
>> +++ b/drivers/net/ethernet/intel/ice/ice.h
>> @@ -558,8 +558,8 @@ struct ice_pf {
>>        u32 msg_enable;
>>        struct ice_ptp ptp;
>>        struct tty_driver *ice_gnss_tty_driver;
>> -     struct tty_port gnss_tty_port;
>> -     struct gnss_serial *gnss_serial;
>> +     struct tty_port *gnss_tty_port[ICE_GNSS_TTY_MINOR_DEVICES];
>> +     struct gnss_serial *gnss_serial[ICE_GNSS_TTY_MINOR_DEVICES];
>>        u16 num_rdma_msix;              /* Total MSIX vectors for RDMA driver */
>>        u16 rdma_base_vector;
>>  
>> diff --git a/drivers/net/ethernet/intel/ice/ice_gnss.c b/drivers/net/ethernet/intel/ice/ice_gnss.c
>> index f0b2091c3b5f..eafebd873236 100644
>> --- a/drivers/net/ethernet/intel/ice/ice_gnss.c
>> +++ b/drivers/net/ethernet/intel/ice/ice_gnss.c
>> @@ -5,6 +5,99 @@
>>   #include "ice_lib.h"
>>   #include <linux/tty_driver.h>
>>  
>> +/**
>> + * ice_gnss_do_write - Write data to internal GNSS
>> + * @pf: board private structure
>> + * @buf: command buffer
>> + * @size: command buffer size
>> + *
>> + * Write UBX command data to the GNSS receiver
>> + */
>> +static void ice_gnss_do_write(struct ice_pf *pf, u8 *buf, u32 size)
>> +{
>> +     u32 i, num_writes, part_writes_num, last_write_bytes, offset = 0;
>
>Can native types be used at least for the loop variable?
>
>Write out `partial_writes_num`?

Done.

>> +     struct ice_aqc_link_topo_addr link_topo;
>> +     struct ice_hw *hw = &pf->hw;
>> +     int err = 0;
>> +
>> +     memset(&link_topo, 0, sizeof(struct ice_aqc_link_topo_addr));
>> +     link_topo.topo_params.index = ICE_E810T_GNSS_I2C_BUS;
>> +     link_topo.topo_params.node_type_ctx |=
>> +             ICE_AQC_LINK_TOPO_NODE_CTX_OVERRIDE <<
>> +             ICE_AQC_LINK_TOPO_NODE_CTX_S;
>> +
>> +     /* Write all bytes except the last partial write */
>> +     last_write_bytes = size % ICE_GNSS_UBX_WRITE_BYTES;
>> +     if (last_write_bytes == 0)
>> +             part_writes_num = 0;
>> +     else if (last_write_bytes == 1)
>> +             part_writes_num = 2;
>> +     else
>> +             part_writes_num = 1;
>
>I do not fully understand the formula. But I am ignorant, so please
>ignore, if it?s obvious.

I changed the formula. Basically, I wanted to split the bytes between the last 2
writes if the last one would be only a byte.

>> +
>> +     num_writes = size / ICE_GNSS_UBX_WRITE_BYTES - part_writes_num;
>> +
>> +     for (i = 0; i < num_writes; i++) {
>> +             err = ice_aq_write_i2c(hw, link_topo, ICE_GNSS_UBX_I2C_BUS_ADDR,
>> +                                    cpu_to_le16(buf[offset]),
>> +                                    ICE_MAX_I2C_WRITE_BYTES,
>> +                                    &buf[offset + 1], NULL);
>> +             if (err)
>> +                     goto err;
>> +
>> +             offset += ICE_GNSS_UBX_WRITE_BYTES;
>> +     }
>> +
>> +     if (part_writes_num == 2) {
>> +             /* We cannot write a single byte to ublox. Do 2 last writes
>> +              * instead of 1.
>> +              */
>> +             err = ice_aq_write_i2c(hw, link_topo, ICE_GNSS_UBX_I2C_BUS_ADDR,
>> +                                    cpu_to_le16(buf[offset]),
>> +                                    ICE_MAX_I2C_WRITE_BYTES - 1,
>> +                                    &buf[offset + 1], NULL);
>> +             if (err)
>> +                     goto err;
>> +
>> +             offset += ICE_GNSS_UBX_WRITE_BYTES - 1;
>> +             last_write_bytes = 2;
>> +     }
>> +
>> +     if (part_writes_num)
>
>Please add a comment here, how you the logic works (that
>`part_writes_num == 2` is also effected).

Done.

>> +             err = ice_aq_write_i2c(hw, link_topo, ICE_GNSS_UBX_I2C_BUS_ADDR,
>> +                                    cpu_to_le16(buf[offset]),
>> +                                    last_write_bytes - 1, &buf[offset + 1],
>> +                                    NULL);
>> +
>
>I wonder if some kind of while could model the algorithm better.

Done.

>> +err:
>> +     if (err)
>> +             dev_err(ice_pf_to_dev(pf), "GNSS failed to write err=%d\n",
>> +                     err);
>
>Please add the offset, and other values to the message.

Done.

>> +}
>> +
>> +/**
>> + * ice_gnss_write_pending - Write all pending data to internal GNSS
>> + * @work: GNSS write work structure
>> + */
>> +static void ice_gnss_write_pending(struct kthread_work *work)
>> +{
>> +     struct gnss_serial *gnss = container_of(work, struct gnss_serial,
>> +                                             write_work);
>> +     struct ice_pf *pf = gnss->back;
>> +
>> +     if (!list_empty(&gnss->queue)) {
>> +             struct gnss_write_buf *write_buf = NULL;
>> +
>> +             write_buf = list_first_entry(&gnss->queue,
>> +                                          struct gnss_write_buf, queue);
>> +             list_del(&write_buf->queue);
>
>Why does the queue need to be deleted here, and not after the write below?

Done.

>> +
>> +             ice_gnss_do_write(pf, write_buf->buf, write_buf->size);
>
>Should `ice_gnss_do_write` return some success/failure code, or the
>number of writes?

Done.

>> +             kfree(write_buf->buf);
>> +             kfree(write_buf);
>> +     }
>> +}
>> +
>>   /**
>>    * ice_gnss_read - Read data from internal GNSS module
>>    * @work: GNSS read work structure
>> @@ -103,8 +196,9 @@ static void ice_gnss_read(struct kthread_work *work)
>>   /**
>>    * ice_gnss_struct_init - Initialize GNSS structure for the TTY
>>    * @pf: Board private structure
>> + * @index: TTY device index
>>    */
>> -static struct gnss_serial *ice_gnss_struct_init(struct ice_pf *pf)
>> +static struct gnss_serial *ice_gnss_struct_init(struct ice_pf *pf, int index)
>>   {
>>        struct device *dev = ice_pf_to_dev(pf);
>>        struct kthread_worker *kworker;
>> @@ -117,9 +211,11 @@ static struct gnss_serial *ice_gnss_struct_init(struct ice_pf *pf)
>>        mutex_init(&gnss->gnss_mutex);
>>        gnss->open_count = 0;
>>        gnss->back = pf;
>> -     pf->gnss_serial = gnss;
>> +     pf->gnss_serial[index] = gnss;
>>  
>>        kthread_init_delayed_work(&gnss->read_work, ice_gnss_read);
>> +     INIT_LIST_HEAD(&gnss->queue);
>> +     kthread_init_work(&gnss->write_work, ice_gnss_write_pending);
>>        /* Allocate a kworker for handling work required for the GNSS TTY
>>         * writes.
>>         */
>> @@ -155,10 +251,10 @@ static int ice_gnss_tty_open(struct tty_struct *tty, struct file *filp)
>>        tty->driver_data = NULL;
>>  
>>        /* Get the serial object associated with this tty pointer */
>> -     gnss = pf->gnss_serial;
>> +     gnss = pf->gnss_serial[tty->index];
>>        if (!gnss) {
>>                /* Initialize GNSS struct on the first device open */
>> -             gnss = ice_gnss_struct_init(pf);
>> +             gnss = ice_gnss_struct_init(pf, tty->index);
>>                if (!gnss)
>>                        return -ENOMEM;
>>        }
>> @@ -211,25 +307,96 @@ static void ice_gnss_tty_close(struct tty_struct *tty, struct file *filp)
>>   }
>>  
>>   /**
>> - * ice_gnss_tty_write - Dummy TTY write function to avoid kernel panic
>> + * ice_gnss_tty_write - Write GNSS data
>>    * @tty: pointer to the tty_struct
>>    * @buf: pointer to the user data
>>    * @cnt: the number of characters that was able to be sent to the hardware (or
>
>s/was/were/

Done.

>>    *       queued to be sent at a later time)
>
>But you are passing `cnt` in, and not set it in the implementation
>below, aren?t you?

Done.

>> + *
>> + * The write function call is called by the user when there is data to be sent
>> + * to the hardware. First the tty core receives the call, and then it passes the
>> + * data on to the tty driver?s write function. The tty core also tells the tty
>> + * driver the size of the data being sent.
>> + * If any errors happen during the write call, a negative error value should be
>> + * returned instead of the number of characters that were written.
>>    */
>>   static int
>>   ice_gnss_tty_write(struct tty_struct *tty, const unsigned char *buf, int cnt)
>
>Should `cnt` be unsigned? Also, I?d use `count`.

Changed to 'count'. I cannot use unsigned here as it's defined by the kernel
interface.

>>   {
>> -     return 0;
>> +     struct gnss_write_buf *write_buf;
>> +     struct gnss_serial *gnss;
>> +     struct ice_pf *pf;
>> +     u8 *cmd_buf;
>> +
>> +     /* We cannot write a single byte using our I2C implementation. */
>> +     if (cnt <= 1 || cnt > ICE_GNSS_TTY_WRITE_BUF)
>> +             return -EINVAL;
>> +
>> +     gnss = tty->driver_data;
>> +     if (!gnss)
>> +             return -EFAULT;
>> +
>> +     pf = (struct ice_pf *)tty->driver->driver_state;
>> +     if (!pf)
>> +             return -EFAULT;
>> +
>> +     /* Allow write only on TTY 0 */
>
>Only allow to write on TTY 0

Done.

>> +     if (gnss != pf->gnss_serial[0])
>> +             return -EIO;
>> +
>> +     mutex_lock(&gnss->gnss_mutex);
>> +
>> +     if (!gnss->open_count) {
>> +             mutex_unlock(&gnss->gnss_mutex);
>> +             return -EINVAL;
>> +     }
>> +
>> +     cmd_buf = kzalloc(sizeof(*buf) * cnt, GFP_KERNEL);
>> +     if (!cmd_buf)
>> +             return -ENOMEM;
>
>Does some unlocking need to happen here?

Done.

>> +
>> +     memcpy(cmd_buf, buf, cnt);
>> +
>> +     /* Send the data out to a hardware port */
>> +     write_buf = kzalloc(sizeof(*write_buf), GFP_KERNEL);
>> +     if (!write_buf)
>> +             return -ENOMEM;
>
>Ditto.

Done.

>> +
>> +     write_buf->buf = cmd_buf;
>> +     write_buf->size = cnt;
>> +     INIT_LIST_HEAD(&write_buf->queue);
>> +     list_add_tail(&write_buf->queue, &gnss->queue);
>> +     kthread_queue_work(gnss->kworker, &gnss->write_work);
>> +     mutex_unlock(&gnss->gnss_mutex);
>> +     return cnt;
>>   }
>>  
>>   /**
>> - * ice_gnss_tty_write_room - Dummy TTY write_room function to avoid kernel panic
>> + * ice_gnss_tty_write_room - Returns the numbers of characters to be written.
>>    * @tty: pointer to the tty_struct
>> + *
>> + * This routine returns the numbers of characters the tty driver will accept
>> + * for queuing to be written. This number is subject to change as output buffers
>> + * get emptied, or if the output flow control is acted.
>
>What do you mean by ?is acted??

Rephrased the description.

>>    */
>>   static unsigned int ice_gnss_tty_write_room(struct tty_struct *tty)
>>   {
>> -     return 0;
>> +     struct gnss_serial *gnss = tty->driver_data;
>> +     unsigned int room = 0;
>> +
>> +     /* Allow write only on TTY 0 */
>
>Ditto.

Done.

>> +     if (!gnss || gnss != gnss->back->gnss_serial[0])
>> +             return room;
>
>Do you need `room`? `return 0` here, and the macro in the end?

Done.

>> +
>> +     mutex_lock(&gnss->gnss_mutex);
>> +
>> +     if (!gnss->open_count)
>> +             goto exit;
>> +
>> +     room = ICE_GNSS_TTY_WRITE_BUF;
>> +exit:
>> +     mutex_unlock(&gnss->gnss_mutex);
>> +     return room;
>>   }
>>  
>>   static const struct tty_operations tty_gps_ops = {
>> @@ -250,10 +417,12 @@ static struct tty_driver *ice_gnss_create_tty_driver(struct ice_pf *pf)
>>        struct tty_driver *tty_driver;
>>        char *ttydrv_name;
>>        int err;
>> +     u32 i;
>
>Use native types?

Done.

>>  
>> -     tty_driver = tty_alloc_driver(1, TTY_DRIVER_REAL_RAW);
>> +     tty_driver = tty_alloc_driver(ICE_GNSS_TTY_MINOR_DEVICES,
>> +                                   TTY_DRIVER_REAL_RAW);
>>        if (IS_ERR(tty_driver)) {
>> -             dev_err(ice_pf_to_dev(pf), "Failed to allocate memory for GNSS TTY\n");
>> +             dev_err(dev, "Failed to allocate memory for GNSS TTY\n");
>>                return NULL;
>>        }
>>  
>> @@ -283,23 +452,32 @@ static struct tty_driver *ice_gnss_create_tty_driver(struct ice_pf *pf)
>>        tty_driver->driver_state = pf;
>>        tty_set_operations(tty_driver, &tty_gps_ops);
>>  
>> -     pf->gnss_serial = NULL;
>> +     for (i = 0; i < ICE_GNSS_TTY_MINOR_DEVICES; i++) {
>> +             pf->gnss_tty_port[i] = kzalloc(sizeof(*pf->gnss_tty_port[i]),
>> +                                            GFP_KERNEL);
>> +             pf->gnss_serial[i] = NULL;
>>  
>> -     tty_port_init(&pf->gnss_tty_port);
>> -     tty_port_link_device(&pf->gnss_tty_port, tty_driver, 0);
>> +             tty_port_init(pf->gnss_tty_port[i]);
>> +             tty_port_link_device(pf->gnss_tty_port[i], tty_driver, i);
>> +     }
>>  
>>        err = tty_register_driver(tty_driver);
>>        if (err) {
>> -             dev_err(ice_pf_to_dev(pf), "Failed to register TTY driver err=%d\n",
>> -                     err);
>> +             dev_err(dev, "Failed to register TTY driver err=%d\n", err);
>>  
>> -             tty_port_destroy(&pf->gnss_tty_port);
>> +             for (i = 0; i < ICE_GNSS_TTY_MINOR_DEVICES; i++) {
>> +                     tty_port_destroy(pf->gnss_tty_port[i]);
>> +                     kfree(pf->gnss_tty_port[i]);
>> +             }
>>                kfree(ttydrv_name);
>>                tty_driver_kref_put(pf->ice_gnss_tty_driver);
>>  
>>                return NULL;
>>        }
>>  
>> +     for (i = 0; i < ICE_GNSS_TTY_MINOR_DEVICES; i++)
>> +             dev_info(dev, "%s%d registered\n", ttydrv_name, i);
>> +
>>        return tty_driver;
>>   }
>>  
>> @@ -327,17 +505,25 @@ void ice_gnss_init(struct ice_pf *pf)
>>    */
>>   void ice_gnss_exit(struct ice_pf *pf)
>>   {
>> +     u32 i;
>
>Ditto.

Done.

>> +
>>        if (!test_bit(ICE_FLAG_GNSS, pf->flags) || !pf->ice_gnss_tty_driver)
>>                return;
>>  
>> -     tty_port_destroy(&pf->gnss_tty_port);
>> +     for (i = 0; i < ICE_GNSS_TTY_MINOR_DEVICES; i++) {
>> +             if (pf->gnss_tty_port[i]) {
>> +                     tty_port_destroy(pf->gnss_tty_port[i]);
>> +                     kfree(pf->gnss_tty_port[i]);
>> +             }
>>  
>> -     if (pf->gnss_serial) {
>> -             struct gnss_serial *gnss = pf->gnss_serial;
>> +             if (pf->gnss_serial[i]) {
>> +                     struct gnss_serial *gnss = pf->gnss_serial[i];
>>  
>> -             kthread_cancel_delayed_work_sync(&gnss->read_work);
>> -             kfree(gnss);
>> -             pf->gnss_serial = NULL;
>> +                     kthread_cancel_work_sync(&gnss->write_work);
>> +                     kthread_cancel_delayed_work_sync(&gnss->read_work);
>> +                     kfree(gnss);
>> +                     pf->gnss_serial[i] = NULL;
>> +             }
>>        }
>>  
>>        tty_unregister_driver(pf->ice_gnss_tty_driver);
>> diff --git a/drivers/net/ethernet/intel/ice/ice_gnss.h b/drivers/net/ethernet/intel/ice/ice_gnss.h
>> index 9211adb2372c..59ba5749143e 100644
>> --- a/drivers/net/ethernet/intel/ice/ice_gnss.h
>> +++ b/drivers/net/ethernet/intel/ice/ice_gnss.h
>> @@ -8,14 +8,31 @@
>>   #include <linux/tty_flip.h>
>>  
>>   #define ICE_E810T_GNSS_I2C_BUS              0x2
>> +#define ICE_GNSS_TIMER_DELAY_TIME    (HZ / 10) /* 0.1 second per message */
>> +#define ICE_GNSS_TTY_MINOR_DEVICES   2
>> +#define ICE_GNSS_TTY_WRITE_BUF               250
>> +#define ICE_MAX_I2C_DATA_SIZE                FIELD_MAX(ICE_AQC_I2C_DATA_SIZE_M)
>> +#define ICE_MAX_I2C_WRITE_BYTES              4
>> +
>> +/* ublox specific deifinitions */
>>   #define ICE_GNSS_UBX_I2C_BUS_ADDR   0x42
>>   /* Data length register is big endian */
>>   #define ICE_GNSS_UBX_DATA_LEN_H             0xFD
>>   #define ICE_GNSS_UBX_DATA_LEN_WIDTH 2
>>   #define ICE_GNSS_UBX_EMPTY_DATA             0xFF
>> -#define ICE_GNSS_TIMER_DELAY_TIME    (HZ / 10) /* 0.1 second per message */
>> -#define ICE_MAX_I2C_DATA_SIZE                FIELD_MAX(ICE_AQC_I2C_DATA_SIZE_M)
>> +/* For ublox writes are performed without address so the first byte to write is
>> + * passed as I2C addr parameter.
>> + */
>> +#define ICE_GNSS_UBX_WRITE_BYTES     (ICE_MAX_I2C_WRITE_BYTES + 1)
>>   #define ICE_MAX_UBX_READ_TRIES              255
>> +#define ICE_MAX_UBX_ACK_READ_TRIES   4095
>> +
>> +struct gnss_write_buf {
>> +     struct list_head queue;
>> +     u32 size;
>
>Use native types.

Done.

Kind regards,
Karol

---------------------------------------------------------------------

Intel Technology Poland sp. z o.o.
ul. Slowackiego 173, 80-298 Gdansk
KRS 101882
NIP 957-07-52-316

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2022-04-22 11:46 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-04-15 10:31 [Intel-wired-lan] [PATCH intel-next 1/3] ice: remove u16 arithmetic in ice_gnss Karol Kolacinski
2022-04-15 10:31 ` [Intel-wired-lan] [PATCH intel-next 2/3] ice: add i2c write command Karol Kolacinski
2022-04-15 13:54   ` Paul Menzel
2022-04-22 11:46     ` Kolacinski, Karol
2022-04-15 10:31 ` [Intel-wired-lan] [PATCH intel-next 3/3] ice: add write functionality for GNSS TTY Karol Kolacinski
2022-04-15 17:11   ` Paul Menzel
2022-04-22 11:46     ` Kolacinski, Karol
2022-04-15 13:50 ` [Intel-wired-lan] [PATCH intel-next 1/3] ice: remove u16 arithmetic in ice_gnss Paul Menzel
2022-04-22 11:44   ` Kolacinski, Karol

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.