Skip to content

Commit bf15bb3

Browse files
michichdavem330
authored andcommitted
ice: make writes to /dev/gnssX synchronous
The current ice driver's GNSS write implementation buffers writes and works through them asynchronously in a kthread. That's bad because: - The GNSS write_raw operation is supposed to be synchronous[1][2]. - There is no upper bound on the number of pending writes. Userspace can submit writes much faster than the driver can process, consuming unlimited amounts of kernel memory. A patch that's currently on review[3] ("[v3,net] ice: Write all GNSS buffers instead of first one") would add one more problem: - The possibility of waiting for a very long time to flush the write work when doing rmmod, softlockups. To fix these issues, simplify the implementation: Drop the buffering, the write_work, and make the writes synchronous. I tested this with gpsd and ubxtool. [1] https://events19.linuxfoundation.org/wp-content/uploads/2017/12/The-GNSS-Subsystem-Johan-Hovold-Hovold-Consulting-AB.pdf "User interface" slide. [2] A comment in drivers/gnss/core.c:gnss_write(): /* Ignoring O_NONBLOCK, write_raw() is synchronous. */ [3] https://patchwork.ozlabs.org/project/intel-wired-lan/patch/[email protected]/ Fixes: d6b98c8 ("ice: add write functionality for GNSS TTY") Signed-off-by: Michal Schmidt <[email protected]> Reviewed-by: Simon Horman <[email protected]> Tested-by: Sunitha Mekala <[email protected]> (A Contingent worker at Intel) Signed-off-by: Tony Nguyen <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent d636fc5 commit bf15bb3

File tree

4 files changed

+6
-72
lines changed

4 files changed

+6
-72
lines changed

drivers/net/ethernet/intel/ice/ice_common.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5160,7 +5160,7 @@ ice_aq_read_i2c(struct ice_hw *hw, struct ice_aqc_link_topo_addr topo_addr,
51605160
*/
51615161
int
51625162
ice_aq_write_i2c(struct ice_hw *hw, struct ice_aqc_link_topo_addr topo_addr,
5163-
u16 bus_addr, __le16 addr, u8 params, u8 *data,
5163+
u16 bus_addr, __le16 addr, u8 params, const u8 *data,
51645164
struct ice_sq_cd *cd)
51655165
{
51665166
struct ice_aq_desc desc = { 0 };

drivers/net/ethernet/intel/ice/ice_common.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ ice_aq_read_i2c(struct ice_hw *hw, struct ice_aqc_link_topo_addr topo_addr,
229229
struct ice_sq_cd *cd);
230230
int
231231
ice_aq_write_i2c(struct ice_hw *hw, struct ice_aqc_link_topo_addr topo_addr,
232-
u16 bus_addr, __le16 addr, u8 params, u8 *data,
232+
u16 bus_addr, __le16 addr, u8 params, const u8 *data,
233233
struct ice_sq_cd *cd);
234234
bool ice_fw_supports_report_dflt_cfg(struct ice_hw *hw);
235235
#endif /* _ICE_COMMON_H_ */

drivers/net/ethernet/intel/ice/ice_gnss.c

Lines changed: 4 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
* * number of bytes written - success
1717
* * negative - error code
1818
*/
19-
static unsigned int
20-
ice_gnss_do_write(struct ice_pf *pf, unsigned char *buf, unsigned int size)
19+
static int
20+
ice_gnss_do_write(struct ice_pf *pf, const unsigned char *buf, unsigned int size)
2121
{
2222
struct ice_aqc_link_topo_addr link_topo;
2323
struct ice_hw *hw = &pf->hw;
@@ -72,39 +72,7 @@ ice_gnss_do_write(struct ice_pf *pf, unsigned char *buf, unsigned int size)
7272
dev_err(ice_pf_to_dev(pf), "GNSS failed to write, offset=%u, size=%u, err=%d\n",
7373
offset, size, err);
7474

75-
return offset;
76-
}
77-
78-
/**
79-
* ice_gnss_write_pending - Write all pending data to internal GNSS
80-
* @work: GNSS write work structure
81-
*/
82-
static void ice_gnss_write_pending(struct kthread_work *work)
83-
{
84-
struct gnss_serial *gnss = container_of(work, struct gnss_serial,
85-
write_work);
86-
struct ice_pf *pf = gnss->back;
87-
88-
if (!pf)
89-
return;
90-
91-
if (!test_bit(ICE_FLAG_GNSS, pf->flags))
92-
return;
93-
94-
if (!list_empty(&gnss->queue)) {
95-
struct gnss_write_buf *write_buf = NULL;
96-
unsigned int bytes;
97-
98-
write_buf = list_first_entry(&gnss->queue,
99-
struct gnss_write_buf, queue);
100-
101-
bytes = ice_gnss_do_write(pf, write_buf->buf, write_buf->size);
102-
dev_dbg(ice_pf_to_dev(pf), "%u bytes written to GNSS\n", bytes);
103-
104-
list_del(&write_buf->queue);
105-
kfree(write_buf->buf);
106-
kfree(write_buf);
107-
}
75+
return err;
10876
}
10977

11078
/**
@@ -220,8 +188,6 @@ static struct gnss_serial *ice_gnss_struct_init(struct ice_pf *pf)
220188
pf->gnss_serial = gnss;
221189

222190
kthread_init_delayed_work(&gnss->read_work, ice_gnss_read);
223-
INIT_LIST_HEAD(&gnss->queue);
224-
kthread_init_work(&gnss->write_work, ice_gnss_write_pending);
225191
kworker = kthread_create_worker(0, "ice-gnss-%s", dev_name(dev));
226192
if (IS_ERR(kworker)) {
227193
kfree(gnss);
@@ -281,7 +247,6 @@ static void ice_gnss_close(struct gnss_device *gdev)
281247
if (!gnss)
282248
return;
283249

284-
kthread_cancel_work_sync(&gnss->write_work);
285250
kthread_cancel_delayed_work_sync(&gnss->read_work);
286251
}
287252

@@ -300,10 +265,7 @@ ice_gnss_write(struct gnss_device *gdev, const unsigned char *buf,
300265
size_t count)
301266
{
302267
struct ice_pf *pf = gnss_get_drvdata(gdev);
303-
struct gnss_write_buf *write_buf;
304268
struct gnss_serial *gnss;
305-
unsigned char *cmd_buf;
306-
int err = count;
307269

308270
/* We cannot write a single byte using our I2C implementation. */
309271
if (count <= 1 || count > ICE_GNSS_TTY_WRITE_BUF)
@@ -319,24 +281,7 @@ ice_gnss_write(struct gnss_device *gdev, const unsigned char *buf,
319281
if (!gnss)
320282
return -ENODEV;
321283

322-
cmd_buf = kcalloc(count, sizeof(*buf), GFP_KERNEL);
323-
if (!cmd_buf)
324-
return -ENOMEM;
325-
326-
memcpy(cmd_buf, buf, count);
327-
write_buf = kzalloc(sizeof(*write_buf), GFP_KERNEL);
328-
if (!write_buf) {
329-
kfree(cmd_buf);
330-
return -ENOMEM;
331-
}
332-
333-
write_buf->buf = cmd_buf;
334-
write_buf->size = count;
335-
INIT_LIST_HEAD(&write_buf->queue);
336-
list_add_tail(&write_buf->queue, &gnss->queue);
337-
kthread_queue_work(gnss->kworker, &gnss->write_work);
338-
339-
return err;
284+
return ice_gnss_do_write(pf, buf, count);
340285
}
341286

342287
static const struct gnss_operations ice_gnss_ops = {
@@ -432,7 +377,6 @@ void ice_gnss_exit(struct ice_pf *pf)
432377
if (pf->gnss_serial) {
433378
struct gnss_serial *gnss = pf->gnss_serial;
434379

435-
kthread_cancel_work_sync(&gnss->write_work);
436380
kthread_cancel_delayed_work_sync(&gnss->read_work);
437381
kthread_destroy_worker(gnss->kworker);
438382
gnss->kworker = NULL;

drivers/net/ethernet/intel/ice/ice_gnss.h

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,26 +22,16 @@
2222
*/
2323
#define ICE_GNSS_UBX_WRITE_BYTES (ICE_MAX_I2C_WRITE_BYTES + 1)
2424

25-
struct gnss_write_buf {
26-
struct list_head queue;
27-
unsigned int size;
28-
unsigned char *buf;
29-
};
30-
3125
/**
3226
* struct gnss_serial - data used to initialize GNSS TTY port
3327
* @back: back pointer to PF
3428
* @kworker: kwork thread for handling periodic work
3529
* @read_work: read_work function for handling GNSS reads
36-
* @write_work: write_work function for handling GNSS writes
37-
* @queue: write buffers queue
3830
*/
3931
struct gnss_serial {
4032
struct ice_pf *back;
4133
struct kthread_worker *kworker;
4234
struct kthread_delayed_work read_work;
43-
struct kthread_work write_work;
44-
struct list_head queue;
4535
};
4636

4737
#if IS_ENABLED(CONFIG_GNSS)

0 commit comments

Comments
 (0)